예제 #1
0
/* A redraw clip represents (in stage coordinates) the bounding box of
 * something that needs to be redraw. Typically they are added to the
 * StageWindow as a result of clutter_actor_queue_clipped_redraw() by
 * actors such as ClutterGLXTexturePixmap. All redraw clips are
 * discarded after the next paint.
 *
 * A NULL stage_clip means the whole stage needs to be redrawn.
 *
 * What we do with this information:
 * - we keep track of the bounding box for all redraw clips
 * - when we come to redraw; if the bounding box is smaller than the
 *   stage we scissor the redraw to that box and use
 *   GLX_MESA_copy_sub_buffer to present the redraw to the front
 *   buffer. Some heuristics are used to decide when a clipped redraw
 *   should be promoted into a full stage redraw.
 *
 * Currently we simply check that the bounding box height is < 300
 * pixels.
 *
 * XXX: we don't have any empirical data telling us what a sensible
 * thresholds is!
 *
 * TODO - we should use different heuristics depending on whether the
 * framebuffer is on screen and not redirected by a compositor VS
 * offscreen (either due to compositor redirection or because we are
 * rendering to a CoglOffscreen framebuffer)
 *
 * When not redirected glXCopySubBuffer (on intel hardware at least)
 * will block the GPU until the vertical trace is at the optimal point
 * so the copy can be done without tearing. In this case we don't want
 * to copy tall regions because they increase the average time spent
 * blocking the GPU.
 *
 * When rendering offscreen (CoglOffscreen or redirected by
 * compositor) then no extra synchronization is needed before the copy
 * can start.
 *
 * In all cases we need to consider that glXCopySubBuffer implies a
 * blit which may be avoided by promoting to a full stage redraw if:
 * - the framebuffer is redirected offscreen or a CoglOffscreen.
 * - the framebuffer is onscreen and fullscreen.
 * By promoting to a full stage redraw we trade off the cost involved
 * in rasterizing the extra pixels vs avoiding to use a blit to
 * present the back buffer.
 *
 */
static void
clutter_stage_glx_add_redraw_clip (ClutterStageWindow *stage_window,
                                   ClutterGeometry    *stage_clip)
{
  ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (stage_window);

  /* If we are already forced to do a full stage redraw then bail early */
  if (clutter_stage_glx_ignoring_redraw_clips (stage_window))
    return;

  /* A NULL stage clip means a full stage redraw has been queued and
   * we keep track of this by setting a degenerate
   * stage_glx->bounding_redraw_clip */
  if (stage_clip == NULL)
    {
      stage_glx->bounding_redraw_clip.width = 0;
      return;
    }

  /* Do nothing on an empty clip to avoid confusing with out magic-flag
   * degenerate clip
   */
  if (stage_clip->width == 0 || stage_clip->height == 0)
    return;

  if (!stage_glx->initialized_redraw_clip)
    {
      stage_glx->bounding_redraw_clip.x = stage_clip->x;
      stage_glx->bounding_redraw_clip.y = stage_clip->y;
      stage_glx->bounding_redraw_clip.width = stage_clip->width;
      stage_glx->bounding_redraw_clip.height = stage_clip->height;
    }
  else if (stage_glx->bounding_redraw_clip.width > 0)
    {
      _clutter_geometry_union (&stage_glx->bounding_redraw_clip, stage_clip,
                               &stage_glx->bounding_redraw_clip);
    }

#if 0
  redraw_area = (stage_glx->bounding_redraw_clip.width *
                 stage_glx->bounding_redraw_clip.height);
  stage_area = stage_x11->xwin_width * stage_x11->xwin_height;

  /* Redrawing and blitting >70% of the stage is assumed to be more
   * expensive than redrawing the additional 30% to avoid the blit.
   *
   * FIXME: This threshold was plucked out of thin air!
   */
  if (redraw_area > (stage_area * 0.7f))
    {
      g_print ("DEBUG: clipped redraw too big, forcing full redraw\n");
      /* Set a degenerate clip to force a full redraw */
      stage_glx->bounding_redraw_clip.width = 0;
    }
#endif

  stage_glx->initialized_redraw_clip = TRUE;
}
예제 #2
0
/* A redraw clip represents (in stage coordinates) the bounding box of
 * something that needs to be redraw. Typically they are added to the
 * StageWindow as a result of clutter_actor_queue_clipped_redraw() by
 * actors such as ClutterGLXTexturePixmap. All redraw clips are
 * discarded after the next paint.
 *
 * A NULL stage_clip means the whole stage needs to be redrawn.
 *
 * What we do with this information:
 * - we keep track of the bounding box for all redraw clips
 * - when we come to redraw; if the bounding box is smaller than the
 *   stage we scissor the redraw to that box and use
 *   GLX_MESA_copy_sub_buffer to present the redraw to the front
 *   buffer.
 *
 * XXX - In theory, we should have some sort of heuristics to promote
 * a clipped redraw to a full screen redraw; in reality, it turns out
 * that promotion is fairly expensive. See the Clutter bug described
 * at: http://bugzilla.clutter-project.org/show_bug.cgi?id=2136 .
 *
 * TODO - we should use different heuristics depending on whether the
 * framebuffer is on screen and not redirected by a compositor VS
 * offscreen (either due to compositor redirection or because we are
 * rendering to a CoglOffscreen framebuffer)
 *
 * When not redirected glXCopySubBuffer (on intel hardware at least)
 * will block the GPU until the vertical trace is at the optimal point
 * so the copy can be done without tearing. In this case we don't want
 * to copy tall regions because they increase the average time spent
 * blocking the GPU.
 *
 * When rendering offscreen (CoglOffscreen or redirected by
 * compositor) then no extra synchronization is needed before the copy
 * can start.
 *
 * In all cases we need to consider that glXCopySubBuffer implies a
 * blit which may be avoided by promoting to a full stage redraw if:
 * - the framebuffer is redirected offscreen or a CoglOffscreen.
 * - the framebuffer is onscreen and fullscreen.
 * By promoting to a full stage redraw we trade off the cost involved
 * in rasterizing the extra pixels vs avoiding to use a blit to
 * present the back buffer.
 */
static void
clutter_stage_glx_add_redraw_clip (ClutterStageWindow *stage_window,
                                   ClutterGeometry    *stage_clip)
{
  ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (stage_window);

  /* If we are already forced to do a full stage redraw then bail early */
  if (clutter_stage_glx_ignoring_redraw_clips (stage_window))
    return;

  /* A NULL stage clip means a full stage redraw has been queued and
   * we keep track of this by setting a zero width
   * stage_glx->bounding_redraw_clip */
  if (stage_clip == NULL)
    {
      stage_glx->bounding_redraw_clip.width = 0;
      stage_glx->initialized_redraw_clip = TRUE;
      return;
    }

  /* Ignore requests to add degenerate/empty clip rectangles */
  if (stage_clip->width == 0 || stage_clip->height == 0)
    return;

  if (!stage_glx->initialized_redraw_clip)
    {
      stage_glx->bounding_redraw_clip.x = stage_clip->x;
      stage_glx->bounding_redraw_clip.y = stage_clip->y;
      stage_glx->bounding_redraw_clip.width = stage_clip->width;
      stage_glx->bounding_redraw_clip.height = stage_clip->height;
    }
  else if (stage_glx->bounding_redraw_clip.width > 0)
    {
      clutter_geometry_union (&stage_glx->bounding_redraw_clip,
                              stage_clip,
			      &stage_glx->bounding_redraw_clip);
    }

#if 0
  redraw_area = (stage_glx->bounding_redraw_clip.width *
                 stage_glx->bounding_redraw_clip.height);
  stage_area = stage_x11->xwin_width * stage_x11->xwin_height;

  /* Redrawing and blitting >70% of the stage is assumed to be more
   * expensive than redrawing the additional 30% to avoid the blit.
   *
   * FIXME: This threshold was plucked out of thin air!
   *
   * The threshold has been disabled after verifying that it indeed
   * made redraws more expensive than intended; see bug reference:
   *
   * http://bugzilla.clutter-project.org/show_bug.cgi?id=2136
   */
  if (redraw_area > (stage_area * 0.7f))
    {
      g_print ("DEBUG: clipped redraw too big, forcing full redraw\n");
      /* Set a zero width clip to force a full redraw */
      stage_glx->bounding_redraw_clip.width = 0;
    }
#endif

  stage_glx->initialized_redraw_clip = TRUE;
}