[cogl/wip/onscreen-flip] Allow the winsys backend to force rendering onscreen buffers flipped



commit 0717f0f96c46da03bac9da024e89f2cd1d9237fc
Author: Neil Roberts <neil linux intel com>
Date:   Tue Dec 6 12:37:13 2011 +0000

    Allow the winsys backend to force rendering onscreen buffers flipped
    
    This adds the option for a winsys to report which kinds of buffers
    need a flipped rendering. This will be used by the KMS backend because
    that also needs flipped rendering for onscreen buffers. There is a
    virtual winsys function to report a bitmask of types of buffers that
    need to be flipped. The default implementation just reports offscreen
    buffers. None of the winsyss actually implement it yet.
    
    When the backend flips for both types of framebuffer or neither type
    of framebuffer the vertend now hardcodes the vector for the flip
    instead of adding the uniform.

 cogl/cogl-clip-stack.c            |    2 +-
 cogl/cogl-context-private.h       |    5 +++++
 cogl/cogl-context.c               |    2 ++
 cogl/cogl-framebuffer-private.h   |    3 +++
 cogl/cogl-framebuffer.c           |   19 ++++++++++++++++++-
 cogl/cogl-matrix-stack.c          |    3 ++-
 cogl/cogl-pipeline-opengl.c       |    2 +-
 cogl/cogl-pipeline-progend-glsl.c |   13 ++++++++-----
 cogl/cogl-pipeline-vertend-glsl.c |   20 ++++++++++++++++----
 cogl/cogl-renderer-private.h      |    3 +++
 cogl/cogl-renderer.c              |   12 ++++++++++++
 cogl/cogl.c                       |    6 +++---
 cogl/winsys/cogl-winsys-egl.c     |   11 ++++++-----
 cogl/winsys/cogl-winsys-glx.c     |   11 ++++++-----
 cogl/winsys/cogl-winsys-private.h |   15 +++++++++++++++
 15 files changed, 101 insertions(+), 26 deletions(-)
---
diff --git a/cogl/cogl-clip-stack.c b/cogl/cogl-clip-stack.c
index 5cc4981..0aeb1ad 100644
--- a/cogl/cogl-clip-stack.c
+++ b/cogl/cogl-clip-stack.c
@@ -861,7 +861,7 @@ _cogl_clip_stack_flush (CoglClipStack *stack,
        * down so in this case no conversion is needed.
        */
 
-      if (cogl_is_offscreen (framebuffer))
+      if (_cogl_framebuffer_is_flipped (framebuffer))
         scissor_y_start = scissor_y0;
       else
         {
diff --git a/cogl/cogl-context-private.h b/cogl/cogl-context-private.h
index b67c7e7..a72cc99 100644
--- a/cogl/cogl-context-private.h
+++ b/cogl/cogl-context-private.h
@@ -277,6 +277,11 @@ struct _CoglContext
   GHashTable *uniform_name_hash;
   int n_uniform_names;
 
+  /* Cache of the result of _cogl_renderer_get_framebuffer_orientation().
+     This will be used every time a matrix is flushed so it's probably
+     worthwhile caching it */
+  CoglRendererFramebufferOrientation framebuffer_orientation;
+
   /* This defines a list of function pointers that Cogl uses from
      either GL or GLES. All functions are accessed indirectly through
      these pointers rather than linking to them directly */
diff --git a/cogl/cogl-context.c b/cogl/cogl-context.c
index 21c10b7..06ddce7 100644
--- a/cogl/cogl-context.c
+++ b/cogl/cogl-context.c
@@ -375,6 +375,8 @@ cogl_context_new (CoglDisplay *display,
   _context->current_projection_stack = NULL;
   _cogl_matrix_stack_init_cache (&_context->builtin_flushed_projection);
   _cogl_matrix_stack_init_cache (&_context->builtin_flushed_modelview);
+  _context->framebuffer_orientation =
+    _cogl_renderer_get_framebuffer_orientation (display->renderer);
 
   /* Create default textures used for fall backs */
   context->default_gl_texture_2d_tex =
diff --git a/cogl/cogl-framebuffer-private.h b/cogl/cogl-framebuffer-private.h
index fce41e6..bdf9e45 100644
--- a/cogl/cogl-framebuffer-private.h
+++ b/cogl/cogl-framebuffer-private.h
@@ -363,4 +363,7 @@ _cogl_framebuffer_save_clip_stack (CoglFramebuffer *framebuffer);
 void
 _cogl_framebuffer_restore_clip_stack (CoglFramebuffer *framebuffer);
 
+gboolean
+_cogl_framebuffer_is_flipped (CoglFramebuffer *framebuffer);
+
 #endif /* __COGL_FRAMEBUFFER_PRIVATE_H */
diff --git a/cogl/cogl-framebuffer.c b/cogl/cogl-framebuffer.c
index 829b5c2..7a5e432 100644
--- a/cogl/cogl-framebuffer.c
+++ b/cogl/cogl-framebuffer.c
@@ -1489,7 +1489,7 @@ _cogl_framebuffer_flush_viewport_state (CoglFramebuffer *framebuffer)
    * left, while Cogl defines them to be top left.
    * NB: We render upside down to offscreen framebuffers so we don't
    * need to convert the y offset in this case. */
-  if (cogl_is_offscreen (framebuffer))
+  if (_cogl_framebuffer_is_flipped (framebuffer))
     gl_viewport_y = framebuffer->viewport_y;
   else
     gl_viewport_y = framebuffer->height -
@@ -2407,3 +2407,20 @@ _cogl_framebuffer_restore_clip_stack (CoglFramebuffer *framebuffer)
     framebuffer->context->current_draw_buffer_changes |=
       COGL_FRAMEBUFFER_STATE_CLIP;
 }
+
+gboolean
+_cogl_framebuffer_is_flipped (CoglFramebuffer *framebuffer)
+{
+  CoglRendererFramebufferOrientation orientation =
+    framebuffer->context->framebuffer_orientation;
+
+  switch (framebuffer->type)
+    {
+    case COGL_FRAMEBUFFER_TYPE_ONSCREEN:
+      return !!(orientation & COGL_RENDERER_FLIP_ONSCREEN);
+    case COGL_FRAMEBUFFER_TYPE_OFFSCREEN:
+      return !!(orientation & COGL_RENDERER_FLIP_OFFSCREEN);
+    }
+
+  g_assert_not_reached ();
+}
diff --git a/cogl/cogl-matrix-stack.c b/cogl/cogl-matrix-stack.c
index c97d3b9..35ae064 100644
--- a/cogl/cogl-matrix-stack.c
+++ b/cogl/cogl-matrix-stack.c
@@ -430,7 +430,8 @@ _cogl_matrix_stack_flush_to_gl_builtins (CoglContext *ctx,
         if (disable_flip)
           needs_flip = FALSE;
         else
-          needs_flip = cogl_is_offscreen (cogl_get_draw_framebuffer ());
+          needs_flip =
+            _cogl_framebuffer_is_flipped (cogl_get_draw_framebuffer ());
 
         cache = &ctx->builtin_flushed_projection;
       }
diff --git a/cogl/cogl-pipeline-opengl.c b/cogl/cogl-pipeline-opengl.c
index aaf5ea8..4e5950f 100644
--- a/cogl/cogl-pipeline-opengl.c
+++ b/cogl/cogl-pipeline-opengl.c
@@ -643,7 +643,7 @@ _cogl_pipeline_flush_color_blend_alpha_depth_state (
           /* If we are painting to an offscreen framebuffer then we
              need to invert the winding of the front face because
              everything is painted upside down */
-          invert_winding = cogl_is_offscreen (draw_framebuffer);
+          invert_winding = _cogl_framebuffer_is_flipped (draw_framebuffer);
 
           switch (cull_face_state->front_winding)
             {
diff --git a/cogl/cogl-pipeline-progend-glsl.c b/cogl/cogl-pipeline-progend-glsl.c
index 561ea3e..e3172ac 100644
--- a/cogl/cogl-pipeline-progend-glsl.c
+++ b/cogl/cogl-pipeline-progend-glsl.c
@@ -142,6 +142,7 @@ typedef struct
      the framebuffer requires it only when there are vertex
      snippets. Otherwise this is acheived using the projection
      matrix */
+  gboolean has_vertex_snippets;
   GLint flip_uniform;
   int flushed_flip_state;
 
@@ -797,6 +798,8 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
       GE_RET (program_state->flip_uniform,
               ctx, glGetUniformLocation (gl_program, "_cogl_flip_vector"));
       program_state->flushed_flip_state = -1;
+      program_state->has_vertex_snippets =
+        _cogl_pipeline_has_vertex_snippets (pipeline);
     }
 
   state.unit = 0;
@@ -951,7 +954,7 @@ _cogl_pipeline_progend_glsl_pre_paint (CoglPipeline *pipeline)
   if (modelview_stack == NULL || projection_stack == NULL)
     return;
 
-  needs_flip = cogl_is_offscreen (cogl_get_draw_framebuffer ());
+  needs_flip = _cogl_framebuffer_is_flipped (cogl_get_draw_framebuffer ());
 
 #ifdef HAVE_COGL_GLES2
   if (ctx->driver == COGL_DRIVER_GLES2)
@@ -967,8 +970,8 @@ _cogl_pipeline_progend_glsl_pre_paint (CoglPipeline *pipeline)
                                                    &program_state->
                                                    projection_cache,
                                                    needs_flip &&
-                                                   program_state->
-                                                   flip_uniform == -1);
+                                                   !program_state->
+                                                   has_vertex_snippets);
 
       modelview_changed =
         _cogl_matrix_stack_check_and_update_cache (modelview_stack,
@@ -993,7 +996,7 @@ _cogl_pipeline_progend_glsl_pre_paint (CoglPipeline *pipeline)
             _cogl_matrix_stack_get (modelview_stack, &modelview);
           if (need_projection)
             {
-              if (needs_flip && program_state->flip_uniform == -1)
+              if (needs_flip && !program_state->has_vertex_snippets)
                 {
                   CoglMatrix tmp_matrix;
                   _cogl_matrix_stack_get (projection_stack, &tmp_matrix);
@@ -1053,7 +1056,7 @@ _cogl_pipeline_progend_glsl_pre_paint (CoglPipeline *pipeline)
 
       /* If there are vertex snippets, then we'll disable flipping the
          geometry via the matrix and use the flip vertex instead */
-      disable_flip = program_state->flip_uniform != -1;
+      disable_flip = program_state->has_vertex_snippets;
 
       _cogl_matrix_stack_flush_to_gl_builtins (ctx,
                                                projection_stack,
diff --git a/cogl/cogl-pipeline-vertend-glsl.c b/cogl/cogl-pipeline-vertend-glsl.c
index 602cf02..c116728 100644
--- a/cogl/cogl-pipeline-vertend-glsl.c
+++ b/cogl/cogl-pipeline-vertend-glsl.c
@@ -469,10 +469,22 @@ _cogl_pipeline_vertend_glsl_end (CoglPipeline *pipeline,
          uniform */
       if (_cogl_pipeline_has_vertex_snippets (pipeline))
         {
-          g_string_append (shader_state->header,
-                           "uniform vec4 _cogl_flip_vector;\n");
-          g_string_append (shader_state->source,
-                           "  cogl_position_out *= _cogl_flip_vector;\n");
+          /* If the backend always needs flipping then we might as
+             well hardcode the flip instead of using a uniform */
+          if (ctx->framebuffer_orientation ==
+              (COGL_RENDERER_FLIP_ONSCREEN | COGL_RENDERER_FLIP_OFFSCREEN))
+            {
+              g_string_append (shader_state->source,
+                               "  cogl_position_out *= "
+                               "vec4 (1.0, -1.0, 1.0, 1.0);\n");
+            }
+          else if (ctx->framebuffer_orientation != 0)
+            {
+              g_string_append (shader_state->header,
+                               "uniform vec4 _cogl_flip_vector;\n");
+              g_string_append (shader_state->source,
+                               "  cogl_position_out *= _cogl_flip_vector;\n");
+            }
         }
 
       g_string_append (shader_state->source,
diff --git a/cogl/cogl-renderer-private.h b/cogl/cogl-renderer-private.h
index 2f7aaf1..83a9314 100644
--- a/cogl/cogl-renderer-private.h
+++ b/cogl/cogl-renderer-private.h
@@ -84,4 +84,7 @@ void *
 _cogl_renderer_get_proc_address (CoglRenderer *renderer,
                                  const char *name);
 
+CoglRendererFramebufferOrientation
+_cogl_renderer_get_framebuffer_orientation (CoglRenderer *renderer);
+
 #endif /* __COGL_RENDERER_PRIVATE_H */
diff --git a/cogl/cogl-renderer.c b/cogl/cogl-renderer.c
index 2e27209..70af0c1 100644
--- a/cogl/cogl-renderer.c
+++ b/cogl/cogl-renderer.c
@@ -403,6 +403,18 @@ _cogl_renderer_get_proc_address (CoglRenderer *renderer,
   return winsys->renderer_get_proc_address (renderer, name);
 }
 
+CoglRendererFramebufferOrientation
+_cogl_renderer_get_framebuffer_orientation (CoglRenderer *renderer)
+{
+  const CoglWinsysVtable *winsys = _cogl_renderer_get_winsys (renderer);
+
+  if (winsys->renderer_get_framebuffer_orientation)
+    return winsys->renderer_get_framebuffer_orientation (renderer);
+  else
+    /* Most backends just need to flip the offscreen buffers */
+    return COGL_RENDERER_FLIP_OFFSCREEN;
+}
+
 int
 cogl_renderer_get_n_fragment_texture_units (CoglRenderer *renderer)
 {
diff --git a/cogl/cogl.c b/cogl/cogl.c
index cba3de7..f1d2456 100644
--- a/cogl/cogl.c
+++ b/cogl/cogl.c
@@ -431,7 +431,7 @@ _cogl_read_pixels_with_rowstride (int x,
    * NB: all offscreen rendering is done upside down so no conversion
    * is necissary in this case.
    */
-  if (!cogl_is_offscreen (framebuffer))
+  if (!_cogl_framebuffer_is_flipped (framebuffer))
     y = framebuffer_height - y - height;
 
   /* Initialise the CoglBitmap */
@@ -462,7 +462,7 @@ _cogl_read_pixels_with_rowstride (int x,
   /* NB: All offscreen rendering is done upside down so there is no need
    * to flip in this case... */
   if ((ctx->private_feature_flags & COGL_PRIVATE_FEATURE_MESA_PACK_INVERT) &&
-      !cogl_is_offscreen (framebuffer))
+      !_cogl_framebuffer_is_flipped (framebuffer))
     {
       GE (ctx, glPixelStorei (GL_PACK_INVERT_MESA, TRUE));
       pack_invert_set = TRUE;
@@ -541,7 +541,7 @@ _cogl_read_pixels_with_rowstride (int x,
 
   /* NB: All offscreen rendering is done upside down so there is no need
    * to flip in this case... */
-  if (!cogl_is_offscreen (framebuffer) && !pack_invert_set)
+  if (!_cogl_framebuffer_is_flipped (framebuffer) && !pack_invert_set)
     {
       guint8 *temprow = g_alloca (rowstride * sizeof (guint8));
 
diff --git a/cogl/winsys/cogl-winsys-egl.c b/cogl/winsys/cogl-winsys-egl.c
index 7d0435f..b21375a 100644
--- a/cogl/winsys/cogl-winsys-egl.c
+++ b/cogl/winsys/cogl-winsys-egl.c
@@ -1535,11 +1535,12 @@ _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen,
    * but we are given rectangles relative to the top left so we need to flip
    * them... */
   memcpy (rectangles, user_rectangles, sizeof (int) * n_rectangles * 4);
-  for (i = 0; i < n_rectangles; i++)
-    {
-      int *rect = &rectangles[4 * i];
-      rect[1] = framebuffer_height - rect[1] - rect[3];
-    }
+  if (!_cogl_framebuffer_is_flipped (framebuffer))
+    for (i = 0; i < n_rectangles; i++)
+      {
+        int *rect = &rectangles[4 * i];
+        rect[1] = framebuffer_height - rect[1] - rect[3];
+      }
 
   /* At least for eglSwapBuffers the EGL spec says that the surface to
      swap must be bound to the current context. It looks like Mesa
diff --git a/cogl/winsys/cogl-winsys-glx.c b/cogl/winsys/cogl-winsys-glx.c
index 58640af..4ed7742 100644
--- a/cogl/winsys/cogl-winsys-glx.c
+++ b/cogl/winsys/cogl-winsys-glx.c
@@ -1211,11 +1211,12 @@ _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen,
    * we are given rectangles relative to the top left so we need to flip
    * them... */
   memcpy (rectangles, user_rectangles, sizeof (int) * n_rectangles * 4);
-  for (i = 0; i < n_rectangles; i++)
-    {
-      int *rect = &rectangles[4 * i];
-      rect[1] = framebuffer_height - rect[1] - rect[3];
-    }
+  if (!_cogl_framebuffer_is_flipped (framebuffer))
+    for (i = 0; i < n_rectangles; i++)
+      {
+        int *rect = &rectangles[4 * i];
+        rect[1] = framebuffer_height - rect[1] - rect[3];
+      }
 
   _cogl_framebuffer_flush_state (framebuffer,
                                  framebuffer,
diff --git a/cogl/winsys/cogl-winsys-private.h b/cogl/winsys/cogl-winsys-private.h
index 16317b7..4fb1cba 100644
--- a/cogl/winsys/cogl-winsys-private.h
+++ b/cogl/winsys/cogl-winsys-private.h
@@ -54,6 +54,18 @@ typedef enum
   COGL_WINSYS_RECTANGLE_STATE_ENABLE
 } CoglWinsysRectangleState;
 
+/* Flags to specify which types of buffers need to be rendered to
+   upside-down for this particularly renderer. Currently all offscreen
+   buffers need to be rendered upside down in Cogl because the texture
+   coordinate 0,0 is expected to be the topleft whereas in GL it is
+   the bottom-left. Additionally, some backends may require rendering
+   upside-down to onscreen buffers as well */
+typedef enum
+{
+  COGL_RENDERER_FLIP_ONSCREEN = (1 << 0),
+  COGL_RENDERER_FLIP_OFFSCREEN = (1 << 1),
+} CoglRendererFramebufferOrientation;
+
 typedef struct _CoglWinsysVtable
 {
   CoglWinsysID id;
@@ -110,6 +122,9 @@ typedef struct _CoglWinsysVtable
                            const int *rectangles,
                            int n_rectangles);
 
+  CoglRendererFramebufferOrientation
+  (*renderer_get_framebuffer_orientation) (CoglRenderer *renderer);
+
 #ifdef COGL_HAS_EGL_SUPPORT
   EGLDisplay
   (*context_egl_get_egl_display) (CoglContext *context);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]