framebuffer: deal with winding state like other state

We should not be deciding whether we need to really update the GL face
winding state at the point where a new framebuffer has been pushed, we
should be waiting until we have really been asked to flush some
framebuffer state otherwise we may do redundant work if multiple
framebuffers are pushed/popped before something is really drawn.

This integrates the face winding state tracking with the design we have
for handling most of the other framebuffer state so we benefit from the
optimizations for minimizing the cost of _cogl_framebuffer_flush_state()

Reviewed-by: Neil Roberts <neil@linux.intel.com>
This commit is contained in:
Robert Bragg 2011-11-21 20:48:23 +00:00
parent cf4b228fc0
commit 2112af0bc5
2 changed files with 67 additions and 35 deletions

View File

@ -65,25 +65,27 @@ typedef enum
*/
typedef enum _CoglFramebufferStateIndex
{
COGL_FRAMEBUFFER_STATE_INDEX_BIND = 0,
COGL_FRAMEBUFFER_STATE_INDEX_VIEWPORT = 1,
COGL_FRAMEBUFFER_STATE_INDEX_CLIP = 2,
COGL_FRAMEBUFFER_STATE_INDEX_DITHER = 3,
COGL_FRAMEBUFFER_STATE_INDEX_MODELVIEW = 4,
COGL_FRAMEBUFFER_STATE_INDEX_PROJECTION = 5,
COGL_FRAMEBUFFER_STATE_INDEX_COLOR_MASK = 6,
COGL_FRAMEBUFFER_STATE_INDEX_MAX = 7
COGL_FRAMEBUFFER_STATE_INDEX_BIND = 0,
COGL_FRAMEBUFFER_STATE_INDEX_VIEWPORT = 1,
COGL_FRAMEBUFFER_STATE_INDEX_CLIP = 2,
COGL_FRAMEBUFFER_STATE_INDEX_DITHER = 3,
COGL_FRAMEBUFFER_STATE_INDEX_MODELVIEW = 4,
COGL_FRAMEBUFFER_STATE_INDEX_PROJECTION = 5,
COGL_FRAMEBUFFER_STATE_INDEX_COLOR_MASK = 6,
COGL_FRAMEBUFFER_STATE_INDEX_FRONT_FACE_WINDING = 7,
COGL_FRAMEBUFFER_STATE_INDEX_MAX = 8
} CoglFramebufferStateIndex;
typedef enum _CoglFramebufferState
{
COGL_FRAMEBUFFER_STATE_BIND = 1<<0,
COGL_FRAMEBUFFER_STATE_VIEWPORT = 1<<1,
COGL_FRAMEBUFFER_STATE_CLIP = 1<<2,
COGL_FRAMEBUFFER_STATE_DITHER = 1<<3,
COGL_FRAMEBUFFER_STATE_MODELVIEW = 1<<4,
COGL_FRAMEBUFFER_STATE_PROJECTION = 1<<5,
COGL_FRAMEBUFFER_STATE_COLOR_MASK = 1<<6
COGL_FRAMEBUFFER_STATE_BIND = 1<<0,
COGL_FRAMEBUFFER_STATE_VIEWPORT = 1<<1,
COGL_FRAMEBUFFER_STATE_CLIP = 1<<2,
COGL_FRAMEBUFFER_STATE_DITHER = 1<<3,
COGL_FRAMEBUFFER_STATE_MODELVIEW = 1<<4,
COGL_FRAMEBUFFER_STATE_PROJECTION = 1<<5,
COGL_FRAMEBUFFER_STATE_COLOR_MASK = 1<<6,
COGL_FRAMEBUFFER_STATE_FRONT_FACE_WINDING = 1<<7
} CoglFramebufferState;
#define COGL_FRAMEBUFFER_STATE_ALL ((1<<COGL_FRAMEBUFFER_STATE_INDEX_MAX) - 1)

View File

@ -1104,25 +1104,6 @@ notify_buffers_changed (CoglFramebuffer *old_draw_buffer,
CoglFramebuffer *old_read_buffer,
CoglFramebuffer *new_read_buffer)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (old_draw_buffer && new_draw_buffer)
{
/* If we're switching from onscreen to offscreen and the last
flush pipeline is using backface culling then we also need to
reflush the cull face state because the winding order of the
front face is flipped for offscreen buffers */
if (old_draw_buffer->type != new_draw_buffer->type &&
ctx->current_pipeline &&
cogl_pipeline_get_cull_face_mode (ctx->current_pipeline) !=
COGL_PIPELINE_CULL_FACE_MODE_NONE)
{
ctx->current_pipeline_changes_since_flush |=
COGL_PIPELINE_STATE_CULL_FACE;
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. A
@ -1132,7 +1113,7 @@ notify_buffers_changed (CoglFramebuffer *old_draw_buffer,
* _cogl_onscreen_free as a kind of a cheap weak reference */
if (new_draw_buffer &&
new_draw_buffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN)
ctx->window_buffer = new_draw_buffer;
new_draw_buffer->context->window_buffer = new_draw_buffer;
}
/* Set the current framebuffer without checking if it's already the
@ -1428,6 +1409,16 @@ _cogl_framebuffer_compare_color_mask_state (CoglFramebuffer *a,
return 0;
}
static unsigned long
_cogl_framebuffer_compare_front_face_winding_state (CoglFramebuffer *a,
CoglFramebuffer *b)
{
if (a->type != b->type)
return COGL_FRAMEBUFFER_STATE_FRONT_FACE_WINDING;
else
return 0;
}
static unsigned long
_cogl_framebuffer_compare (CoglFramebuffer *a,
CoglFramebuffer *b,
@ -1472,6 +1463,10 @@ _cogl_framebuffer_compare (CoglFramebuffer *a,
differences |=
_cogl_framebuffer_compare_color_mask_state (a, b);
break;
case COGL_FRAMEBUFFER_STATE_INDEX_FRONT_FACE_WINDING:
differences |=
_cogl_framebuffer_compare_front_face_winding_state (a, b);
break;
default:
g_warn_if_reached ();
}
@ -1565,6 +1560,38 @@ _cogl_framebuffer_flush_color_mask_state (CoglFramebuffer *framebuffer)
context->current_pipeline_age--;
}
static void
_cogl_framebuffer_flush_front_face_winding_state (CoglFramebuffer *framebuffer)
{
CoglContext *context = framebuffer->context;
CoglPipelineCullFaceMode mode;
/* NB: The face winding state is actually owned by the current
* CoglPipeline.
*
* If we don't have a current pipeline then we can just assume that
* when we later do flush a pipeline we will check the current
* framebuffer to know how to setup the winding */
if (!context->current_pipeline)
return;
mode = cogl_pipeline_get_cull_face_mode (context->current_pipeline);
/* If the current CoglPipeline has a culling mode that doesn't care
* about the winding we can avoid forcing an update of the state and
* bail out. */
if (mode == COGL_PIPELINE_CULL_FACE_MODE_NONE ||
mode == COGL_PIPELINE_CULL_FACE_MODE_BOTH)
return;
/* Since the winding state is really owned by the current pipeline
* the way we "flush" an updated winding is to dirty the pipeline
* state... */
context->current_pipeline_changes_since_flush |=
COGL_PIPELINE_STATE_CULL_FACE;
context->current_pipeline_age--;
}
void
_cogl_framebuffer_flush_state (CoglFramebuffer *draw_buffer,
CoglFramebuffer *read_buffer,
@ -1668,6 +1695,9 @@ _cogl_framebuffer_flush_state (CoglFramebuffer *draw_buffer,
case COGL_FRAMEBUFFER_STATE_INDEX_COLOR_MASK:
_cogl_framebuffer_flush_color_mask_state (draw_buffer);
break;
case COGL_FRAMEBUFFER_STATE_INDEX_FRONT_FACE_WINDING:
_cogl_framebuffer_flush_front_face_winding_state (draw_buffer);
break;
default:
g_warn_if_reached ();
}