From 879ce7301aec71d19252528feabc19c946c6e856 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Fri, 16 Sep 2011 11:41:21 +0100 Subject: [PATCH] cogl-framebuffer: Force flushing the color mask when changing fbs When changing between two framebuffers that have different color masks it now forces the pipeline to flush the mask by setting current_pipeline_changes_since_flush. For this to work there needs to be a common bit of code that gets called when the framebuffers are changed that has access to both the old framebuffer and the new framebuffer. _cogl_set_framebuffers_real can't be used for this because when it is called from cogl_pop_framebuffer the stack entries have already changed so it can't know the old framebuffer. This patch adds a new function called notify_buffers_changed which should get called whenever the buffers are changed and it explicitly gets passed pointers to the old and new buffers. cogl_pop_framebuffer now calls this instead of trying to use _cogl_set_framebuffers_real to force a flush. This patch also fixes the ctx->window_buffer pointer. Previously this was implemented by searching in the framebuffer stack for an onscreen framebuffer whenever the current buffers are changed. However it does this after the stack has already changed so it won't usually find the right buffer. Reviewed-by: Robert Bragg --- cogl/cogl-context.c | 7 +++ cogl/cogl-framebuffer.c | 94 +++++++++++++++++++++++++---------------- 2 files changed, 64 insertions(+), 37 deletions(-) diff --git a/cogl/cogl-context.c b/cogl/cogl-context.c index 02f05a653..fe86721b6 100644 --- a/cogl/cogl-context.c +++ b/cogl/cogl-context.c @@ -297,6 +297,7 @@ cogl_context_new (CoglDisplay *display, for (i = 0; i < COGL_BUFFER_BIND_TARGET_COUNT; i++) context->current_buffer[i] = NULL; + context->window_buffer = NULL; context->framebuffer_stack = _cogl_create_framebuffer_stack (); /* XXX: In this case the Clutter backend is still responsible for @@ -399,6 +400,12 @@ _cogl_context_free (CoglContext *context) _cogl_destroy_texture_units (); + if (context->window_buffer) + { + cogl_object_unref (context->window_buffer); + context->window_buffer = NULL; + } + _cogl_free_framebuffer_stack (context->framebuffer_stack); if (context->current_path) diff --git a/cogl/cogl-framebuffer.c b/cogl/cogl-framebuffer.c index 351ed19cb..2ba034f99 100644 --- a/cogl/cogl-framebuffer.c +++ b/cogl/cogl-framebuffer.c @@ -1120,6 +1120,55 @@ _cogl_free_framebuffer_stack (GSList *stack) g_slist_free (stack); } +static void +notify_buffers_changed (CoglFramebuffer *old_draw_buffer, + CoglFramebuffer *new_draw_buffer, + CoglFramebuffer *old_read_buffer, + CoglFramebuffer *new_read_buffer) +{ + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + ctx->dirty_bound_framebuffer = 1; + ctx->dirty_gl_viewport = 1; + + /* We've effectively just switched the current modelview and + * projection matrix stacks and clip state so we need to dirty + * them to ensure they get flushed for the next batch of geometry + * we flush */ + if (new_draw_buffer) + { + _cogl_matrix_stack_dirty (new_draw_buffer->modelview_stack); + _cogl_matrix_stack_dirty (new_draw_buffer->projection_stack); + } + + _cogl_clip_stack_dirty (); + + /* If the two draw framebuffers have a different color mask then we + need to ensure the logic ops are reflushed the next time + something is drawn */ + if (old_draw_buffer && new_draw_buffer && + cogl_framebuffer_get_color_mask (old_draw_buffer) != + cogl_framebuffer_get_color_mask (new_draw_buffer)) + { + ctx->current_pipeline_changes_since_flush |= + COGL_PIPELINE_STATE_LOGIC_OPS; + ctx->current_pipeline_age--; + } + + /* XXX: + * To support the deprecated cogl_set_draw_buffer API we keep track + * of the last onscreen framebuffer that was set so that it can + * be restored if the COGL_WINDOW_BUFFER enum is used. */ + if (new_draw_buffer && + new_draw_buffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN) + { + cogl_object_ref (new_draw_buffer); + if (ctx->window_buffer) + cogl_object_unref (ctx->window_buffer); + ctx->window_buffer = new_draw_buffer; + } +} + /* Set the current framebuffer without checking if it's already the * current framebuffer. This is used by cogl_pop_framebuffer while * the top of the stack is currently not up to date. */ @@ -1128,7 +1177,6 @@ _cogl_set_framebuffers_real (CoglFramebuffer *draw_buffer, CoglFramebuffer *read_buffer) { CoglFramebufferStackEntry *entry; - GSList *l; _COGL_GET_CONTEXT (ctx, NO_RETVAL); @@ -1138,8 +1186,10 @@ _cogl_set_framebuffers_real (CoglFramebuffer *draw_buffer, entry = ctx->framebuffer_stack->data; - ctx->dirty_bound_framebuffer = 1; - ctx->dirty_gl_viewport = 1; + notify_buffers_changed (entry->draw_buffer, + draw_buffer, + entry->read_buffer, + read_buffer); if (draw_buffer) cogl_object_ref (draw_buffer); @@ -1153,31 +1203,6 @@ _cogl_set_framebuffers_real (CoglFramebuffer *draw_buffer, entry->draw_buffer = draw_buffer; entry->read_buffer = read_buffer; - - /* We've effectively just switched the current modelview and - * projection matrix stacks and clip state so we need to dirty - * them to ensure they get flushed for the next batch of geometry - * we flush */ - if (draw_buffer) - { - _cogl_matrix_stack_dirty (draw_buffer->modelview_stack); - _cogl_matrix_stack_dirty (draw_buffer->projection_stack); - } - - _cogl_clip_stack_dirty (); - - /* XXX: - * To support the deprecated cogl_set_draw_buffer API we keep track - * of the last onscreen framebuffer that was pushed so that it can - * be restored if the COGL_WINDOW_BUFFER enum is used. */ - ctx->window_buffer = NULL; - for (l = ctx->framebuffer_stack; l; l = l->next) - { - entry = l->data; - if (entry->draw_buffer && - entry->draw_buffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN) - ctx->window_buffer = entry->draw_buffer; - } } static void @@ -1309,7 +1334,6 @@ cogl_pop_framebuffer (void) { CoglFramebufferStackEntry *to_pop; CoglFramebufferStackEntry *to_restore; - gboolean changed = FALSE; _COGL_GET_CONTEXT (ctx, NO_RETVAL); @@ -1329,7 +1353,10 @@ cogl_pop_framebuffer (void) _cogl_framebuffer_flush_journal (to_pop->draw_buffer); _cogl_framebuffer_flush_journal (to_pop->read_buffer); - changed = TRUE; + notify_buffers_changed (to_pop->draw_buffer, + to_restore->draw_buffer, + to_pop->read_buffer, + to_restore->read_buffer); } cogl_object_unref (to_pop->draw_buffer); @@ -1339,13 +1366,6 @@ cogl_pop_framebuffer (void) ctx->framebuffer_stack = g_slist_delete_link (ctx->framebuffer_stack, ctx->framebuffer_stack); - - /* If the framebuffer has changed as a result of popping the top - * then re-assert the current buffer so as to dirty state as - * necessary. */ - if (changed) - _cogl_set_framebuffers_real (to_restore->draw_buffer, - to_restore->read_buffer); } /* XXX: deprecated API */