clip-stack: workaround intel gen6 viewport clip bug

The Intel Mesa gen6 driver doesn't currently handle scissoring offset
viewports correctly, so this implements a workaround to intersect the
current viewport bounds with the scissor rectangle.

(cherry picked from commit afc5daab85e5faca99d6d6866658cb82c3954830)
This commit is contained in:
Robert Bragg 2012-10-02 11:44:00 +01:00
parent 362db1c445
commit 6cfc93f26f
7 changed files with 88 additions and 7 deletions

View File

@ -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);
}
}

View File

@ -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;

View File

@ -52,6 +52,7 @@
#include "cogl-error-private.h"
#include <string.h>
#include <stdlib.h>
#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 ();

View File

@ -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;

View File

@ -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 |=

View File

@ -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 */

View File

@ -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;