Ejemplo n.º 1
0
/**
 * Update the hardware state for drawing into a window or framebuffer object.
 *
 * Called by glDrawBuffer, glBindFramebufferEXT, MakeCurrent, and other
 * places within the driver.
 *
 * Basically, this needs to be called any time the current framebuffer
 * changes, the renderbuffers change, or we need to draw into different
 * color buffers.
 */
void
intel_draw_buffer(struct gl_context * ctx, struct gl_framebuffer *fb)
{
   struct intel_context *intel = intel_context(ctx);
   struct intel_region *colorRegions[MAX_DRAW_BUFFERS], *depthRegion = NULL;
   struct intel_renderbuffer *irbDepth = NULL, *irbStencil = NULL;

   if (!fb) {
      /* this can happen during the initial context initialization */
      return;
   }

   /* Do this here, not core Mesa, since this function is called from
    * many places within the driver.
    */
   if (ctx->NewState & _NEW_BUFFERS) {
      /* this updates the DrawBuffer->_NumColorDrawBuffers fields, etc */
      _mesa_update_framebuffer(ctx);
      /* this updates the DrawBuffer's Width/Height if it's a FBO */
      _mesa_update_draw_buffer_bounds(ctx);
   }

   if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
      /* this may occur when we're called by glBindFrameBuffer() during
       * the process of someone setting up renderbuffers, etc.
       */
      /*_mesa_debug(ctx, "DrawBuffer: incomplete user FBO\n");*/
      return;
   }

   /* How many color buffers are we drawing into?
    *
    * If there are zero buffers or the buffer is too big, don't configure any
    * regions for hardware drawing.  We'll fallback to software below.  Not
    * having regions set makes some of the software fallback paths faster.
    */
   if ((fb->Width > ctx->Const.MaxRenderbufferSize)
       || (fb->Height > ctx->Const.MaxRenderbufferSize)
       || (fb->_NumColorDrawBuffers == 0)) {
      /* writing to 0  */
      colorRegions[0] = NULL;
   }
   else if (fb->_NumColorDrawBuffers > 1) {
       int i;
       struct intel_renderbuffer *irb;

       for (i = 0; i < fb->_NumColorDrawBuffers; i++) {
           irb = intel_renderbuffer(fb->_ColorDrawBuffers[i]);
           colorRegions[i] = irb ? irb->region : NULL;
       }
   }
   else {
      /* Get the intel_renderbuffer for the single colorbuffer we're drawing
       * into.
       */
      if (fb->Name == 0) {
	 /* drawing to window system buffer */
	 if (fb->_ColorDrawBufferIndexes[0] == BUFFER_FRONT_LEFT)
	    colorRegions[0] = intel_get_rb_region(fb, BUFFER_FRONT_LEFT);
	 else
	    colorRegions[0] = intel_get_rb_region(fb, BUFFER_BACK_LEFT);
      }
      else {
	 /* drawing to user-created FBO */
	 struct intel_renderbuffer *irb;
	 irb = intel_renderbuffer(fb->_ColorDrawBuffers[0]);
	 colorRegions[0] = (irb && irb->region) ? irb->region : NULL;
      }
   }

   if (!colorRegions[0]) {
      FALLBACK(intel, INTEL_FALLBACK_DRAW_BUFFER, GL_TRUE);
   }
   else {
      FALLBACK(intel, INTEL_FALLBACK_DRAW_BUFFER, GL_FALSE);
   }

   /***
    *** Get depth buffer region and check if we need a software fallback.
    *** Note that the depth buffer is usually a DEPTH_STENCIL buffer.
    ***/
   if (fb->_DepthBuffer && fb->_DepthBuffer->Wrapped) {
      irbDepth = intel_renderbuffer(fb->_DepthBuffer->Wrapped);
      if (irbDepth && irbDepth->region) {
         FALLBACK(intel, INTEL_FALLBACK_DEPTH_BUFFER, GL_FALSE);
         depthRegion = irbDepth->region;
      }
      else {
         FALLBACK(intel, INTEL_FALLBACK_DEPTH_BUFFER, GL_TRUE);
         depthRegion = NULL;
      }
   }
   else {
      /* not using depth buffer */
      FALLBACK(intel, INTEL_FALLBACK_DEPTH_BUFFER, GL_FALSE);
      depthRegion = NULL;
   }

   /***
    *** Stencil buffer
    *** This can only be hardware accelerated if we're using a
    *** combined DEPTH_STENCIL buffer.
    ***/
   if (fb->_StencilBuffer && fb->_StencilBuffer->Wrapped) {
      irbStencil = intel_renderbuffer(fb->_StencilBuffer->Wrapped);
      if (irbStencil && irbStencil->region) {
         ASSERT(irbStencil->Base.Format == MESA_FORMAT_S8_Z24);
         FALLBACK(intel, INTEL_FALLBACK_STENCIL_BUFFER, GL_FALSE);
      }
      else {
         FALLBACK(intel, INTEL_FALLBACK_STENCIL_BUFFER, GL_TRUE);
      }
   }
   else {
      /* XXX FBO: instead of FALSE, pass ctx->Stencil._Enabled ??? */
      FALLBACK(intel, INTEL_FALLBACK_STENCIL_BUFFER, GL_FALSE);
   }

   /* If we have a (packed) stencil buffer attached but no depth buffer,
    * we still need to set up the shared depth/stencil state so we can use it.
    */
   if (depthRegion == NULL && irbStencil && irbStencil->region)
      depthRegion = irbStencil->region;

   /*
    * Update depth and stencil test state
    */
   if (ctx->Driver.Enable) {
      ctx->Driver.Enable(ctx, GL_DEPTH_TEST,
                         (ctx->Depth.Test && fb->Visual.depthBits > 0));
      ctx->Driver.Enable(ctx, GL_STENCIL_TEST,
                         (ctx->Stencil.Enabled && fb->Visual.stencilBits > 0));
   }
   else {
      /* Mesa's Stencil._Enabled field is updated when
       * _NEW_BUFFERS | _NEW_STENCIL, but i965 code assumes that the value
       * only changes with _NEW_STENCIL (which seems sensible).  So flag it
       * here since this is the _NEW_BUFFERS path.
       */
      intel->NewGLState |= (_NEW_DEPTH | _NEW_STENCIL);
   }

   intel->vtbl.set_draw_region(intel, colorRegions, depthRegion, 
                               fb->_NumColorDrawBuffers);
   intel->NewGLState |= _NEW_BUFFERS;

   /* update viewport since it depends on window size */
#ifdef I915
   intelCalcViewport(ctx);
#else
   intel->NewGLState |= _NEW_VIEWPORT;
#endif
   /* Set state we know depends on drawable parameters:
    */
   if (ctx->Driver.Scissor)
      ctx->Driver.Scissor(ctx, ctx->Scissor.X, ctx->Scissor.Y,
			  ctx->Scissor.Width, ctx->Scissor.Height);
   intel->NewGLState |= _NEW_SCISSOR;

   if (ctx->Driver.DepthRange)
      ctx->Driver.DepthRange(ctx,
			     ctx->Viewport.Near,
			     ctx->Viewport.Far);

   /* Update culling direction which changes depending on the
    * orientation of the buffer:
    */
   if (ctx->Driver.FrontFace)
      ctx->Driver.FrontFace(ctx, ctx->Polygon.FrontFace);
   else
      intel->NewGLState |= _NEW_POLYGON;
}
Ejemplo n.º 2
0
/**
 * Copy the back color buffer to the front color buffer. 
 * Used for SwapBuffers().
 */
void intelCopyBuffer( const __DRIdrawablePrivate *dPriv ) 
{
   GET_CURRENT_CONTEXT(ctx);
   struct intel_context *intel;

   DBG("%s\n", __FUNCTION__);

   assert(dPriv);

   /* We need a rendering context in order to issue the blit cmd.
    * Use the current context.
    * XXX need to fix this someday.
    */
   if (!ctx) {
      _mesa_problem(NULL, "No current context in intelCopyBuffer()");
      return;
   }
   intel = (struct intel_context *) ctx;

   bmFinishFence(intel->bm, intel->last_swap_fence);

   /* The LOCK_HARDWARE is required for the cliprects.  Buffer offsets
    * should work regardless.
    */
   LOCK_HARDWARE( intel );

   if (intel->driDrawable &&
       intel->driDrawable->numClipRects)
   {
      const intelScreenPrivate *intelScreen = intel->intelScreen;
      struct gl_framebuffer *fb
         = (struct gl_framebuffer *) dPriv->driverPrivate;
      const struct intel_region *frontRegion
         = intel_get_rb_region(fb, BUFFER_FRONT_LEFT);
      const struct intel_region *backRegion
         = intel_get_rb_region(fb, BUFFER_BACK_LEFT);
      const int nbox = dPriv->numClipRects;
      const drm_clip_rect_t *pbox = dPriv->pClipRects;
      const int pitch = frontRegion->pitch;
      const int cpp = frontRegion->cpp;
      int BR13, CMD;
      int i;

      ASSERT(fb);
      ASSERT(fb->Name == 0); /* Not a user-created FBO */
      ASSERT(frontRegion);
      ASSERT(backRegion);
      ASSERT(frontRegion->pitch == backRegion->pitch);
      ASSERT(frontRegion->cpp == backRegion->cpp);

      if (cpp == 2) {
	 BR13 = (pitch * cpp) | (0xCC << 16) | (1<<24);
	 CMD = XY_SRC_COPY_BLT_CMD;
      } 
      else {
	 BR13 = (pitch * cpp) | (0xCC << 16) | (1<<24) | (1<<25);
	 CMD = (XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA |
		XY_SRC_COPY_BLT_WRITE_RGB);
      }

      for (i = 0 ; i < nbox; i++, pbox++) 
      {
	 if (pbox->x1 > pbox->x2 ||
	     pbox->y1 > pbox->y2 ||
	     pbox->x2 > intelScreen->width ||
	     pbox->y2 > intelScreen->height)
	    continue;
 
	 BEGIN_BATCH(8, INTEL_BATCH_NO_CLIPRECTS);
	 OUT_BATCH( CMD );
	 OUT_BATCH( BR13 );
	 OUT_BATCH( (pbox->y1 << 16) | pbox->x1 );
	 OUT_BATCH( (pbox->y2 << 16) | pbox->x2 );

	 if (intel->sarea->pf_current_page == 0) 
	    OUT_RELOC( frontRegion->buffer, DRM_MM_TT|DRM_MM_WRITE, 0 );
	 else
	    OUT_RELOC( backRegion->buffer, DRM_MM_TT|DRM_MM_WRITE, 0 ); 
	 OUT_BATCH( (pbox->y1 << 16) | pbox->x1 );
	 OUT_BATCH( BR13 & 0xffff );

	 if (intel->sarea->pf_current_page == 0) 
	    OUT_RELOC( backRegion->buffer, DRM_MM_TT|DRM_MM_READ, 0 ); 
	 else
	    OUT_RELOC( frontRegion->buffer, DRM_MM_TT|DRM_MM_READ, 0 );

	 ADVANCE_BATCH();
      }

      intel->last_swap_fence = intel_batchbuffer_flush( intel->batch );
   }
   UNLOCK_HARDWARE( intel );
}
/**
 * Copy the back color buffer to the front color buffer. 
 * Used for SwapBuffers().
 */
void
intelCopyBuffer(const __DRIdrawablePrivate * dPriv,
                const drm_clip_rect_t * rect)
{

   struct intel_context *intel;
   const intelScreenPrivate *intelScreen;

   DBG("%s\n", __FUNCTION__);

   assert(dPriv);

   intel = intelScreenContext(dPriv->driScreenPriv->private);
   if (!intel)
      return;

   intelScreen = intel->intelScreen;

   if (intel->last_swap_fence) {
      dri_fence_wait(intel->last_swap_fence);
      dri_fence_unreference(intel->last_swap_fence);
      intel->last_swap_fence = NULL;
   }
   intel->last_swap_fence = intel->first_swap_fence;
   intel->first_swap_fence = NULL;

   /* The LOCK_HARDWARE is required for the cliprects.  Buffer offsets
    * should work regardless.
    */
   LOCK_HARDWARE(intel);

   if (dPriv && dPriv->numClipRects) {
      struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
      const struct intel_region *frontRegion
	 = intel_get_rb_region(&intel_fb->Base, BUFFER_FRONT_LEFT);
      const struct intel_region *backRegion
	 = intel_get_rb_region(&intel_fb->Base, BUFFER_BACK_LEFT);
      const int nbox = dPriv->numClipRects;
      const drm_clip_rect_t *pbox = dPriv->pClipRects;
      const int cpp = frontRegion->cpp;
      int src_pitch = backRegion->pitch * cpp;
      int dst_pitch = frontRegion->pitch * cpp;
      int BR13, CMD;
      int i;

      ASSERT(intel_fb);
      ASSERT(intel_fb->Base.Name == 0);    /* Not a user-created FBO */
      ASSERT(frontRegion);
      ASSERT(backRegion);
      ASSERT(frontRegion->pitch == backRegion->pitch);
      ASSERT(frontRegion->cpp == backRegion->cpp);

      if (cpp == 2) {
	 BR13 = (0xCC << 16) | (1 << 24);
	 CMD = XY_SRC_COPY_BLT_CMD;
      }
      else {
	 BR13 = (0xCC << 16) | (1 << 24) | (1 << 25);
	 CMD = XY_SRC_COPY_BLT_CMD | XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB;
      }

#ifndef I915
      if (backRegion->tiled) {
	 CMD |= XY_SRC_TILED;
	 src_pitch /= 4;
      }
      if (frontRegion->tiled) {
	 CMD |= XY_DST_TILED;
	 dst_pitch /= 4;
      }
#endif

      for (i = 0; i < nbox; i++, pbox++) {
	 drm_clip_rect_t box;

	 if (pbox->x1 >= pbox->x2 ||
	     pbox->y1 >= pbox->y2 ||
	     pbox->x2 > intelScreen->width || pbox->y2 > intelScreen->height)
	    continue;

	 box = *pbox;

	 if (rect) {
	    if (rect->x1 > box.x1)
	       box.x1 = rect->x1;
	    if (rect->y1 > box.y1)
	       box.y1 = rect->y1;
	    if (rect->x2 < box.x2)
	       box.x2 = rect->x2;
	    if (rect->y2 < box.y2)
	       box.y2 = rect->y2;

	    if (box.x1 >= box.x2 || box.y1 >= box.y2)
	       continue;
	 }

	 assert(box.x1 < box.x2);
	 assert(box.y1 < box.y2);

	 BEGIN_BATCH(8, INTEL_BATCH_NO_CLIPRECTS);
	 OUT_BATCH(CMD);
	 OUT_BATCH(BR13 | dst_pitch);
	 OUT_BATCH((box.y1 << 16) | box.x1);
	 OUT_BATCH((box.y2 << 16) | box.x2);

	 OUT_RELOC(frontRegion->buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE,
		   0);
	 OUT_BATCH((box.y1 << 16) | box.x1);
	 OUT_BATCH(src_pitch);
	 OUT_RELOC(backRegion->buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_READ,
		   0);

	 ADVANCE_BATCH();
      }

      if (intel->first_swap_fence)
	 dri_fence_unreference(intel->first_swap_fence);
      intel_batchbuffer_flush(intel->batch);
      intel->first_swap_fence = intel->batch->last_fence;
      if (intel->first_swap_fence)
	 dri_fence_reference(intel->first_swap_fence);
   }

   UNLOCK_HARDWARE(intel);
}
/**
 * Use blitting to clear the renderbuffers named by 'flags'.
 * Note: we can't use the ctx->DrawBuffer->_ColorDrawBufferMask field
 * since that might include software renderbuffers or renderbuffers
 * which we're clearing with triangles.
 * \param mask  bitmask of BUFFER_BIT_* values indicating buffers to clear
 */
void
intelClearWithBlit(GLcontext * ctx, GLbitfield mask)
{
   struct intel_context *intel = intel_context(ctx);
   struct gl_framebuffer *fb = ctx->DrawBuffer;
   GLuint clear_depth;
   GLbitfield skipBuffers = 0;
   BATCH_LOCALS;

   DBG("%s %x\n", __FUNCTION__, mask);

   /*
    * Compute values for clearing the buffers.
    */
   clear_depth = 0;
   if (mask & BUFFER_BIT_DEPTH) {
      clear_depth = (GLuint) (fb->_DepthMax * ctx->Depth.Clear);
   }
   if (mask & BUFFER_BIT_STENCIL) {
      clear_depth |= (ctx->Stencil.Clear & 0xff) << 24;
   }

   /* If clearing both depth and stencil, skip BUFFER_BIT_STENCIL in
    * the loop below.
    */
   if ((mask & BUFFER_BIT_DEPTH) && (mask & BUFFER_BIT_STENCIL)) {
      skipBuffers = BUFFER_BIT_STENCIL;
   }

   /* XXX Move this flush/lock into the following conditional? */
   intelFlush(&intel->ctx);
   LOCK_HARDWARE(intel);

   if (intel->numClipRects) {
      GLint cx, cy, cw, ch;
      drm_clip_rect_t clear;
      int i;

      /* Get clear bounds after locking */
      cx = fb->_Xmin;
      cy = fb->_Ymin;
      cw = fb->_Xmax - cx;
      ch = fb->_Ymax - cy;

      if (fb->Name == 0) {
         /* clearing a window */

         /* flip top to bottom */
         clear.x1 = cx + intel->drawX;
         clear.y1 = intel->driDrawable->y + intel->driDrawable->h - cy - ch;
         clear.x2 = clear.x1 + cw;
         clear.y2 = clear.y1 + ch;
      }
      else {
         /* clearing FBO */
         assert(intel->numClipRects == 1);
         assert(intel->pClipRects == &intel->fboRect);
         clear.x1 = cx;
         clear.y1 = cy;
         clear.x2 = clear.x1 + cw;
         clear.y2 = clear.y1 + ch;
         /* no change to mask */
      }

      for (i = 0; i < intel->numClipRects; i++) {
         const drm_clip_rect_t *box = &intel->pClipRects[i];
         drm_clip_rect_t b;
         GLuint buf;
         GLuint clearMask = mask;      /* use copy, since we modify it below */
         GLboolean all = (cw == fb->Width && ch == fb->Height);

         if (!all) {
            intel_intersect_cliprects(&b, &clear, box);
         }
         else {
            b = *box;
         }

         if (b.x1 >= b.x2 || b.y1 >= b.y2)
            continue;

         if (0)
            _mesa_printf("clear %d,%d..%d,%d, mask %x\n",
                         b.x1, b.y1, b.x2, b.y2, mask);

         /* Loop over all renderbuffers */
         for (buf = 0; buf < BUFFER_COUNT && clearMask; buf++) {
            const GLbitfield bufBit = 1 << buf;
            if ((clearMask & bufBit) && !(bufBit & skipBuffers)) {
               /* OK, clear this renderbuffer */
               struct intel_region *irb_region =
		  intel_get_rb_region(fb, buf);
               dri_bo *write_buffer =
                  intel_region_buffer(intel->intelScreen, irb_region,
                                      all ? INTEL_WRITE_FULL :
                                      INTEL_WRITE_PART);

               GLuint clearVal;
               GLint pitch, cpp;
               GLuint BR13, CMD;

               ASSERT(irb_region);

               pitch = irb_region->pitch;
               cpp = irb_region->cpp;

               DBG("%s dst:buf(%p)/%d+%d %d,%d sz:%dx%d\n",
                   __FUNCTION__,
                   irb_region->buffer, (pitch * cpp),
                   irb_region->draw_offset,
                   b.x1, b.y1, b.x2 - b.x1, b.y2 - b.y1);

	       BR13 = 0xf0 << 16;
	       CMD = XY_COLOR_BLT_CMD;

               /* Setup the blit command */
               if (cpp == 4) {
                  BR13 |= (1 << 24) | (1 << 25);
                  if (buf == BUFFER_DEPTH || buf == BUFFER_STENCIL) {
                     if (clearMask & BUFFER_BIT_DEPTH)
                        CMD |= XY_BLT_WRITE_RGB;
                     if (clearMask & BUFFER_BIT_STENCIL)
                        CMD |= XY_BLT_WRITE_ALPHA;
                  }
                  else {
                     /* clearing RGBA */
                     CMD |= XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB;
                  }
               }
               else {
                  ASSERT(cpp == 2 || cpp == 0);
                  BR13 |= (1 << 24);
               }

#ifndef I915
	       if (irb_region->tiled) {
		  CMD |= XY_DST_TILED;
		  pitch /= 4;
	       }
#endif
	       BR13 |= (pitch * cpp);

               if (buf == BUFFER_DEPTH || buf == BUFFER_STENCIL) {
                  clearVal = clear_depth;
               }
               else {
                  clearVal = (cpp == 4)
                     ? intel->ClearColor8888 : intel->ClearColor565;
               }
               /*
                  _mesa_debug(ctx, "hardware blit clear buf %d rb id %d\n",
                  buf, irb->Base.Name);
                */
	       intel_wait_flips(intel, INTEL_BATCH_NO_CLIPRECTS);

               assert(b.x1 < b.x2);
               assert(b.y1 < b.y2);

               BEGIN_BATCH(6, INTEL_BATCH_NO_CLIPRECTS);
               OUT_BATCH(CMD);
               OUT_BATCH(BR13);
               OUT_BATCH((b.y1 << 16) | b.x1);
               OUT_BATCH((b.y2 << 16) | b.x2);
               OUT_RELOC(write_buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE,
                         irb_region->draw_offset);
               OUT_BATCH(clearVal);
               ADVANCE_BATCH();
               clearMask &= ~bufBit;    /* turn off bit, for faster loop exit */
            }
         }
      }
      intel_batchbuffer_flush(intel->batch);
   }

   UNLOCK_HARDWARE(intel);
}
Ejemplo n.º 5
0
/**
 * Called by ctx->Driver.Clear.
 */
static void
intelClear(struct gl_context *ctx, GLbitfield mask)
{
   struct intel_context *intel = intel_context(ctx);
   const GLuint colorMask = *((GLuint *) & ctx->Color.ColorMask[0]);
   GLbitfield tri_mask = 0;
   GLbitfield blit_mask = 0;
   GLbitfield swrast_mask = 0;
   struct gl_framebuffer *fb = ctx->DrawBuffer;
   struct intel_renderbuffer *irb;
   int i;

   if (!_mesa_check_conditional_render(ctx))
      return;

   if (mask & (BUFFER_BIT_FRONT_LEFT | BUFFER_BIT_FRONT_RIGHT)) {
      intel->front_buffer_dirty = GL_TRUE;
   }

   if (0)
      fprintf(stderr, "%s\n", __FUNCTION__);

   /* Get SW clears out of the way: Anything without an intel_renderbuffer */
   for (i = 0; i < BUFFER_COUNT; i++) {
      if (!(mask & (1 << i)))
	 continue;

      irb = intel_get_renderbuffer(fb, i);
      if (unlikely(!irb)) {
	 swrast_mask |= (1 << i);
	 mask &= ~(1 << i);
      }
   }
   if (unlikely(swrast_mask)) {
      debug_mask("swrast", swrast_mask);
      _swrast_Clear(ctx, swrast_mask);
   }

   /* HW color buffers (front, back, aux, generic FBO, etc) */
   if (intel->gen < 6 && colorMask == ~0) {
      /* clear all R,G,B,A */
      blit_mask |= (mask & BUFFER_BITS_COLOR);
   }
   else {
      /* glColorMask in effect */
      tri_mask |= (mask & BUFFER_BITS_COLOR);
   }

   /* Make sure we have up to date buffers before we start looking at
    * the tiling bits to determine how to clear. */
   intel_prepare_render(intel);

   /* HW stencil */
   if (mask & BUFFER_BIT_STENCIL) {
      const struct intel_region *stencilRegion
         = intel_get_rb_region(fb, BUFFER_STENCIL);
      if (stencilRegion) {
         /* have hw stencil */
         if (stencilRegion->tiling == I915_TILING_Y ||
	     (ctx->Stencil.WriteMask[0] & 0xff) != 0xff) {
	    /* We have to use the 3D engine if we're clearing a partial mask
	     * of the stencil buffer, or if we're on a 965 which has a tiled
	     * depth/stencil buffer in a layout we can't blit to.
	     */
            tri_mask |= BUFFER_BIT_STENCIL;
         }
	 else if (intel->has_separate_stencil &&
	       stencilRegion->tiling == I915_TILING_NONE) {
	    /* The stencil buffer is actually W tiled, which the hardware
	     * cannot blit to. */
	    tri_mask |= BUFFER_BIT_STENCIL;
	 }
         else {
            /* clearing all stencil bits, use blitting */
            blit_mask |= BUFFER_BIT_STENCIL;
         }
      }
   }

   /* HW depth */
   if (mask & BUFFER_BIT_DEPTH) {
      const struct intel_region *irb = intel_get_rb_region(fb, BUFFER_DEPTH);

      /* clear depth with whatever method is used for stencil (see above) */
      if (irb->tiling == I915_TILING_Y || tri_mask & BUFFER_BIT_STENCIL)
         tri_mask |= BUFFER_BIT_DEPTH;
      else
         blit_mask |= BUFFER_BIT_DEPTH;
   }

   /* If we're doing a tri pass for depth/stencil, include a likely color
    * buffer with it.
    */
   if (mask & (BUFFER_BIT_DEPTH | BUFFER_BIT_STENCIL)) {
      int color_bit = _mesa_ffs(mask & BUFFER_BITS_COLOR);
      if (color_bit != 0) {
	 tri_mask |= blit_mask & (1 << (color_bit - 1));
	 blit_mask &= ~(1 << (color_bit - 1));
      }
   }

   /* Anything left, just use tris */
   tri_mask |= mask & ~blit_mask;

   if (blit_mask) {
      debug_mask("blit", blit_mask);
      tri_mask |= intelClearWithBlit(ctx, blit_mask);
   }

   if (tri_mask) {
      debug_mask("tri", tri_mask);
      if (ctx->Extensions.ARB_fragment_shader)
	 _mesa_meta_glsl_Clear(&intel->ctx, tri_mask);
      else
	 _mesa_meta_Clear(&intel->ctx, tri_mask);
   }
}
Ejemplo n.º 6
0
/**
 * Called by ctx->Driver.Clear.
 */
static void
intelClear(GLcontext *ctx, GLbitfield mask)
{
   struct intel_context *intel = intel_context(ctx);
   const GLuint colorMask = *((GLuint *) & ctx->Color.ColorMask);
   GLbitfield tri_mask = 0;
   GLbitfield blit_mask = 0;
   GLbitfield swrast_mask = 0;
   struct gl_framebuffer *fb = ctx->DrawBuffer;
   GLuint i;

   if (0)
      fprintf(stderr, "%s\n", __FUNCTION__);

   /* HW color buffers (front, back, aux, generic FBO, etc) */
   if (colorMask == ~0) {
      /* clear all R,G,B,A */
      /* XXX FBO: need to check if colorbuffers are software RBOs! */
      blit_mask |= (mask & BUFFER_BITS_COLOR);
   }
   else {
      /* glColorMask in effect */
      tri_mask |= (mask & (BUFFER_BIT_FRONT_LEFT | BUFFER_BIT_BACK_LEFT));
   }

   /* HW stencil */
   if (mask & BUFFER_BIT_STENCIL) {
      const struct intel_region *stencilRegion
         = intel_get_rb_region(fb, BUFFER_STENCIL);
      if (stencilRegion) {
         /* have hw stencil */
         if (IS_965(intel->intelScreen->deviceID) ||
	     (ctx->Stencil.WriteMask[0] & 0xff) != 0xff) {
	    /* We have to use the 3D engine if we're clearing a partial mask
	     * of the stencil buffer, or if we're on a 965 which has a tiled
	     * depth/stencil buffer in a layout we can't blit to.
	     */
            tri_mask |= BUFFER_BIT_STENCIL;
         }
         else {
            /* clearing all stencil bits, use blitting */
            blit_mask |= BUFFER_BIT_STENCIL;
         }
      }
   }

   /* HW depth */
   if (mask & BUFFER_BIT_DEPTH) {
      /* clear depth with whatever method is used for stencil (see above) */
      if (IS_965(intel->intelScreen->deviceID) ||
	  tri_mask & BUFFER_BIT_STENCIL)
         tri_mask |= BUFFER_BIT_DEPTH;
      else
         blit_mask |= BUFFER_BIT_DEPTH;
   }

   /* If we're doing a tri pass for depth/stencil, include a likely color
    * buffer with it.
    */
   if (mask & (BUFFER_BIT_DEPTH | BUFFER_BIT_STENCIL)) {
      int color_bit = _mesa_ffs(mask & TRI_CLEAR_COLOR_BITS);
      if (color_bit != 0) {
	 tri_mask |= blit_mask & (1 << (color_bit - 1));
	 blit_mask &= ~(1 << (color_bit - 1));
      }
   }

   /* SW fallback clearing */
   swrast_mask = mask & ~tri_mask & ~blit_mask;

   for (i = 0; i < BUFFER_COUNT; i++) {
      GLuint bufBit = 1 << i;
      if ((blit_mask | tri_mask) & bufBit) {
         if (!fb->Attachment[i].Renderbuffer->ClassID) {
            blit_mask &= ~bufBit;
            tri_mask &= ~bufBit;
            swrast_mask |= bufBit;
         }
      }
   }

   if (blit_mask) {
      if (INTEL_DEBUG & DEBUG_BLIT) {
	 DBG("blit clear:");
	 for (i = 0; i < BUFFER_COUNT; i++) {
	    if (blit_mask & (1 << i))
	       DBG(" %s", buffer_names[i]);
	 }
	 DBG("\n");
      }
      intelClearWithBlit(ctx, blit_mask);
   }

   if (tri_mask) {
      if (INTEL_DEBUG & DEBUG_BLIT) {
	 DBG("tri clear:");
	 for (i = 0; i < BUFFER_COUNT; i++) {
	    if (tri_mask & (1 << i))
	       DBG(" %s", buffer_names[i]);
	 }
	 DBG("\n");
      }
      intel_clear_tris(ctx, tri_mask);
   }

   if (swrast_mask) {
      if (INTEL_DEBUG & DEBUG_BLIT) {
	 DBG("swrast clear:");
	 for (i = 0; i < BUFFER_COUNT; i++) {
	    if (swrast_mask & (1 << i))
	       DBG(" %s", buffer_names[i]);
	 }
	 DBG("\n");
      }
      _swrast_Clear(ctx, swrast_mask);
   }
}
/**
 * Copy the back color buffer to the front color buffer. 
 * Used for SwapBuffers().
 */
void
intelCopyBuffer(const __DRIdrawablePrivate * dPriv,
                const drm_clip_rect_t * rect)
{

   struct intel_context *intel;
   const intelScreenPrivate *intelScreen;
   int ret;

   DBG("%s\n", __FUNCTION__);

   assert(dPriv);

   intel = intelScreenContext(dPriv->driScreenPriv->private);
   if (!intel)
      return;

   intelScreen = intel->intelScreen;

   if (intel->last_swap_fence) {
      dri_fence_wait(intel->last_swap_fence);
      dri_fence_unreference(intel->last_swap_fence);
      intel->last_swap_fence = NULL;
   }
   intel->last_swap_fence = intel->first_swap_fence;
   intel->first_swap_fence = NULL;

   /* The LOCK_HARDWARE is required for the cliprects.  Buffer offsets
    * should work regardless.
    */
   LOCK_HARDWARE(intel);

   if (dPriv && dPriv->numClipRects) {
      struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
      struct intel_region *src, *dst;
      int nbox = dPriv->numClipRects;
      drm_clip_rect_t *pbox = dPriv->pClipRects;
      int cpp;
      int src_pitch, dst_pitch;
      unsigned short src_x, src_y;
      int BR13, CMD;
      int i;

      src = intel_get_rb_region(&intel_fb->Base, BUFFER_BACK_LEFT);
      dst = intel_get_rb_region(&intel_fb->Base, BUFFER_FRONT_LEFT);

      src_pitch = src->pitch * src->cpp;
      dst_pitch = dst->pitch * dst->cpp;

      cpp = src->cpp;

      ASSERT(intel_fb);
      ASSERT(intel_fb->Base.Name == 0);    /* Not a user-created FBO */
      ASSERT(src);
      ASSERT(dst);
      ASSERT(src->cpp == dst->cpp);

      if (cpp == 2) {
	 BR13 = (0xCC << 16) | (1 << 24);
	 CMD = XY_SRC_COPY_BLT_CMD;
      }
      else {
	 BR13 = (0xCC << 16) | (1 << 24) | (1 << 25);
	 CMD = XY_SRC_COPY_BLT_CMD | XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB;
      }

#ifndef I915
      if (src->tiled) {
	 CMD |= XY_SRC_TILED;
	 src_pitch /= 4;
      }
      if (dst->tiled) {
	 CMD |= XY_DST_TILED;
	 dst_pitch /= 4;
      }
#endif
      /* do space/cliprects check before going any further */
      intel_batchbuffer_require_space(intel->batch, 8 * 4, REFERENCES_CLIPRECTS);
   again:
      ret = dri_bufmgr_check_aperture_space(dst->buffer);
      ret |= dri_bufmgr_check_aperture_space(src->buffer);
      
      if (ret) {
	intel_batchbuffer_flush(intel->batch);
	goto again;
      }
      
      for (i = 0; i < nbox; i++, pbox++) {
	 drm_clip_rect_t box = *pbox;

	 if (rect) {
	    if (!intel_intersect_cliprects(&box, &box, rect))
	       continue;
	 }

	 if (box.x1 >= box.x2 ||
	     box.y1 >= box.y2)
	    continue;

	 assert(box.x1 < box.x2);
	 assert(box.y1 < box.y2);
	 src_x = box.x1 - dPriv->x + dPriv->backX;
	 src_y = box.y1 - dPriv->y + dPriv->backY;

	 BEGIN_BATCH(8, REFERENCES_CLIPRECTS);
	 OUT_BATCH(CMD);
	 OUT_BATCH(BR13 | dst_pitch);
	 OUT_BATCH((box.y1 << 16) | box.x1);
	 OUT_BATCH((box.y2 << 16) | box.x2);

	 OUT_RELOC(dst->buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE, 0);
	 OUT_BATCH((src_y << 16) | src_x);
	 OUT_BATCH(src_pitch);
	 OUT_RELOC(src->buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_READ, 0);
	 ADVANCE_BATCH();
      }

      if (intel->first_swap_fence)
	 dri_fence_unreference(intel->first_swap_fence);
      intel_batchbuffer_flush(intel->batch);
      intel->first_swap_fence = intel->batch->last_fence;
      if (intel->first_swap_fence)
	 dri_fence_reference(intel->first_swap_fence);
   }

   UNLOCK_HARDWARE(intel);
}