[cogl/wip/quadbuffer-stereo: 1/7] Add support for setting up stereo CoglOnscreens



commit cdae3ad7cdf67bd3cb421acc38c50d0d2470ea5e
Author: Owen W. Taylor <otaylor fishsoup net>
Date:   Mon Apr 28 12:37:32 2014 -0400

    Add support for setting up stereo CoglOnscreens
    
    If we want to show quad-buffer stereo with Cogl, we need to pick an
    appropriate fbconfig for creating the CoglOnscreen objects. Add
    cogl_onscreen_template_set_stereo_enabled() to indicate whether
    stereo support is desired.
    
    Add cogl_framebuffer_get_stereo_mode() to see whether that worked
    (whether the system had support)
    
    Add cogl_framebuffer_get_stereo_mode() to pick whether to draw to
    the left, right, or both buffers.

 cogl/cogl-context-private.h                     |    1 +
 cogl/cogl-framebuffer-private.h                 |    9 +++-
 cogl/cogl-framebuffer.c                         |   46 ++++++++++++++++++++
 cogl/cogl-framebuffer.h                         |   52 +++++++++++++++++++++++
 cogl/cogl-onscreen-template.c                   |    8 ++++
 cogl/cogl-onscreen-template.h                   |   19 ++++++++
 cogl/cogl-types.h                               |   15 +++++++
 cogl/driver/gl/cogl-framebuffer-gl.c            |   29 +++++++++++++
 cogl/winsys/cogl-winsys-glx-feature-functions.h |    5 ++
 cogl/winsys/cogl-winsys-glx.c                   |   35 +++++++++++++++-
 examples/Makefile.am                            |    4 +-
 11 files changed, 219 insertions(+), 4 deletions(-)
---
diff --git a/cogl/cogl-context-private.h b/cogl/cogl-context-private.h
index 13bb8e4..782eff1 100644
--- a/cogl/cogl-context-private.h
+++ b/cogl/cogl-context-private.h
@@ -265,6 +265,7 @@ struct _CoglContext
 
   CoglBool current_gl_dither_enabled;
   CoglColorMask current_gl_color_mask;
+  GLenum current_gl_draw_buffer;
 
   /* Clipping */
   /* TRUE if we have a valid clipping stack flushed. In that case
diff --git a/cogl/cogl-framebuffer-private.h b/cogl/cogl-framebuffer-private.h
index 4891d53..78a93bf 100644
--- a/cogl/cogl-framebuffer-private.h
+++ b/cogl/cogl-framebuffer-private.h
@@ -61,6 +61,7 @@ typedef struct
   int samples_per_pixel;
   CoglBool swap_throttled;
   CoglBool depth_texture_enabled;
+  CoglBool stereo_enabled;
 } CoglFramebufferConfig;
 
 /* Flags to pass to _cogl_offscreen_new_with_texture_full */
@@ -86,7 +87,8 @@ typedef enum _CoglFramebufferStateIndex
   COGL_FRAMEBUFFER_STATE_INDEX_COLOR_MASK         = 6,
   COGL_FRAMEBUFFER_STATE_INDEX_FRONT_FACE_WINDING = 7,
   COGL_FRAMEBUFFER_STATE_INDEX_DEPTH_WRITE        = 8,
-  COGL_FRAMEBUFFER_STATE_INDEX_MAX                = 9
+  COGL_FRAMEBUFFER_STATE_INDEX_STEREO_MODE        = 9,
+  COGL_FRAMEBUFFER_STATE_INDEX_MAX                = 10
 } CoglFramebufferStateIndex;
 
 typedef enum _CoglFramebufferState
@@ -99,7 +101,8 @@ typedef enum _CoglFramebufferState
   COGL_FRAMEBUFFER_STATE_PROJECTION         = 1<<5,
   COGL_FRAMEBUFFER_STATE_COLOR_MASK         = 1<<6,
   COGL_FRAMEBUFFER_STATE_FRONT_FACE_WINDING = 1<<7,
-  COGL_FRAMEBUFFER_STATE_DEPTH_WRITE        = 1<<8
+  COGL_FRAMEBUFFER_STATE_DEPTH_WRITE        = 1<<8,
+  COGL_FRAMEBUFFER_STATE_STEREO_MODE        = 1<<9
 } CoglFramebufferState;
 
 #define COGL_FRAMEBUFFER_STATE_ALL ((1<<COGL_FRAMEBUFFER_STATE_INDEX_MAX) - 1)
@@ -154,6 +157,7 @@ struct _CoglFramebuffer
   CoglBool            dither_enabled;
   CoglBool            depth_writing_enabled;
   CoglColorMask       color_mask;
+  CoglStereoMode      stereo_mode;
 
   /* We journal the textured rectangles we want to submit to OpenGL so
    * we have an oppertunity to batch them together into less draw
@@ -189,6 +193,7 @@ struct _CoglFramebuffer
   CoglFramebufferBits bits;
 
   int                 samples_per_pixel;
+  CoglBool            is_stereo;
 };
 
 typedef enum {
diff --git a/cogl/cogl-framebuffer.c b/cogl/cogl-framebuffer.c
index 135b873..8418e06 100644
--- a/cogl/cogl-framebuffer.c
+++ b/cogl/cogl-framebuffer.c
@@ -127,6 +127,8 @@ _cogl_framebuffer_init (CoglFramebuffer *framebuffer,
 
   framebuffer->samples_per_pixel = 0;
 
+  framebuffer->is_stereo = FALSE;
+
   framebuffer->clip_stack = NULL;
 
   framebuffer->journal = _cogl_journal_new (framebuffer);
@@ -907,6 +909,14 @@ _cogl_framebuffer_compare_depth_write_state (CoglFramebuffer *a,
     COGL_FRAMEBUFFER_STATE_DEPTH_WRITE : 0;
 }
 
+static unsigned long
+_cogl_framebuffer_compare_stereo_mode (CoglFramebuffer *a,
+                                      CoglFramebuffer *b)
+{
+  return a->stereo_mode != b->stereo_mode ?
+    COGL_FRAMEBUFFER_STATE_STEREO_MODE : 0;
+}
+
 unsigned long
 _cogl_framebuffer_compare (CoglFramebuffer *a,
                            CoglFramebuffer *b,
@@ -959,6 +969,10 @@ _cogl_framebuffer_compare (CoglFramebuffer *a,
           differences |=
             _cogl_framebuffer_compare_depth_write_state (a, b);
           break;
+        case COGL_FRAMEBUFFER_STATE_INDEX_STEREO_MODE:
+          differences |=
+            _cogl_framebuffer_compare_stereo_mode (a, b);
+          break;
         default:
           g_warn_if_reached ();
         }
@@ -1046,6 +1060,15 @@ _cogl_framebuffer_get_stencil_bits (CoglFramebuffer *framebuffer)
   return bits.stencil;
 }
 
+gboolean
+cogl_framebuffer_get_is_stereo (CoglFramebuffer *framebuffer)
+{
+  if (framebuffer->allocated)
+    return framebuffer->is_stereo;
+  else
+    return framebuffer->config.stereo_enabled;
+}
+
 CoglColorMask
 cogl_framebuffer_get_color_mask (CoglFramebuffer *framebuffer)
 {
@@ -1069,6 +1092,29 @@ cogl_framebuffer_set_color_mask (CoglFramebuffer *framebuffer,
       COGL_FRAMEBUFFER_STATE_COLOR_MASK;
 }
 
+CoglStereoMode
+cogl_framebuffer_get_stereo_mode (CoglFramebuffer *framebuffer)
+{
+  return framebuffer->stereo_mode;
+}
+
+void
+cogl_framebuffer_set_stereo_mode (CoglFramebuffer *framebuffer,
+                                 CoglStereoMode   stereo_mode)
+{
+  if (framebuffer->stereo_mode == stereo_mode)
+    return;
+
+  /* XXX: Currently color mask changes don't go through the journal */
+  _cogl_framebuffer_flush_journal (framebuffer);
+
+  framebuffer->stereo_mode = stereo_mode;
+
+  if (framebuffer->context->current_draw_buffer == framebuffer)
+    framebuffer->context->current_draw_buffer_changes |=
+      COGL_FRAMEBUFFER_STATE_STEREO_MODE;
+}
+
 CoglBool
 cogl_framebuffer_get_depth_write_enabled (CoglFramebuffer *framebuffer)
 {
diff --git a/cogl/cogl-framebuffer.h b/cogl/cogl-framebuffer.h
index 347284f..58d65a8 100644
--- a/cogl/cogl-framebuffer.h
+++ b/cogl/cogl-framebuffer.h
@@ -737,6 +737,23 @@ cogl_framebuffer_get_alpha_bits (CoglFramebuffer *framebuffer);
 int
 cogl_framebuffer_get_depth_bits (CoglFramebuffer *framebuffer);
 
+/*
+ * cogl_framebuffer_get_is_stereo:
+ * @framebuffer: a pointer to a #CoglFramebuffer
+ *
+ * Retrieves whether @framebuffer has separate left and right
+ * buffers for use with stereo drawing. See
+ * cogl_framebuffer_set_stereo_mode().
+ *
+ * Return value: %TRUE if @framebuffer has separate left and
+ * right buffers.
+ *
+ * Since: 1.20
+ * Stability: unstable
+ */
+CoglBool
+cogl_framebuffer_get_is_stereo (CoglFramebuffer *framebuffer);
+
 /**
  * cogl_framebuffer_get_dither_enabled:
  * @framebuffer: a pointer to a #CoglFramebuffer
@@ -847,6 +864,41 @@ cogl_framebuffer_set_color_mask (CoglFramebuffer *framebuffer,
                                  CoglColorMask color_mask);
 
 /**
+ * cogl_framebuffer_get_stereo_mode:
+ * @framebuffer: a pointer to a #CoglFramebuffer
+ *
+ * Gets the current #CoglStereoMode, which defines which stereo buffers
+ * should be drawn to. See cogl_framebuffer_set_stereo_mode().
+ *
+ * Returns: A #CoglStereoMode
+ * Since: 1.20
+ * Stability: unstable
+ */
+CoglStereoMode
+cogl_framebuffer_get_stereo_mode (CoglFramebuffer *framebuffer);
+
+/**
+ * cogl_framebuffer_set_stereo_mode:
+ * @framebuffer: a pointer to a #CoglFramebuffer
+ * @stereo_mode: A #CoglStereoMode specifying which stereo buffers
+ *               should be drawn tow.
+ *
+ * Sets which stereo buffers should be drawn to. The default
+ * is %COGL_STEREO_BOTH, which means that both the left and
+ * right buffers will be affected by drawing. For this to have
+ * an effect, the display system must support stereo drawables,
+ * and the framebuffer must have been created with stereo
+ * enabled. (See cogl_onscreen_template_set_stereo_enabled(),
+ * cogl_framebuffer_get_is_stereo().)
+ *
+ * Since: 1.20
+ * Stability: unstable
+ */
+void
+cogl_framebuffer_set_stereo_mode (CoglFramebuffer *framebuffer,
+                                 CoglStereoMode stereo_mode);
+
+/**
  * cogl_framebuffer_set_depth_texture_enabled:
  * @framebuffer: A #CoglFramebuffer
  * @enabled: TRUE or FALSE
diff --git a/cogl/cogl-onscreen-template.c b/cogl/cogl-onscreen-template.c
index 5a5e54c..3940627 100644
--- a/cogl/cogl-onscreen-template.c
+++ b/cogl/cogl-onscreen-template.c
@@ -95,3 +95,11 @@ cogl_onscreen_template_set_swap_throttled (
 {
   onscreen_template->config.swap_throttled = throttled;
 }
+
+void
+cogl_onscreen_template_set_stereo_enabled (
+                                          CoglOnscreenTemplate *onscreen_template,
+                                          CoglBool enabled)
+{
+  onscreen_template->config.stereo_enabled = enabled;
+}
diff --git a/cogl/cogl-onscreen-template.h b/cogl/cogl-onscreen-template.h
index cd1d853..7024fed 100644
--- a/cogl/cogl-onscreen-template.h
+++ b/cogl/cogl-onscreen-template.h
@@ -107,6 +107,25 @@ cogl_onscreen_template_set_swap_throttled (
                                           CoglBool throttled);
 
 /**
+ * cogl_onscreen_template_set_stereo_enabled:
+ * @onscreen_template: A #CoglOnscreenTemplate template framebuffer
+ * @enabled: Whether framebuffers are created with stereo buffers
+ *
+ * Sets whether future #CoglOnscreen framebuffers derived from this
+ * template are attempted to be created with both left and right
+ * buffers, for use with stereo display. If the display system
+ * does not support stereo, then the framebuffers will be created
+ * with only a single buffer. (Use clutter_framebuffer_get_is_stereo()
+ * to check.)
+ *
+ * Since: 1.20
+ * Stability: unstable
+ */
+void
+cogl_onscreen_template_set_stereo_enabled (
+                                          CoglOnscreenTemplate *onscreen_template,
+                                          CoglBool enabled);
+/**
  * cogl_is_onscreen_template:
  * @object: A #CoglObject pointer
  *
diff --git a/cogl/cogl-types.h b/cogl/cogl-types.h
index b4d79c7..6accf8d 100644
--- a/cogl/cogl-types.h
+++ b/cogl/cogl-types.h
@@ -920,6 +920,21 @@ typedef enum { /*< prefix=COGL_READ_PIXELS >*/
   COGL_READ_PIXELS_COLOR_BUFFER = 1L << 0
 } CoglReadPixelsFlags;
 
+/**
+ * CoglStereoMode:
+ * @COGL_STEREO_BOTH: draw to both stereo buffers
+ * @COGL_STEREO_LEFT: draw only to the left stereo buffer
+ * @COGL_STEREO_RIGHT: draw only to the left stereo buffer
+ *
+ * Represents how draw should affect the two buffers
+ * of a stereo framebuffer. See cogl_framebuffer_set_stereo_mode().
+ */
+typedef enum {
+  COGL_STEREO_BOTH,
+  COGL_STEREO_LEFT,
+  COGL_STEREO_RIGHT
+} CoglStereoMode;
+
 COGL_END_DECLS
 
 #endif /* __COGL_TYPES_H__ */
diff --git a/cogl/driver/gl/cogl-framebuffer-gl.c b/cogl/driver/gl/cogl-framebuffer-gl.c
index 03a4a12..ab3a9d6 100644
--- a/cogl/driver/gl/cogl-framebuffer-gl.c
+++ b/cogl/driver/gl/cogl-framebuffer-gl.c
@@ -236,6 +236,32 @@ _cogl_framebuffer_gl_flush_front_face_winding_state (CoglFramebuffer *framebuffe
   context->current_pipeline_age--;
 }
 
+static void
+_cogl_framebuffer_gl_flush_stereo_mode_state (CoglFramebuffer *framebuffer)
+{
+  CoglContext *ctx = framebuffer->context;
+  GLenum draw_buffer = GL_BACK;
+
+  switch (framebuffer->stereo_mode)
+    {
+    case COGL_STEREO_BOTH:
+      draw_buffer = GL_BACK;
+      break;
+    case COGL_STEREO_LEFT:
+      draw_buffer = GL_BACK_LEFT;
+      break;
+    case COGL_STEREO_RIGHT:
+      draw_buffer = GL_BACK_RIGHT;
+      break;
+    }
+
+  if (ctx->current_gl_draw_buffer != draw_buffer)
+    {
+      GE (ctx, glDrawBuffer (draw_buffer));
+      ctx->current_gl_draw_buffer = draw_buffer;
+    }
+}
+
 void
 _cogl_framebuffer_gl_bind (CoglFramebuffer *framebuffer, GLenum target)
 {
@@ -377,6 +403,9 @@ _cogl_framebuffer_gl_flush_state (CoglFramebuffer *draw_buffer,
           /* Nothing to do for depth write state change; the state will always
            * be taken into account when flushing the pipeline's depth state. */
           break;
+        case COGL_FRAMEBUFFER_STATE_INDEX_STEREO_MODE:
+          _cogl_framebuffer_gl_flush_stereo_mode_state (draw_buffer);
+          break;
         default:
           g_warn_if_reached ();
         }
diff --git a/cogl/winsys/cogl-winsys-glx-feature-functions.h b/cogl/winsys/cogl-winsys-glx-feature-functions.h
index 1e2cec1..7e24638 100644
--- a/cogl/winsys/cogl-winsys-glx-feature-functions.h
+++ b/cogl/winsys/cogl-winsys-glx-feature-functions.h
@@ -183,7 +183,12 @@ COGL_WINSYS_FEATURE_BEGIN (255, 255,
                            "INTEL\0",
                            "swap_event\0",
                            0,
+#if 1
                            COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT)
+#else
+                           0)
+#endif
+
 COGL_WINSYS_FEATURE_END ()
 
 COGL_WINSYS_FEATURE_BEGIN (255, 255,
diff --git a/cogl/winsys/cogl-winsys-glx.c b/cogl/winsys/cogl-winsys-glx.c
index 3095acf..f9c50bd 100644
--- a/cogl/winsys/cogl-winsys-glx.c
+++ b/cogl/winsys/cogl-winsys-glx.c
@@ -880,6 +880,8 @@ update_winsys_features (CoglContext *context, CoglError **error)
   return TRUE;
 }
 
+#include <stdio.h>
+
 static void
 glx_attributes_from_framebuffer_config (CoglDisplay *display,
                                         CoglFramebufferConfig *config,
@@ -909,6 +911,11 @@ glx_attributes_from_framebuffer_config (CoglDisplay *display,
   attributes[i++] = 1;
   attributes[i++] = GLX_STENCIL_SIZE;
   attributes[i++] = config->need_stencil ? 1: GLX_DONT_CARE;
+  if (config->stereo_enabled)
+    {
+      attributes[i++] = GLX_STEREO;
+      attributes[i++] = TRUE;
+    }
 
   if (glx_renderer->glx_major == 1 && glx_renderer->glx_minor >= 4 &&
       config->samples_per_pixel)
@@ -948,6 +955,21 @@ find_fbconfig (CoglDisplay *display,
                                              xscreen_num,
                                              attributes,
                                              &n_configs);
+  if ((!config || n_configs == 0) && config->stereo_enabled)
+    {
+      CoglFramebufferConfig modified = *config;
+      modified.stereo_enabled = FALSE;
+
+      glx_attributes_from_framebuffer_config (display, &modified, attributes);
+
+      configs = glx_renderer->glXChooseFBConfig (xlib_renderer->xdpy,
+                                                xscreen_num,
+                                                attributes,
+                                                &n_configs);
+
+      XFree (configs);
+    }
+
   if (!configs || n_configs == 0)
     {
       _cogl_set_error (error, COGL_WINSYS_ERROR,
@@ -1286,6 +1308,17 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
       framebuffer->samples_per_pixel = samples;
     }
 
+  if (framebuffer->config.stereo_enabled)
+    {
+      int stereo;
+      int status = glx_renderer->glXGetFBConfigAttrib (xlib_renderer->xdpy,
+                                                       fbconfig,
+                                                       GLX_STEREO,
+                                                       &stereo);
+      g_return_val_if_fail (status == Success, TRUE);
+      framebuffer->is_stereo = stereo != 0;
+    }
+
   /* FIXME: We need to explicitly Select for ConfigureNotify events.
    * For foreign windows we need to be careful not to mess up any
    * existing event mask.
@@ -1856,7 +1889,7 @@ _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen,
                                       rect[0], rect[1], x2, y2,
                                       GL_COLOR_BUFFER_BIT, GL_NEAREST);
         }
-      context->glDrawBuffer (GL_BACK);
+      context->glDrawBuffer (context->current_gl_draw_buffer);
     }
 
   /* NB: unlike glXSwapBuffers, glXCopySubBuffer and
diff --git a/examples/Makefile.am b/examples/Makefile.am
index b7cccec..01cf003 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -33,7 +33,7 @@ cogl_info_SOURCES = cogl-info.c
 cogl_info_LDADD = $(common_ldadd)
 
 if USE_GLIB
-programs += cogl-hello cogl-msaa cogl-gles2-context cogl-point-sprites
+programs += cogl-hello cogl-msaa cogl-gles2-context cogl-point-sprites cogl-stereo
 examples_datadir = $(pkgdatadir)/examples-data
 examples_data_DATA =
 
@@ -43,6 +43,8 @@ cogl_msaa_SOURCES = cogl-msaa.c
 cogl_msaa_LDADD = $(common_ldadd)
 cogl_point_sprites_SOURCES = cogl-point-sprites.c
 cogl_point_sprites_LDADD = $(common_ldadd)
+cogl_stereo_SOURCES = cogl-stereo.c
+cogl_stereo_LDADD = $(common_ldadd)
 
 if BUILD_COGL_PANGO
 programs += cogl-crate


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