[cogl/wip/neil/snippets] Allow the winsys backend to force rendering onscreen buffers flipped



commit 617f65639af18da6b4d28bd68f4703b2c6e68280
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 |   11 +++++++----
 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, 100 insertions(+), 25 deletions(-)
---
diff --git a/cogl/cogl-clip-stack.c b/cogl/cogl-clip-stack.c
index 5bcd29d..9c44407 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 53a7cef..8336639 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 8183982..37901cd 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 f70657c..ddd2936 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 15bd45c..160b42d 100644
--- a/cogl/cogl-matrix-stack.c
+++ b/cogl/cogl-matrix-stack.c
@@ -450,7 +450,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 17da03c..9397e80 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;
@@ -984,7 +987,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)
@@ -999,7 +1002,7 @@ _cogl_pipeline_progend_glsl_pre_paint (CoglPipeline *pipeline)
         check_and_update_matrix_cache (projection_stack,
                                        &program_state->projection_cache,
                                        needs_flip &&
-                                       program_state->flip_uniform == -1);
+                                       !program_state->has_vertex_snippets);
 
       modelview_changed =
         check_and_update_matrix_cache (modelview_stack,
@@ -1022,7 +1025,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);
@@ -1082,7 +1085,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 45222ef..1a354d8 100644
--- a/cogl/cogl-renderer-private.h
+++ b/cogl/cogl-renderer-private.h
@@ -83,4 +83,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 a691bda..8557846 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 15d0d7a..676c3c6 100644
--- a/cogl/winsys/cogl-winsys-egl.c
+++ b/cogl/winsys/cogl-winsys-egl.c
@@ -1532,11 +1532,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];
+      }
 
   if (egl_renderer->pf_eglSwapBuffersRegion (egl_renderer->edpy,
                                              egl_onscreen->egl_surface,
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]