Example #1
0
/*
 * Render a bitmap.
 */
static bool
do_blit_bitmap( struct gl_context *ctx, 
		GLint dstx, GLint dsty,
		GLsizei width, GLsizei height,
		const struct gl_pixelstore_attrib *unpack,
		const GLubyte *bitmap )
{
   struct intel_context *intel = intel_context(ctx);
   struct gl_framebuffer *fb = ctx->DrawBuffer;
   struct intel_renderbuffer *irb;
   GLfloat tmpColor[4];
   GLubyte ubcolor[4];
   GLuint color;
   GLsizei bitmap_width = width;
   GLsizei bitmap_height = height;
   GLint px, py;
   GLuint stipple[32];
   GLint orig_dstx = dstx;
   GLint orig_dsty = dsty;

   /* Update draw buffer bounds */
   _mesa_update_state(ctx);

   if (ctx->Depth.Test) {
      /* The blit path produces incorrect results when depth testing is on.
       * It seems the blit Z coord is always 1.0 (the far plane) so fragments
       * will likely be obscured by other, closer geometry.
       */
      return false;
   }

   intel_prepare_render(intel);

   if (fb->_NumColorDrawBuffers != 1) {
      perf_debug("accelerated glBitmap() only supports rendering to a "
                 "single color buffer\n");
      return false;
   }

   irb = intel_renderbuffer(fb->_ColorDrawBuffers[0]);

   if (_mesa_is_bufferobj(unpack->BufferObj)) {
      bitmap = map_pbo(ctx, width, height, unpack, bitmap);
      if (bitmap == NULL)
	 return true;	/* even though this is an error, we're done */
   }

   COPY_4V(tmpColor, ctx->Current.RasterColor);

   if (_mesa_need_secondary_color(ctx)) {
       ADD_3V(tmpColor, tmpColor, ctx->Current.RasterSecondaryColor);
   }

   UNCLAMPED_FLOAT_TO_UBYTE(ubcolor[0], tmpColor[0]);
   UNCLAMPED_FLOAT_TO_UBYTE(ubcolor[1], tmpColor[1]);
   UNCLAMPED_FLOAT_TO_UBYTE(ubcolor[2], tmpColor[2]);
   UNCLAMPED_FLOAT_TO_UBYTE(ubcolor[3], tmpColor[3]);

   switch (irb->mt->format) {
   case MESA_FORMAT_B8G8R8A8_UNORM:
   case MESA_FORMAT_B8G8R8X8_UNORM:
      color = PACK_COLOR_8888(ubcolor[3], ubcolor[0], ubcolor[1], ubcolor[2]);
      break;
   case MESA_FORMAT_B5G6R5_UNORM:
      color = PACK_COLOR_565(ubcolor[0], ubcolor[1], ubcolor[2]);
      break;
   default:
      perf_debug("Unsupported format %s in accelerated glBitmap()\n",
                 _mesa_get_format_name(irb->mt->format));
      return false;
   }

   if (!intel_check_blit_fragment_ops(ctx, tmpColor[3] == 1.0F))
      return false;

   /* Clip to buffer bounds and scissor. */
   if (!_mesa_clip_to_region(fb->_Xmin, fb->_Ymin,
			     fb->_Xmax, fb->_Ymax,
			     &dstx, &dsty, &width, &height))
      goto out;

   dsty = y_flip(fb, dsty, height);

#define DY 32
#define DX 32

   /* Chop it all into chunks that can be digested by hardware: */
   for (py = 0; py < height; py += DY) {
      for (px = 0; px < width; px += DX) {
	 int h = MIN2(DY, height - py);
	 int w = MIN2(DX, width - px);
	 GLuint sz = ALIGN(ALIGN(w,8) * h, 64)/8;
	 GLenum logic_op = ctx->Color.ColorLogicOpEnabled ?
	    ctx->Color.LogicOp : GL_COPY;

	 assert(sz <= sizeof(stipple));
	 memset(stipple, 0, sz);

	 /* May need to adjust this when padding has been introduced in
	  * sz above:
	  *
	  * Have to translate destination coordinates back into source
	  * coordinates.
	  */
         int count = get_bitmap_rect(bitmap_width, bitmap_height, unpack,
                                     bitmap,
                                     -orig_dstx + (dstx + px),
                                     -orig_dsty + y_flip(fb, dsty + py, h),
                                     w, h,
                                     (GLubyte *)stipple,
                                     8,
                                     _mesa_is_winsys_fbo(fb));
         if (count == 0)
	    continue;

	 if (!intelEmitImmediateColorExpandBlit(intel,
						irb->mt->cpp,
						(GLubyte *)stipple,
						sz,
						color,
						irb->mt->region->pitch,
						irb->mt->region->bo,
						0,
						irb->mt->region->tiling,
						dstx + px,
						dsty + py,
						w, h,
						logic_op)) {
	    return false;
	 }

         if (ctx->Query.CurrentOcclusionObject)
            ctx->Query.CurrentOcclusionObject->Result += count;
      }
   }
out:

   if (unlikely(INTEL_DEBUG & DEBUG_SYNC))
      intel_batchbuffer_flush(intel);

   if (_mesa_is_bufferobj(unpack->BufferObj)) {
      /* done with PBO so unmap it now */
      ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj, MAP_INTERNAL);
   }

   intel_check_front_buffer_rendering(intel);

   return true;
}
Example #2
0
/**
 * CopyPixels with the blitter.  Don't support zooming, pixel transfer, etc.
 */
static GLboolean
do_blit_copypixels(struct gl_context * ctx,
                   GLint srcx, GLint srcy,
                   GLsizei width, GLsizei height,
                   GLint dstx, GLint dsty, GLenum type)
{
   struct intel_context *intel = intel_context(ctx);
   struct gl_framebuffer *fb = ctx->DrawBuffer;
   struct gl_framebuffer *read_fb = ctx->ReadBuffer;
   GLint orig_dstx;
   GLint orig_dsty;
   GLint orig_srcx;
   GLint orig_srcy;
   GLboolean flip = GL_FALSE;
   struct intel_renderbuffer *draw_irb = NULL;
   struct intel_renderbuffer *read_irb = NULL;

   /* Update draw buffer bounds */
   _mesa_update_state(ctx);

   switch (type) {
   case GL_COLOR:
      if (fb->_NumColorDrawBuffers != 1) {
	 fallback_debug("glCopyPixels() fallback: MRT\n");
	 return GL_FALSE;
      }

      draw_irb = intel_renderbuffer(fb->_ColorDrawBuffers[0]);
      read_irb = intel_renderbuffer(read_fb->_ColorReadBuffer);
      break;
   case GL_DEPTH_STENCIL_EXT:
      draw_irb = intel_renderbuffer(fb->Attachment[BUFFER_DEPTH].Renderbuffer);
      read_irb =
	 intel_renderbuffer(read_fb->Attachment[BUFFER_DEPTH].Renderbuffer);
      break;
   case GL_DEPTH:
      fallback_debug("glCopyPixels() fallback: GL_DEPTH\n");
      return GL_FALSE;
   case GL_STENCIL:
      fallback_debug("glCopyPixels() fallback: GL_STENCIL\n");
      return GL_FALSE;
   default:
      fallback_debug("glCopyPixels(): Unknown type\n");
      return GL_FALSE;
   }

   if (!draw_irb) {
      fallback_debug("glCopyPixels() fallback: missing draw buffer\n");
      return GL_FALSE;
   }

   if (!read_irb) {
      fallback_debug("glCopyPixels() fallback: missing read buffer\n");
      return GL_FALSE;
   }

   if (draw_irb->Base.Format != read_irb->Base.Format &&
       !(draw_irb->Base.Format == MESA_FORMAT_XRGB8888 &&
	 read_irb->Base.Format == MESA_FORMAT_ARGB8888)) {
      fallback_debug("glCopyPixels() fallback: mismatched formats (%s -> %s\n",
		     _mesa_get_format_name(read_irb->Base.Format),
		     _mesa_get_format_name(draw_irb->Base.Format));
      return GL_FALSE;
   }

   /* Copypixels can be more than a straight copy.  Ensure all the
    * extra operations are disabled:
    */
   if (!intel_check_copypixel_blit_fragment_ops(ctx) ||
       ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F)
      return GL_FALSE;

   intel_prepare_render(intel);

   intel_flush(&intel->ctx);

   /* Clip to destination buffer. */
   orig_dstx = dstx;
   orig_dsty = dsty;
   if (!_mesa_clip_to_region(fb->_Xmin, fb->_Ymin,
			     fb->_Xmax, fb->_Ymax,
			     &dstx, &dsty, &width, &height))
      goto out;
   /* Adjust src coords for our post-clipped destination origin */
   srcx += dstx - orig_dstx;
   srcy += dsty - orig_dsty;

   /* Clip to source buffer. */
   orig_srcx = srcx;
   orig_srcy = srcy;
   if (!_mesa_clip_to_region(0, 0,
			     read_fb->Width, read_fb->Height,
			     &srcx, &srcy, &width, &height))
      goto out;
   /* Adjust dst coords for our post-clipped source origin */
   dstx += srcx - orig_srcx;
   dsty += srcy - orig_srcy;

   /* Flip dest Y if it's a window system framebuffer. */
   if (fb->Name == 0) {
      /* copypixels to a window system framebuffer */
      dsty = fb->Height - dsty - height;
      flip = !flip;
   }

   /* Flip source Y if it's a window system framebuffer. */
   if (read_fb->Name == 0) {
      srcy = read_fb->Height - srcy - height;
      flip = !flip;
   }

   srcx += read_irb->draw_x;
   srcy += read_irb->draw_y;
   dstx += draw_irb->draw_x;
   dsty += draw_irb->draw_y;

   if (!intel_region_copy(intel,
			  draw_irb->region, 0, dstx, dsty,
			  read_irb->region, 0, srcx, srcy,
			  width, height, flip,
			  ctx->Color.ColorLogicOpEnabled ?
			  ctx->Color.LogicOp : GL_COPY)) {
      DBG("%s: blit failure\n", __FUNCTION__);
      return GL_FALSE;
   }

out:
   intel_check_front_buffer_rendering(intel);

   DBG("%s: success\n", __FUNCTION__);
   return GL_TRUE;
}
Example #3
0
/**
 * CopyPixels with the blitter.  Don't support zooming, pixel transfer, etc.
 */
static bool
do_blit_copypixels(struct gl_context * ctx,
                   GLint srcx, GLint srcy,
                   GLsizei width, GLsizei height,
                   GLint dstx, GLint dsty, GLenum type)
{
   struct brw_context *brw = brw_context(ctx);
   struct gl_framebuffer *fb = ctx->DrawBuffer;
   struct gl_framebuffer *read_fb = ctx->ReadBuffer;
   GLint orig_dstx;
   GLint orig_dsty;
   GLint orig_srcx;
   GLint orig_srcy;
   struct intel_renderbuffer *draw_irb = NULL;
   struct intel_renderbuffer *read_irb = NULL;

   /* Update draw buffer bounds */
   _mesa_update_state(ctx);

   intel_prepare_render(brw);

   switch (type) {
   case GL_COLOR:
      if (fb->_NumColorDrawBuffers != 1) {
	 perf_debug("glCopyPixels() fallback: MRT\n");
	 return false;
      }

      draw_irb = intel_renderbuffer(fb->_ColorDrawBuffers[0]);
      read_irb = intel_renderbuffer(read_fb->_ColorReadBuffer);
      break;
   case GL_DEPTH_STENCIL_EXT:
      draw_irb = intel_renderbuffer(fb->Attachment[BUFFER_DEPTH].Renderbuffer);
      read_irb =
	 intel_renderbuffer(read_fb->Attachment[BUFFER_DEPTH].Renderbuffer);
      break;
   case GL_DEPTH:
      perf_debug("glCopyPixels() fallback: GL_DEPTH\n");
      return false;
   case GL_STENCIL:
      perf_debug("glCopyPixels() fallback: GL_STENCIL\n");
      return false;
   default:
      perf_debug("glCopyPixels(): Unknown type\n");
      return false;
   }

   if (!draw_irb) {
      perf_debug("glCopyPixels() fallback: missing draw buffer\n");
      return false;
   }

   if (!read_irb) {
      perf_debug("glCopyPixels() fallback: missing read buffer\n");
      return false;
   }

   if (draw_irb->mt->num_samples > 1 || read_irb->mt->num_samples > 1) {
      perf_debug("glCopyPixels() fallback: multisampled buffers\n");
      return false;
   }

   if (ctx->_ImageTransferState) {
      perf_debug("glCopyPixels(): Unsupported image transfer state\n");
      return false;
   }

   if (ctx->Depth.Test) {
      perf_debug("glCopyPixels(): Unsupported depth test state\n");
      return false;
   }

   if (ctx->Stencil._Enabled) {
      perf_debug("glCopyPixels(): Unsupported stencil test state\n");
      return false;
   }

   if (ctx->Fog.Enabled ||
       ctx->Texture._MaxEnabledTexImageUnit != -1 ||
       ctx->FragmentProgram._Enabled) {
      perf_debug("glCopyPixels(): Unsupported fragment shader state\n");
      return false;
   }

   if (ctx->Color.AlphaEnabled ||
       ctx->Color.BlendEnabled) {
      perf_debug("glCopyPixels(): Unsupported blend state\n");
      return false;
   }

   if (!ctx->Color.ColorMask[0][0] ||
       !ctx->Color.ColorMask[0][1] ||
       !ctx->Color.ColorMask[0][2] ||
       !ctx->Color.ColorMask[0][3]) {
      perf_debug("glCopyPixels(): Unsupported color mask state\n");
      return false;
   }

   if (ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F) {
      perf_debug("glCopyPixles(): Unsupported pixel zoom\n");
      return false;
   }

   intel_batchbuffer_flush(brw);

   /* Clip to destination buffer. */
   orig_dstx = dstx;
   orig_dsty = dsty;
   if (!_mesa_clip_to_region(fb->_Xmin, fb->_Ymin,
			     fb->_Xmax, fb->_Ymax,
			     &dstx, &dsty, &width, &height))
      goto out;
   /* Adjust src coords for our post-clipped destination origin */
   srcx += dstx - orig_dstx;
   srcy += dsty - orig_dsty;

   /* Clip to source buffer. */
   orig_srcx = srcx;
   orig_srcy = srcy;
   if (!_mesa_clip_to_region(0, 0,
			     read_fb->Width, read_fb->Height,
			     &srcx, &srcy, &width, &height))
      goto out;
   /* Adjust dst coords for our post-clipped source origin */
   dstx += srcx - orig_srcx;
   dsty += srcy - orig_srcy;

   if (!intel_miptree_blit(brw,
                           read_irb->mt, read_irb->mt_level, read_irb->mt_layer,
                           srcx, srcy, _mesa_is_winsys_fbo(read_fb),
                           draw_irb->mt, draw_irb->mt_level, draw_irb->mt_layer,
                           dstx, dsty, _mesa_is_winsys_fbo(fb),
                           width, height,
                           (ctx->Color.ColorLogicOpEnabled ?
                            ctx->Color.LogicOp : GL_COPY))) {
      DBG("%s: blit failure\n", __FUNCTION__);
      return false;
   }

   if (ctx->Query.CurrentOcclusionObject)
      ctx->Query.CurrentOcclusionObject->Result += width * height;

out:

   DBG("%s: success\n", __FUNCTION__);
   return true;
}
Example #4
0
/*
 * Render a bitmap.
 */
static GLboolean
do_blit_bitmap( GLcontext *ctx, 
		GLint dstx, GLint dsty,
		GLsizei width, GLsizei height,
		const struct gl_pixelstore_attrib *unpack,
		const GLubyte *bitmap )
{
   struct intel_context *intel = intel_context(ctx);
   struct intel_region *dst = intel_drawbuf_region(intel);
   GLfloat tmpColor[4];
   GLubyte ubcolor[4];
   GLuint color8888, color565;

   if (!dst)
       return GL_FALSE;

   if (unpack->BufferObj->Name) {
      bitmap = map_pbo(ctx, width, height, unpack, bitmap);
      if (bitmap == NULL)
	 return GL_TRUE;	/* even though this is an error, we're done */
   }

   COPY_4V(tmpColor, ctx->Current.RasterColor);

   if (NEED_SECONDARY_COLOR(ctx)) {
       ADD_3V(tmpColor, tmpColor, ctx->Current.RasterSecondaryColor);
   }

   UNCLAMPED_FLOAT_TO_UBYTE(ubcolor[0], tmpColor[0]);
   UNCLAMPED_FLOAT_TO_UBYTE(ubcolor[1], tmpColor[1]);
   UNCLAMPED_FLOAT_TO_UBYTE(ubcolor[2], tmpColor[2]);
   UNCLAMPED_FLOAT_TO_UBYTE(ubcolor[3], tmpColor[3]);

   color8888 = INTEL_PACKCOLOR8888(ubcolor[0], ubcolor[1], ubcolor[2], ubcolor[3]);
   color565 = INTEL_PACKCOLOR565(ubcolor[0], ubcolor[1], ubcolor[2]);
 

   /* Does zoom apply to bitmaps?
    */
   if (!intel_check_blit_fragment_ops(ctx) ||
       ctx->Pixel.ZoomX != 1.0F || 
       ctx->Pixel.ZoomY != 1.0F)
      return GL_FALSE;

   LOCK_HARDWARE(intel);

   if (intel->driDrawable->numClipRects) {
      __DRIdrawablePrivate *dPriv = intel->driDrawable;
      drm_clip_rect_t *box = dPriv->pClipRects;
      drm_clip_rect_t dest_rect;
      GLint nbox = dPriv->numClipRects;
      GLint srcx = 0, srcy = 0;
      GLint orig_screen_x1, orig_screen_y2;
      GLuint i;


      orig_screen_x1 = dPriv->x + dstx;
      orig_screen_y2 = dPriv->y + (dPriv->h - dsty);

      /* Do scissoring in GL coordinates:
       */
      if (ctx->Scissor.Enabled)
      {
	 GLint x = ctx->Scissor.X;
	 GLint y = ctx->Scissor.Y;
	 GLuint w = ctx->Scissor.Width;
	 GLuint h = ctx->Scissor.Height;

         if (!_mesa_clip_to_region(x, y, x+w-1, y+h-1, &dstx, &dsty, &width, &height))
            goto out;
      }

      /* Convert from GL to hardware coordinates:
       */
      dsty = dPriv->y + (dPriv->h - dsty - height);  
      dstx = dPriv->x + dstx;

      dest_rect.x1 = dstx < 0 ? 0 : dstx;
      dest_rect.y1 = dsty < 0 ? 0 : dsty;
      dest_rect.x2 = dstx + width < 0 ? 0 : dstx + width;
      dest_rect.y2 = dsty + height < 0 ? 0 : dsty + height;

      for (i = 0; i < nbox; i++) {
         drm_clip_rect_t rect;
	 int box_w, box_h;
	 GLint px, py;
	 GLuint stipple[32];  

         if (!intel_intersect_cliprects(&rect, &dest_rect, &box[i]))
            continue;

	 /* Now go back to GL coordinates to figure out what subset of
	  * the bitmap we are uploading for this cliprect:
	  */
	 box_w = rect.x2 - rect.x1;
	 box_h = rect.y2 - rect.y1;
	 srcx = rect.x1 - orig_screen_x1;
	 srcy = orig_screen_y2 - rect.y2;


#define DY 32
#define DX 32

	 /* Then, finally, chop it all into chunks that can be
	  * digested by hardware:
	  */
	 for (py = 0; py < box_h; py += DY) { 
	    for (px = 0; px < box_w; px += DX) { 
	       int h = MIN2(DY, box_h - py);
	       int w = MIN2(DX, box_w - px); 
	       GLuint sz = ALIGN(ALIGN(w,8) * h, 64)/8;
	       GLenum logic_op = ctx->Color.ColorLogicOpEnabled ?
		  ctx->Color.LogicOp : GL_COPY;

	       assert(sz <= sizeof(stipple));
	       memset(stipple, 0, sz);

	       /* May need to adjust this when padding has been introduced in
		* sz above:
		*/
	       if (get_bitmap_rect(width, height, unpack, 
				   bitmap,
				   srcx + px, srcy + py, w, h,
				   (GLubyte *)stipple,
				   8,
				   GL_TRUE) == 0)
		  continue;

	       /* 
		*/
	       intelEmitImmediateColorExpandBlit( intel,
						  dst->cpp,
						  (GLubyte *)stipple, 
						  sz,
						  (dst->cpp == 2) ? color565 : color8888,
						  dst->pitch,
						  dst->buffer,
						  0,
						  dst->tiled,
						  rect.x1 + px,
						  rect.y2 - (py + h),
						  w, h,
						  logic_op);
	    } 
	 } 
      }
      intel->need_flush = GL_TRUE;
   out:
      intel_batchbuffer_flush(intel->batch);
   }
   UNLOCK_HARDWARE(intel);


   if (unpack->BufferObj->Name) {
      /* done with PBO so unmap it now */
      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
                              unpack->BufferObj);
   }

   return GL_TRUE;
}
Example #5
0
static GLboolean
do_copy_texsubimage(struct intel_context *intel,
                    struct intel_texture_image *intelImage,
                    GLenum internalFormat,
                    GLint dstx, GLint dsty,
                    GLint x, GLint y, GLsizei width, GLsizei height)
{
   GLcontext *ctx = &intel->ctx;
   const struct intel_region *src =
      get_teximage_source(intel, internalFormat);

   if (!intelImage->mt || !src) {
      DBG("%s fail %p %p\n", __FUNCTION__, intelImage->mt, src);
      return GL_FALSE;
   }

   intelFlush(ctx);
   LOCK_HARDWARE(intel);
   {
      GLuint image_offset = intel_miptree_image_offset(intelImage->mt,
                                                       intelImage->face,
                                                       intelImage->level);
      const GLint orig_x = x;
      const GLint orig_y = y;
      const struct gl_framebuffer *fb = ctx->DrawBuffer;

      if (_mesa_clip_to_region(fb->_Xmin, fb->_Ymin, fb->_Xmax, fb->_Ymax,
                               &x, &y, &width, &height)) {
         /* Update dst for clipped src.  Need to also clip the source rect.
          */
         dstx += x - orig_x;
         dsty += y - orig_y;

         if (ctx->ReadBuffer->Name == 0) {
            /* reading from a window, adjust x, y */
            __DRIdrawablePrivate *dPriv = intel->driDrawable;
            GLuint window_y;
            /* window_y = position of window on screen if y=0=bottom */
            window_y = intel->intelScreen->height - (dPriv->y + dPriv->h);
            y = window_y + y;
            x += dPriv->x;
         }
         else {
            /* reading from a FBO */
            /* invert Y */
            y = ctx->ReadBuffer->Height - y - 1;
         }


         /* A bit of fiddling to get the blitter to work with -ve
          * pitches.  But we get a nice inverted blit this way, so it's
          * worth it:
          */
         intelEmitCopyBlit(intel,
                           intelImage->mt->cpp,
                           -src->pitch,
                           src->buffer,
                           src->height * src->pitch * src->cpp,
                           intelImage->mt->pitch,
                           intelImage->mt->region->buffer,
                           image_offset,
                           x, y + height, dstx, dsty, width, height,
			   GL_COPY); /* ? */

         intel_batchbuffer_flush(intel->batch);
      }
   }


   UNLOCK_HARDWARE(intel);

#if 0
   /* GL_SGIS_generate_mipmap -- this can be accelerated now.
    * XXX Add a ctx->Driver.GenerateMipmaps() function?
    */
   if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
      intel_generate_mipmap(ctx, target,
                            &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
                            texObj);
   }
#endif

   return GL_TRUE;
}
Example #6
0
static GLboolean
do_texture_drawpixels(GLcontext * ctx,
                      GLint x, GLint y,
                      GLsizei width, GLsizei height,
                      GLenum format, GLenum type,
                      const struct gl_pixelstore_attrib *unpack,
                      const GLvoid * pixels)
{
   struct intel_context *intel = intel_context(ctx);
   struct intel_region *dst = intel_drawbuf_region(intel);
   struct intel_buffer_object *src = intel_buffer_object(unpack->BufferObj);
   GLuint rowLength = unpack->RowLength ? unpack->RowLength : width;
   GLuint src_offset;

   if (INTEL_DEBUG & DEBUG_PIXEL)
      fprintf(stderr, "%s\n", __FUNCTION__);

   intelFlush(&intel->ctx);
   intel->vtbl.render_start(intel);
   intel->vtbl.emit_state(intel);

   if (!dst)
      return GL_FALSE;

   if (src) {
      if (!_mesa_validate_pbo_access(2, unpack, width, height, 1,
                                     format, type, pixels)) {
         _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawPixels");
         return GL_TRUE;
      }
   }
   else {
      /* PBO only for now:
       */
/*       _mesa_printf("%s - not PBO\n", __FUNCTION__); */
      return GL_FALSE;
   }

   /* There are a couple of things we can't do yet, one of which is
    * set the correct state for pixel operations when GL texturing is
    * enabled.  That's a pretty rare state and probably not worth the
    * effort.  A completely device-independent version of this may do
    * more.
    *
    * Similarly, we make no attempt to merge metaops processing with
    * an enabled fragment program, though it would certainly be
    * possible.
    */
   if (!intel_check_meta_tex_fragment_ops(ctx)) {
      if (INTEL_DEBUG & DEBUG_PIXEL)
         _mesa_printf("%s - bad GL fragment state for metaops texture\n",
                      __FUNCTION__);
      return GL_FALSE;
   }

   intel->vtbl.install_meta_state(intel);


   /* Is this true?  Also will need to turn depth testing on according
    * to state:
    */
   intel->vtbl.meta_no_stencil_write(intel);
   intel->vtbl.meta_no_depth_write(intel);

   /* Set the 3d engine to draw into the destination region:
    */
   intel->vtbl.meta_draw_region(intel, dst, intel->intelScreen->depth_region);

   intel->vtbl.meta_import_pixel_state(intel);

   src_offset = (GLuint) _mesa_image_address(2, unpack, pixels, width, height,
                                             format, type, 0, 0, 0);


   /* Setup the pbo up as a rectangular texture, if possible.
    *
    * TODO: This is almost always possible if the i915 fragment
    * program is adjusted to correctly swizzle the sampled colors.
    * The major exception is any 24bit texture, like RGB888, for which
    * there is no hardware support.  
    */
   if (!intel->vtbl.meta_tex_rect_source(intel, src->buffer, src_offset,
                                         rowLength, height, format, type)) {
      intel->vtbl.leave_meta_state(intel);
      return GL_FALSE;
   }

   intel->vtbl.meta_texture_blend_replace(intel);


   LOCK_HARDWARE(intel);

   if (intel->driDrawable->numClipRects) {
      __DRIdrawablePrivate *dPriv = intel->driDrawable;
      GLint srcx, srcy;
      GLint dstx, dsty;

      dstx = x;
      dsty = dPriv->h - (y + height);

      srcx = 0;                 /* skiprows/pixels already done */
      srcy = 0;

      if (0) {
         const GLint orig_x = dstx;
         const GLint orig_y = dsty;

         if (!_mesa_clip_to_region(0, 0, dst->pitch, dst->height,
                                   &dstx, &dsty, &width, &height))
            goto out;

         srcx += dstx - orig_x;
         srcy += dsty - orig_y;
      }


      if (INTEL_DEBUG & DEBUG_PIXEL)
         _mesa_printf("draw %d,%d %dx%d\n", dstx, dsty, width, height);

      /* Must use the regular cliprect mechanism in order to get the
       * drawing origin set correctly.  Otherwise scissor state is in
       * incorrect coordinate space.  Does this even need to hold the
       * lock???
       */
      intel_meta_draw_quad(intel,
                           dstx, dstx + width * ctx->Pixel.ZoomX,
                           dPriv->h - (y + height * ctx->Pixel.ZoomY),
                           dPriv->h - (y),
                           -ctx->Current.RasterPos[2] * .5,
                           0x00ff00ff,
                           srcx, srcx + width, srcy + height, srcy);
    out:
      intel->vtbl.leave_meta_state(intel);
      intel_batchbuffer_flush(intel->batch);
   }
   UNLOCK_HARDWARE(intel);
   return GL_TRUE;
}