diff --git a/cogl/cogl-clip-stack.c b/cogl/cogl-clip-stack.c index ad23409bf..7ecf83fd4 100644 --- a/cogl/cogl-clip-stack.c +++ b/cogl/cogl-clip-stack.c @@ -447,10 +447,14 @@ _cogl_clip_stack_get_bounds (CoglClipStack *stack, { /* Get the intersection of the current scissor and the bounding box of this clip */ - *scissor_x0 = MAX (*scissor_x0, entry->bounds_x0); - *scissor_y0 = MAX (*scissor_y0, entry->bounds_y0); - *scissor_x1 = MIN (*scissor_x1, entry->bounds_x1); - *scissor_y1 = MIN (*scissor_y1, entry->bounds_y1); + _cogl_util_scissor_intersect (entry->bounds_x0, + entry->bounds_y0, + entry->bounds_x1, + entry->bounds_y1, + scissor_x0, + scissor_y0, + scissor_x1, + scissor_y1); } } diff --git a/cogl/cogl-context-private.h b/cogl/cogl-context-private.h index 788cf3d3c..06acc3c08 100644 --- a/cogl/cogl-context-private.h +++ b/cogl/cogl-context-private.h @@ -83,6 +83,9 @@ struct _CoglContext CoglFeatureFlags feature_flags; /* legacy/deprecated feature flags */ CoglPrivateFeatureFlags private_feature_flags; + CoglBool needs_viewport_scissor_workaround; + CoglFramebuffer *viewport_scissor_workaround_framebuffer; + CoglPipeline *default_pipeline; CoglPipelineLayer *default_layer_0; CoglPipelineLayer *default_layer_n; diff --git a/cogl/cogl-context.c b/cogl/cogl-context.c index 8bf443048..207d68c69 100644 --- a/cogl/cogl-context.c +++ b/cogl/cogl-context.c @@ -52,6 +52,7 @@ #include "cogl-error-private.h" #include +#include #ifdef HAVE_COGL_GL #include "cogl-pipeline-fragend-arbfp-private.h" @@ -240,6 +241,22 @@ cogl_context_new (CoglDisplay *display, /* Initialise the driver specific state */ _cogl_init_feature_overrides (context); + /* XXX: ONGOING BUG: Intel viewport scissor + * + * Intel gen6 drivers don't currently correctly handle offset + * viewports, since primitives aren't clipped within the bounds of + * the viewport. To workaround this we push our own clip for the + * viewport that will use scissoring to ensure we clip as expected. + * + * TODO: file a bug upstream! + */ + if (context->gpu.driver_package == COGL_GPU_INFO_DRIVER_PACKAGE_MESA && + context->gpu.architecture == COGL_GPU_INFO_ARCHITECTURE_SANDYBRIDGE && + !getenv ("COGL_DISABLE_INTEL_VIEWPORT_SCISSORT_WORKAROUND")) + context->needs_viewport_scissor_workaround = TRUE; + else + context->needs_viewport_scissor_workaround = FALSE; + context->sampler_cache = _cogl_sampler_cache_new (context); _cogl_pipeline_init_default_pipeline (); diff --git a/cogl/cogl-framebuffer-private.h b/cogl/cogl-framebuffer-private.h index d2c2c36e1..8db49eccc 100644 --- a/cogl/cogl-framebuffer-private.h +++ b/cogl/cogl-framebuffer-private.h @@ -127,6 +127,8 @@ struct _CoglFramebuffer float viewport_y; float viewport_width; float viewport_height; + int viewport_age; + int viewport_age_for_scissor_workaround; CoglClipState clip_state; diff --git a/cogl/cogl-framebuffer.c b/cogl/cogl-framebuffer.c index fd646b10c..f7f29836e 100644 --- a/cogl/cogl-framebuffer.c +++ b/cogl/cogl-framebuffer.c @@ -112,6 +112,8 @@ _cogl_framebuffer_init (CoglFramebuffer *framebuffer, framebuffer->viewport_y = 0; framebuffer->viewport_width = width; framebuffer->viewport_height = height; + framebuffer->viewport_age = 0; + framebuffer->viewport_age_for_scissor_workaround = -1; framebuffer->dither_enabled = TRUE; framebuffer->modelview_stack = _cogl_matrix_stack_new (); @@ -179,6 +181,9 @@ _cogl_framebuffer_free (CoglFramebuffer *framebuffer) cogl_object_unref (framebuffer->journal); + if (ctx->viewport_scissor_workaround_framebuffer == framebuffer) + ctx->viewport_scissor_workaround_framebuffer = NULL; + ctx->framebuffers = g_list_remove (ctx->framebuffers, framebuffer); if (ctx->current_draw_buffer == framebuffer) @@ -458,6 +463,7 @@ cogl_framebuffer_set_viewport (CoglFramebuffer *framebuffer, framebuffer->viewport_y = y; framebuffer->viewport_width = width; framebuffer->viewport_height = height; + framebuffer->viewport_age++; if (framebuffer->context->current_draw_buffer == framebuffer) framebuffer->context->current_draw_buffer_changes |= diff --git a/cogl/cogl-util.h b/cogl/cogl-util.h index 4fb42274c..1f3d26638 100644 --- a/cogl/cogl-util.h +++ b/cogl/cogl-util.h @@ -278,4 +278,20 @@ _cogl_util_memmem (const void *haystack, size_t needle_len); #endif +static inline void +_cogl_util_scissor_intersect (int rect_x0, + int rect_y0, + int rect_x1, + int rect_y1, + int *scissor_x0, + int *scissor_y0, + int *scissor_x1, + int *scissor_y1) +{ + *scissor_x0 = MAX (*scissor_x0, rect_x0); + *scissor_y0 = MAX (*scissor_y0, rect_y0); + *scissor_x1 = MIN (*scissor_x1, rect_x1); + *scissor_y1 = MIN (*scissor_y1, rect_y1); +} + #endif /* __COGL_UTIL_H */ diff --git a/cogl/driver/gl/cogl-clip-stack-gl.c b/cogl/driver/gl/cogl-clip-stack-gl.c index db9fbd440..c81699428 100644 --- a/cogl/driver/gl/cogl-clip-stack-gl.c +++ b/cogl/driver/gl/cogl-clip-stack-gl.c @@ -467,7 +467,12 @@ _cogl_clip_stack_gl_flush (CoglClipStack *stack, anything */ if (ctx->current_clip_stack_valid) { - if (ctx->current_clip_stack == stack) + if (ctx->current_clip_stack == stack && + (ctx->needs_viewport_scissor_workaround == FALSE || + (framebuffer->viewport_age == + framebuffer->viewport_age_for_scissor_workaround && + ctx->viewport_scissor_workaround_framebuffer == + framebuffer))) return; _cogl_clip_stack_unref (ctx->current_clip_stack); @@ -483,8 +488,11 @@ _cogl_clip_stack_gl_flush (CoglClipStack *stack, disable_clip_planes (ctx); GE( ctx, glDisable (GL_STENCIL_TEST) ); - /* If the stack is empty then there's nothing else to do */ - if (stack == NULL) + /* If the stack is empty then there's nothing else to do + * + * See comment below about ctx->needs_viewport_scissor_workaround + */ + if (stack == NULL && !ctx->needs_viewport_scissor_workaround) { COGL_NOTE (CLIPPING, "Flushed empty clip stack"); @@ -501,6 +509,31 @@ _cogl_clip_stack_gl_flush (CoglClipStack *stack, &scissor_x0, &scissor_y0, &scissor_x1, &scissor_y1); + /* XXX: ONGOING BUG: Intel viewport scissor + * + * Intel gen6 drivers don't correctly handle offset viewports, since + * primitives aren't clipped within the bounds of the viewport. To + * workaround this we push our own clip for the viewport that will + * use scissoring to ensure we clip as expected. + * + * TODO: file a bug upstream! + */ + if (ctx->needs_viewport_scissor_workaround) + { + _cogl_util_scissor_intersect (framebuffer->viewport_x, + framebuffer->viewport_y, + framebuffer->viewport_x + + framebuffer->viewport_width, + framebuffer->viewport_y + + framebuffer->viewport_height, + &scissor_x0, &scissor_y0, + &scissor_x1, &scissor_y1); + framebuffer->viewport_age_for_scissor_workaround = + framebuffer->viewport_age; + ctx->viewport_scissor_workaround_framebuffer = + framebuffer; + } + /* Enable scissoring as soon as possible */ if (scissor_x0 >= scissor_x1 || scissor_y0 >= scissor_y1) scissor_x0 = scissor_y0 = scissor_x1 = scissor_y1 = scissor_y_start = 0;