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 needed.

Add cogl_framebuffer_get_stereo_mode() to see if a framebuffer was
created with stereo support.

Add cogl_framebuffer_get_stereo_mode() to pick whether to draw to
the left, right, or both buffers.

Reviewed-by: Robert Bragg <robert.bragg@intel.com>
This commit is contained in:
Owen W. Taylor 2014-04-28 12:37:32 -04:00
parent 775fcbaaaf
commit d16df5a5aa
10 changed files with 185 additions and 3 deletions

View File

@ -270,6 +270,7 @@ struct _CoglContext
CoglBool current_gl_dither_enabled; CoglBool current_gl_dither_enabled;
CoglColorMask current_gl_color_mask; CoglColorMask current_gl_color_mask;
GLenum current_gl_draw_buffer;
/* Clipping */ /* Clipping */
/* TRUE if we have a valid clipping stack flushed. In that case /* TRUE if we have a valid clipping stack flushed. In that case

View File

@ -61,6 +61,7 @@ typedef struct
int samples_per_pixel; int samples_per_pixel;
CoglBool swap_throttled; CoglBool swap_throttled;
CoglBool depth_texture_enabled; CoglBool depth_texture_enabled;
CoglBool stereo_enabled;
} CoglFramebufferConfig; } CoglFramebufferConfig;
/* Flags to pass to _cogl_offscreen_new_with_texture_full */ /* 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_COLOR_MASK = 6,
COGL_FRAMEBUFFER_STATE_INDEX_FRONT_FACE_WINDING = 7, COGL_FRAMEBUFFER_STATE_INDEX_FRONT_FACE_WINDING = 7,
COGL_FRAMEBUFFER_STATE_INDEX_DEPTH_WRITE = 8, 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; } CoglFramebufferStateIndex;
typedef enum _CoglFramebufferState typedef enum _CoglFramebufferState
@ -99,7 +101,8 @@ typedef enum _CoglFramebufferState
COGL_FRAMEBUFFER_STATE_PROJECTION = 1<<5, COGL_FRAMEBUFFER_STATE_PROJECTION = 1<<5,
COGL_FRAMEBUFFER_STATE_COLOR_MASK = 1<<6, COGL_FRAMEBUFFER_STATE_COLOR_MASK = 1<<6,
COGL_FRAMEBUFFER_STATE_FRONT_FACE_WINDING = 1<<7, 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; } CoglFramebufferState;
#define COGL_FRAMEBUFFER_STATE_ALL ((1<<COGL_FRAMEBUFFER_STATE_INDEX_MAX) - 1) #define COGL_FRAMEBUFFER_STATE_ALL ((1<<COGL_FRAMEBUFFER_STATE_INDEX_MAX) - 1)
@ -154,6 +157,7 @@ struct _CoglFramebuffer
CoglBool dither_enabled; CoglBool dither_enabled;
CoglBool depth_writing_enabled; CoglBool depth_writing_enabled;
CoglColorMask color_mask; CoglColorMask color_mask;
CoglStereoMode stereo_mode;
/* We journal the textured rectangles we want to submit to OpenGL so /* We journal the textured rectangles we want to submit to OpenGL so
* we have an oppertunity to batch them together into less draw * we have an oppertunity to batch them together into less draw

View File

@ -907,6 +907,14 @@ _cogl_framebuffer_compare_depth_write_state (CoglFramebuffer *a,
COGL_FRAMEBUFFER_STATE_DEPTH_WRITE : 0; 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 unsigned long
_cogl_framebuffer_compare (CoglFramebuffer *a, _cogl_framebuffer_compare (CoglFramebuffer *a,
CoglFramebuffer *b, CoglFramebuffer *b,
@ -959,6 +967,10 @@ _cogl_framebuffer_compare (CoglFramebuffer *a,
differences |= differences |=
_cogl_framebuffer_compare_depth_write_state (a, b); _cogl_framebuffer_compare_depth_write_state (a, b);
break; break;
case COGL_FRAMEBUFFER_STATE_INDEX_STEREO_MODE:
differences |=
_cogl_framebuffer_compare_stereo_mode (a, b);
break;
default: default:
g_warn_if_reached (); g_warn_if_reached ();
} }
@ -1046,6 +1058,12 @@ _cogl_framebuffer_get_stencil_bits (CoglFramebuffer *framebuffer)
return bits.stencil; return bits.stencil;
} }
gboolean
cogl_framebuffer_get_is_stereo (CoglFramebuffer *framebuffer)
{
return framebuffer->config.stereo_enabled;
}
CoglColorMask CoglColorMask
cogl_framebuffer_get_color_mask (CoglFramebuffer *framebuffer) cogl_framebuffer_get_color_mask (CoglFramebuffer *framebuffer)
{ {
@ -1069,6 +1087,29 @@ cogl_framebuffer_set_color_mask (CoglFramebuffer *framebuffer,
COGL_FRAMEBUFFER_STATE_COLOR_MASK; 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;
/* Stereo mode 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 CoglBool
cogl_framebuffer_get_depth_write_enabled (CoglFramebuffer *framebuffer) cogl_framebuffer_get_depth_write_enabled (CoglFramebuffer *framebuffer)
{ {

View File

@ -737,6 +737,23 @@ cogl_framebuffer_get_alpha_bits (CoglFramebuffer *framebuffer);
int int
cogl_framebuffer_get_depth_bits (CoglFramebuffer *framebuffer); 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: * cogl_framebuffer_get_dither_enabled:
* @framebuffer: a pointer to a #CoglFramebuffer * @framebuffer: a pointer to a #CoglFramebuffer
@ -846,6 +863,41 @@ void
cogl_framebuffer_set_color_mask (CoglFramebuffer *framebuffer, cogl_framebuffer_set_color_mask (CoglFramebuffer *framebuffer,
CoglColorMask color_mask); 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: * cogl_framebuffer_set_depth_texture_enabled:
* @framebuffer: A #CoglFramebuffer * @framebuffer: A #CoglFramebuffer

View File

@ -95,3 +95,11 @@ cogl_onscreen_template_set_swap_throttled (
{ {
onscreen_template->config.swap_throttled = 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;
}

View File

@ -106,6 +106,24 @@ cogl_onscreen_template_set_swap_throttled (
CoglOnscreenTemplate *onscreen_template, CoglOnscreenTemplate *onscreen_template,
CoglBool 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 creation of the framebuffer will
* fail.
*
* Since: 1.20
* Stability: unstable
*/
void
cogl_onscreen_template_set_stereo_enabled (
CoglOnscreenTemplate *onscreen_template,
CoglBool enabled);
/** /**
* cogl_is_onscreen_template: * cogl_is_onscreen_template:
* @object: A #CoglObject pointer * @object: A #CoglObject pointer

View File

@ -920,6 +920,21 @@ typedef enum { /*< prefix=COGL_READ_PIXELS >*/
COGL_READ_PIXELS_COLOR_BUFFER = 1L << 0 COGL_READ_PIXELS_COLOR_BUFFER = 1L << 0
} CoglReadPixelsFlags; } 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 COGL_END_DECLS
#endif /* __COGL_TYPES_H__ */ #endif /* __COGL_TYPES_H__ */

View File

@ -236,6 +236,39 @@ _cogl_framebuffer_gl_flush_front_face_winding_state (CoglFramebuffer *framebuffe
context->current_pipeline_age--; context->current_pipeline_age--;
} }
static void
_cogl_framebuffer_gl_flush_stereo_mode_state (CoglFramebuffer *framebuffer)
{
CoglContext *ctx = framebuffer->context;
GLenum draw_buffer = GL_BACK;
if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN)
return;
/* The one-shot default draw buffer setting in _cogl_framebuffer_gl_bind
* must have already happened. If not it would override what we set here. */
g_assert (ctx->was_bound_to_onscreen);
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 void
_cogl_framebuffer_gl_bind (CoglFramebuffer *framebuffer, GLenum target) _cogl_framebuffer_gl_bind (CoglFramebuffer *framebuffer, GLenum target)
{ {
@ -406,6 +439,9 @@ _cogl_framebuffer_gl_flush_state (CoglFramebuffer *draw_buffer,
/* Nothing to do for depth write state change; the state will always /* Nothing to do for depth write state change; the state will always
* be taken into account when flushing the pipeline's depth state. */ * be taken into account when flushing the pipeline's depth state. */
break; break;
case COGL_FRAMEBUFFER_STATE_INDEX_STEREO_MODE:
_cogl_framebuffer_gl_flush_stereo_mode_state (draw_buffer);
break;
default: default:
g_warn_if_reached (); g_warn_if_reached ();
} }

View File

@ -184,6 +184,7 @@ COGL_WINSYS_FEATURE_BEGIN (255, 255,
"swap_event\0", "swap_event\0",
0, 0,
COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT) COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT)
COGL_WINSYS_FEATURE_END () COGL_WINSYS_FEATURE_END ()
COGL_WINSYS_FEATURE_BEGIN (255, 255, COGL_WINSYS_FEATURE_BEGIN (255, 255,

View File

@ -909,6 +909,11 @@ glx_attributes_from_framebuffer_config (CoglDisplay *display,
attributes[i++] = 1; attributes[i++] = 1;
attributes[i++] = GLX_STENCIL_SIZE; attributes[i++] = GLX_STENCIL_SIZE;
attributes[i++] = config->need_stencil ? 1: GLX_DONT_CARE; 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 && if (glx_renderer->glx_major == 1 && glx_renderer->glx_minor >= 4 &&
config->samples_per_pixel) config->samples_per_pixel)
@ -948,6 +953,7 @@ find_fbconfig (CoglDisplay *display,
xscreen_num, xscreen_num,
attributes, attributes,
&n_configs); &n_configs);
if (!configs || n_configs == 0) if (!configs || n_configs == 0)
{ {
_cogl_set_error (error, COGL_WINSYS_ERROR, _cogl_set_error (error, COGL_WINSYS_ERROR,
@ -1856,7 +1862,7 @@ _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen,
rect[0], rect[1], x2, y2, rect[0], rect[1], x2, y2,
GL_COLOR_BUFFER_BIT, GL_NEAREST); GL_COLOR_BUFFER_BIT, GL_NEAREST);
} }
context->glDrawBuffer (GL_BACK); context->glDrawBuffer (context->current_gl_draw_buffer);
} }
/* NB: unlike glXSwapBuffers, glXCopySubBuffer and /* NB: unlike glXSwapBuffers, glXCopySubBuffer and