add cogl_push_draw_buffer() and cogl_pop_draw_buffer()
These are necessary if nesting redirections to an fbo, otherwise there's no way to know how to restore previous state. glPushAttrib(GL_COLOR_BUFFER_BIT) would save draw buffer state, but also saves a lot of other stuff, and cogl_draw_buffer() relies on knowing about all draw buffer state changes. So we have to implement a draw buffer stack ourselves. Signed-off-by: Robert Bragg <robert@linux.intel.com>
This commit is contained in:
parent
d5fc61102f
commit
e47b198225
@ -128,6 +128,20 @@ void cogl_offscreen_blit_region (CoglHandle src_buffer,
|
||||
void cogl_draw_buffer (CoglBufferTarget target,
|
||||
CoglHandle offscreen);
|
||||
|
||||
/**
|
||||
* cogl_push_draw_buffer:
|
||||
*
|
||||
* Save cogl_draw_buffer() state.
|
||||
*/
|
||||
void cogl_push_draw_buffer (void);
|
||||
|
||||
/**
|
||||
* cogl_pop_draw_buffer:
|
||||
*
|
||||
* Restore cogl_draw_buffer() state.
|
||||
*/
|
||||
void cogl_pop_draw_buffer (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __COGL_OFFSCREEN_H__ */
|
||||
|
@ -42,6 +42,7 @@ cogl_create_context ()
|
||||
{
|
||||
GLubyte default_texture_data[] = { 0xff, 0xff, 0xff, 0x0 };
|
||||
gulong enable_flags = 0;
|
||||
CoglDrawBufferState *draw_buffer;
|
||||
|
||||
if (_context != NULL)
|
||||
return FALSE;
|
||||
@ -78,7 +79,11 @@ cogl_create_context ()
|
||||
sizeof (CoglLayerInfo));
|
||||
_context->n_texcoord_arrays_enabled = 0;
|
||||
|
||||
_context->draw_buffer = COGL_WINDOW_BUFFER;
|
||||
draw_buffer = g_slice_new0 (CoglDrawBufferState);
|
||||
draw_buffer->target = COGL_WINDOW_BUFFER;
|
||||
draw_buffer->offscreen = COGL_INVALID_HANDLE;
|
||||
_context->draw_buffer_stack =
|
||||
g_slist_prepend (NULL, draw_buffer);
|
||||
|
||||
_context->path_nodes = g_array_new (FALSE, FALSE, sizeof (CoglPathNode));
|
||||
_context->last_path = 0;
|
||||
|
@ -36,6 +36,12 @@ typedef struct
|
||||
GLubyte c[4];
|
||||
} CoglTextureGLVertex;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CoglBufferTarget target;
|
||||
CoglHandle offscreen;
|
||||
} CoglDrawBufferState;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* Features cache */
|
||||
@ -82,7 +88,7 @@ typedef struct
|
||||
guint n_texcoord_arrays_enabled;
|
||||
|
||||
/* Framebuffer objects */
|
||||
CoglBufferTarget draw_buffer;
|
||||
GSList *draw_buffer_stack;
|
||||
|
||||
/* Clip stack */
|
||||
CoglClipStackState clip;
|
||||
|
@ -242,9 +242,13 @@ void
|
||||
cogl_draw_buffer (CoglBufferTarget target, CoglHandle offscreen)
|
||||
{
|
||||
CoglFbo *fbo = NULL;
|
||||
CoglDrawBufferState *draw_buffer;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
g_assert (ctx->draw_buffer_stack != NULL);
|
||||
draw_buffer = ctx->draw_buffer_stack->data;
|
||||
|
||||
if (target == COGL_OFFSCREEN_BUFFER)
|
||||
{
|
||||
/* Make sure it is a valid fbo handle */
|
||||
@ -254,7 +258,7 @@ cogl_draw_buffer (CoglBufferTarget target, CoglHandle offscreen)
|
||||
fbo = _cogl_offscreen_pointer_from_handle (offscreen);
|
||||
|
||||
/* Check current draw buffer target */
|
||||
if (ctx->draw_buffer != COGL_OFFSCREEN_BUFFER)
|
||||
if (draw_buffer->target != COGL_OFFSCREEN_BUFFER)
|
||||
{
|
||||
/* Push the viewport and matrix setup if redirecting
|
||||
from a non-screen buffer */
|
||||
@ -303,7 +307,7 @@ cogl_draw_buffer (CoglBufferTarget target, CoglHandle offscreen)
|
||||
(target & COGL_MASK_BUFFER))
|
||||
{
|
||||
/* Check current draw buffer target */
|
||||
if (ctx->draw_buffer == COGL_OFFSCREEN_BUFFER)
|
||||
if (draw_buffer->target == COGL_OFFSCREEN_BUFFER)
|
||||
{
|
||||
/* Pop viewport and matrices if redirecting back
|
||||
from an offscreen buffer */
|
||||
@ -338,5 +342,70 @@ cogl_draw_buffer (CoglBufferTarget target, CoglHandle offscreen)
|
||||
}
|
||||
|
||||
/* Store new target */
|
||||
ctx->draw_buffer = target;
|
||||
draw_buffer->target = target;
|
||||
if (draw_buffer->offscreen != offscreen)
|
||||
{
|
||||
if (draw_buffer->offscreen != COGL_INVALID_HANDLE)
|
||||
cogl_handle_unref (draw_buffer->offscreen);
|
||||
if (offscreen != COGL_INVALID_HANDLE)
|
||||
cogl_handle_ref (offscreen);
|
||||
draw_buffer->offscreen = offscreen;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cogl_push_draw_buffer(void)
|
||||
{
|
||||
CoglDrawBufferState *old;
|
||||
CoglDrawBufferState *draw_buffer;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
g_assert (ctx->draw_buffer_stack != NULL);
|
||||
old = ctx->draw_buffer_stack->data;
|
||||
|
||||
draw_buffer = g_slice_new0 (CoglDrawBufferState);
|
||||
*draw_buffer = *old;
|
||||
|
||||
ctx->draw_buffer_stack =
|
||||
g_slist_prepend (ctx->draw_buffer_stack, draw_buffer);
|
||||
}
|
||||
|
||||
void
|
||||
cogl_pop_draw_buffer(void)
|
||||
{
|
||||
CoglDrawBufferState *to_pop;
|
||||
CoglDrawBufferState *to_restore;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
g_assert (ctx->draw_buffer_stack != NULL);
|
||||
if (ctx->draw_buffer_stack->next == NULL)
|
||||
{
|
||||
g_warning ("1 more cogl_pop_draw_buffer() than cogl_push_draw_buffer()");
|
||||
return;
|
||||
}
|
||||
|
||||
to_pop = ctx->draw_buffer_stack->data;
|
||||
to_restore = ctx->draw_buffer_stack->next->data;
|
||||
|
||||
/* the logic in cogl_draw_buffer() only works if
|
||||
* to_pop is still on top of the stack, because
|
||||
* cogl_draw_buffer() needs to know the previous
|
||||
* state.
|
||||
*/
|
||||
cogl_draw_buffer (to_restore->target, to_restore->offscreen);
|
||||
|
||||
/* cogl_draw_buffer() should have set top of stack
|
||||
* to to_restore
|
||||
*/
|
||||
g_assert (to_restore->target == to_pop->target);
|
||||
g_assert (to_restore->offscreen == to_pop->offscreen);
|
||||
|
||||
g_assert (ctx->draw_buffer_stack->data == to_pop);
|
||||
ctx->draw_buffer_stack =
|
||||
g_slist_remove_link (ctx->draw_buffer_stack,
|
||||
ctx->draw_buffer_stack);
|
||||
|
||||
g_slice_free (CoglDrawBufferState, to_pop);
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ cogl_create_context ()
|
||||
{
|
||||
GLubyte default_texture_data[] = { 0xff, 0xff, 0xff, 0x0 };
|
||||
gulong enable_flags = 0;
|
||||
CoglDrawBufferState *draw_buffer;
|
||||
|
||||
if (_context != NULL)
|
||||
return FALSE;
|
||||
@ -81,7 +82,11 @@ cogl_create_context ()
|
||||
sizeof (CoglLayerInfo));
|
||||
_context->n_texcoord_arrays_enabled = 0;
|
||||
|
||||
_context->draw_buffer = COGL_WINDOW_BUFFER;
|
||||
draw_buffer = g_slice_new0 (CoglDrawBufferState);
|
||||
draw_buffer->target = COGL_WINDOW_BUFFER;
|
||||
draw_buffer->offscreen = COGL_INVALID_HANDLE;
|
||||
_context->draw_buffer_stack =
|
||||
g_slist_prepend (NULL, draw_buffer);
|
||||
|
||||
_context->path_nodes = g_array_new (FALSE, FALSE, sizeof (CoglPathNode));
|
||||
_context->last_path = 0;
|
||||
|
@ -38,6 +38,12 @@ typedef struct
|
||||
GLubyte c[4];
|
||||
} CoglTextureGLVertex;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CoglBufferTarget target;
|
||||
CoglHandle offscreen;
|
||||
} CoglDrawBufferState;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* Features cache */
|
||||
@ -84,7 +90,7 @@ typedef struct
|
||||
guint n_texcoord_arrays_enabled;
|
||||
|
||||
/* Framebuffer objects */
|
||||
CoglBufferTarget draw_buffer;
|
||||
GSList *draw_buffer_stack;
|
||||
|
||||
/* Clip stack */
|
||||
CoglClipStackState clip;
|
||||
|
@ -180,9 +180,13 @@ void
|
||||
cogl_draw_buffer (CoglBufferTarget target, CoglHandle offscreen)
|
||||
{
|
||||
CoglFbo *fbo = NULL;
|
||||
CoglDrawBufferState *draw_buffer;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
g_assert (ctx->draw_buffer_stack != NULL);
|
||||
draw_buffer = ctx->draw_buffer_stack->data;
|
||||
|
||||
if (target == COGL_OFFSCREEN_BUFFER)
|
||||
{
|
||||
GLboolean scissor_enabled;
|
||||
@ -195,7 +199,7 @@ cogl_draw_buffer (CoglBufferTarget target, CoglHandle offscreen)
|
||||
fbo = _cogl_offscreen_pointer_from_handle (offscreen);
|
||||
|
||||
/* Check current draw buffer target */
|
||||
if (ctx->draw_buffer != COGL_OFFSCREEN_BUFFER)
|
||||
if (draw_buffer->target != COGL_OFFSCREEN_BUFFER)
|
||||
{
|
||||
/* Push the viewport and matrix setup if redirecting
|
||||
from a non-screen buffer */
|
||||
@ -249,7 +253,7 @@ cogl_draw_buffer (CoglBufferTarget target, CoglHandle offscreen)
|
||||
(target & COGL_MASK_BUFFER))
|
||||
{
|
||||
/* Check current draw buffer target */
|
||||
if (ctx->draw_buffer == COGL_OFFSCREEN_BUFFER)
|
||||
if (draw_buffer->target == COGL_OFFSCREEN_BUFFER)
|
||||
{
|
||||
/* Pop viewport and matrices if redirecting back
|
||||
from an offscreen buffer */
|
||||
@ -285,7 +289,72 @@ cogl_draw_buffer (CoglBufferTarget target, CoglHandle offscreen)
|
||||
}
|
||||
|
||||
/* Store new target */
|
||||
ctx->draw_buffer = target;
|
||||
draw_buffer->target = target;
|
||||
if (draw_buffer->offscreen != offscreen)
|
||||
{
|
||||
if (draw_buffer->offscreen != COGL_INVALID_HANDLE)
|
||||
cogl_handle_unref (draw_buffer->offscreen);
|
||||
if (offscreen != COGL_INVALID_HANDLE)
|
||||
cogl_handle_ref (offscreen);
|
||||
draw_buffer->offscreen = offscreen;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cogl_push_draw_buffer(void)
|
||||
{
|
||||
CoglDrawBufferState *old;
|
||||
CoglDrawBufferState *draw_buffer;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
g_assert (ctx->draw_buffer_stack != NULL);
|
||||
old = ctx->draw_buffer_stack->data;
|
||||
|
||||
draw_buffer = g_slice_new0 (CoglDrawBufferState);
|
||||
*draw_buffer = *old;
|
||||
|
||||
ctx->draw_buffer_stack =
|
||||
g_slist_prepend (ctx->draw_buffer_stack, draw_buffer);
|
||||
}
|
||||
|
||||
void
|
||||
cogl_pop_draw_buffer(void)
|
||||
{
|
||||
CoglDrawBufferState *to_pop;
|
||||
CoglDrawBufferState *to_restore;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
g_assert (ctx->draw_buffer_stack != NULL);
|
||||
if (ctx->draw_buffer_stack->next == NULL)
|
||||
{
|
||||
g_warning ("1 more cogl_pop_draw_buffer() than cogl_push_draw_buffer()");
|
||||
return;
|
||||
}
|
||||
|
||||
to_pop = ctx->draw_buffer_stack->data;
|
||||
to_restore = ctx->draw_buffer_stack->next->data;
|
||||
|
||||
/* the logic in cogl_draw_buffer() only works if
|
||||
* to_pop is still on top of the stack, because
|
||||
* cogl_draw_buffer() needs to know the previous
|
||||
* state.
|
||||
*/
|
||||
cogl_draw_buffer (to_restore->target, to_restore->offscreen);
|
||||
|
||||
/* cogl_draw_buffer() should have set top of stack
|
||||
* to to_restore
|
||||
*/
|
||||
g_assert (to_restore->target == to_pop->target);
|
||||
g_assert (to_restore->offscreen == to_pop->offscreen);
|
||||
|
||||
g_assert (ctx->draw_buffer_stack->data == to_pop);
|
||||
ctx->draw_buffer_stack =
|
||||
g_slist_remove_link (ctx->draw_buffer_stack,
|
||||
ctx->draw_buffer_stack);
|
||||
|
||||
g_slice_free (CoglDrawBufferState, to_pop);
|
||||
}
|
||||
|
||||
#else /* HAVE_COGL_GLES2 */
|
||||
|
Loading…
Reference in New Issue
Block a user