mirror of
https://github.com/brl/mutter.git
synced 2025-02-17 05:44:08 +00:00
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
c8862e35cc
commit
cb344560dc
@ -128,6 +128,20 @@ void cogl_offscreen_blit_region (CoglHandle src_buffer,
|
|||||||
void cogl_draw_buffer (CoglBufferTarget target,
|
void cogl_draw_buffer (CoglBufferTarget target,
|
||||||
CoglHandle offscreen);
|
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
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __COGL_OFFSCREEN_H__ */
|
#endif /* __COGL_OFFSCREEN_H__ */
|
||||||
|
@ -42,6 +42,7 @@ cogl_create_context ()
|
|||||||
{
|
{
|
||||||
GLubyte default_texture_data[] = { 0xff, 0xff, 0xff, 0x0 };
|
GLubyte default_texture_data[] = { 0xff, 0xff, 0xff, 0x0 };
|
||||||
gulong enable_flags = 0;
|
gulong enable_flags = 0;
|
||||||
|
CoglDrawBufferState *draw_buffer;
|
||||||
|
|
||||||
if (_context != NULL)
|
if (_context != NULL)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -78,7 +79,11 @@ cogl_create_context ()
|
|||||||
sizeof (CoglLayerInfo));
|
sizeof (CoglLayerInfo));
|
||||||
_context->n_texcoord_arrays_enabled = 0;
|
_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->path_nodes = g_array_new (FALSE, FALSE, sizeof (CoglPathNode));
|
||||||
_context->last_path = 0;
|
_context->last_path = 0;
|
||||||
|
@ -36,6 +36,12 @@ typedef struct
|
|||||||
GLubyte c[4];
|
GLubyte c[4];
|
||||||
} CoglTextureGLVertex;
|
} CoglTextureGLVertex;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
CoglBufferTarget target;
|
||||||
|
CoglHandle offscreen;
|
||||||
|
} CoglDrawBufferState;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
/* Features cache */
|
/* Features cache */
|
||||||
@ -82,7 +88,7 @@ typedef struct
|
|||||||
guint n_texcoord_arrays_enabled;
|
guint n_texcoord_arrays_enabled;
|
||||||
|
|
||||||
/* Framebuffer objects */
|
/* Framebuffer objects */
|
||||||
CoglBufferTarget draw_buffer;
|
GSList *draw_buffer_stack;
|
||||||
|
|
||||||
/* Clip stack */
|
/* Clip stack */
|
||||||
CoglClipStackState clip;
|
CoglClipStackState clip;
|
||||||
|
@ -242,9 +242,13 @@ void
|
|||||||
cogl_draw_buffer (CoglBufferTarget target, CoglHandle offscreen)
|
cogl_draw_buffer (CoglBufferTarget target, CoglHandle offscreen)
|
||||||
{
|
{
|
||||||
CoglFbo *fbo = NULL;
|
CoglFbo *fbo = NULL;
|
||||||
|
CoglDrawBufferState *draw_buffer;
|
||||||
|
|
||||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
_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)
|
if (target == COGL_OFFSCREEN_BUFFER)
|
||||||
{
|
{
|
||||||
/* Make sure it is a valid fbo handle */
|
/* 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);
|
fbo = _cogl_offscreen_pointer_from_handle (offscreen);
|
||||||
|
|
||||||
/* Check current draw buffer target */
|
/* 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
|
/* Push the viewport and matrix setup if redirecting
|
||||||
from a non-screen buffer */
|
from a non-screen buffer */
|
||||||
@ -303,7 +307,7 @@ cogl_draw_buffer (CoglBufferTarget target, CoglHandle offscreen)
|
|||||||
(target & COGL_MASK_BUFFER))
|
(target & COGL_MASK_BUFFER))
|
||||||
{
|
{
|
||||||
/* Check current draw buffer target */
|
/* 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
|
/* Pop viewport and matrices if redirecting back
|
||||||
from an offscreen buffer */
|
from an offscreen buffer */
|
||||||
@ -338,5 +342,70 @@ cogl_draw_buffer (CoglBufferTarget target, CoglHandle offscreen)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Store new target */
|
/* 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 };
|
GLubyte default_texture_data[] = { 0xff, 0xff, 0xff, 0x0 };
|
||||||
gulong enable_flags = 0;
|
gulong enable_flags = 0;
|
||||||
|
CoglDrawBufferState *draw_buffer;
|
||||||
|
|
||||||
if (_context != NULL)
|
if (_context != NULL)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -81,7 +82,11 @@ cogl_create_context ()
|
|||||||
sizeof (CoglLayerInfo));
|
sizeof (CoglLayerInfo));
|
||||||
_context->n_texcoord_arrays_enabled = 0;
|
_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->path_nodes = g_array_new (FALSE, FALSE, sizeof (CoglPathNode));
|
||||||
_context->last_path = 0;
|
_context->last_path = 0;
|
||||||
|
@ -38,6 +38,12 @@ typedef struct
|
|||||||
GLubyte c[4];
|
GLubyte c[4];
|
||||||
} CoglTextureGLVertex;
|
} CoglTextureGLVertex;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
CoglBufferTarget target;
|
||||||
|
CoglHandle offscreen;
|
||||||
|
} CoglDrawBufferState;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
/* Features cache */
|
/* Features cache */
|
||||||
@ -84,7 +90,7 @@ typedef struct
|
|||||||
guint n_texcoord_arrays_enabled;
|
guint n_texcoord_arrays_enabled;
|
||||||
|
|
||||||
/* Framebuffer objects */
|
/* Framebuffer objects */
|
||||||
CoglBufferTarget draw_buffer;
|
GSList *draw_buffer_stack;
|
||||||
|
|
||||||
/* Clip stack */
|
/* Clip stack */
|
||||||
CoglClipStackState clip;
|
CoglClipStackState clip;
|
||||||
|
@ -180,9 +180,13 @@ void
|
|||||||
cogl_draw_buffer (CoglBufferTarget target, CoglHandle offscreen)
|
cogl_draw_buffer (CoglBufferTarget target, CoglHandle offscreen)
|
||||||
{
|
{
|
||||||
CoglFbo *fbo = NULL;
|
CoglFbo *fbo = NULL;
|
||||||
|
CoglDrawBufferState *draw_buffer;
|
||||||
|
|
||||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
_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)
|
if (target == COGL_OFFSCREEN_BUFFER)
|
||||||
{
|
{
|
||||||
GLboolean scissor_enabled;
|
GLboolean scissor_enabled;
|
||||||
@ -195,7 +199,7 @@ cogl_draw_buffer (CoglBufferTarget target, CoglHandle offscreen)
|
|||||||
fbo = _cogl_offscreen_pointer_from_handle (offscreen);
|
fbo = _cogl_offscreen_pointer_from_handle (offscreen);
|
||||||
|
|
||||||
/* Check current draw buffer target */
|
/* 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
|
/* Push the viewport and matrix setup if redirecting
|
||||||
from a non-screen buffer */
|
from a non-screen buffer */
|
||||||
@ -249,7 +253,7 @@ cogl_draw_buffer (CoglBufferTarget target, CoglHandle offscreen)
|
|||||||
(target & COGL_MASK_BUFFER))
|
(target & COGL_MASK_BUFFER))
|
||||||
{
|
{
|
||||||
/* Check current draw buffer target */
|
/* 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
|
/* Pop viewport and matrices if redirecting back
|
||||||
from an offscreen buffer */
|
from an offscreen buffer */
|
||||||
@ -285,7 +289,72 @@ cogl_draw_buffer (CoglBufferTarget target, CoglHandle offscreen)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Store new target */
|
/* 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 */
|
#else /* HAVE_COGL_GLES2 */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user