/** * 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, GLboolean all, GLint cx, GLint cy, GLint cw, GLint ch) { struct intel_context *intel = intel_context( ctx ); GLuint clear_depth; GLbitfield skipBuffers = 0; BATCH_LOCALS; if (INTEL_DEBUG & DEBUG_DRI) _mesa_printf("%s %x\n", __FUNCTION__, mask); /* * Compute values for clearing the buffers. */ clear_depth = 0; if (mask & BUFFER_BIT_DEPTH) { clear_depth = (GLuint) (ctx->DrawBuffer->_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) { drm_clip_rect_t clear; int i; if (intel->ctx.DrawBuffer->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; /* adjust for page flipping */ if ( intel->sarea->pf_current_page == 1 ) { const GLuint tmp = mask; mask &= ~(BUFFER_BIT_FRONT_LEFT | BUFFER_BIT_BACK_LEFT); if ( tmp & BUFFER_BIT_FRONT_LEFT ) mask |= BUFFER_BIT_BACK_LEFT; if ( tmp & BUFFER_BIT_BACK_LEFT ) mask |= BUFFER_BIT_FRONT_LEFT; } } else { /* clearing FBO */ ASSERT(intel->numClipRects == 1); ASSERT(intel->pClipRects == &intel->fboRect); clear.x1 = cx; clear.y1 = intel->ctx.DrawBuffer->Height - cy - ch; clear.x2 = clear.y1 + 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 */ if (!all) { intel_intersect_cliprects(&b, &clear, box); } else { b = *box; } 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 */ const struct intel_renderbuffer *irb = intel_renderbuffer(ctx->DrawBuffer-> Attachment[buf].Renderbuffer); GLuint clearVal; GLint pitch, cpp; GLuint BR13, CMD; ASSERT(irb); ASSERT(irb->region); pitch = irb->region->pitch; cpp = irb->region->cpp; /* Setup the blit command */ if (cpp == 4) { BR13 = (0xF0 << 16) | (pitch * cpp) | (1<<24) | (1<<25); if (buf == BUFFER_DEPTH || buf == BUFFER_STENCIL) { CMD = XY_COLOR_BLT_CMD; if (clearMask & BUFFER_BIT_DEPTH) CMD |= XY_COLOR_BLT_WRITE_RGB; if (clearMask & BUFFER_BIT_STENCIL) CMD |= XY_COLOR_BLT_WRITE_ALPHA; } else { /* clearing RGBA */ CMD = (XY_COLOR_BLT_CMD | XY_COLOR_BLT_WRITE_ALPHA | XY_COLOR_BLT_WRITE_RGB); } } else { ASSERT(cpp == 2 || cpp == 0); BR13 = (0xF0 << 16) | (pitch * cpp) | (1<<24); CMD = XY_COLOR_BLT_CMD; } 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); */ 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( irb->region->buffer, DRM_MM_TT|DRM_MM_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 ); }
/* * 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; }
/** * 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); }
/** * 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); }
/* * Copy the back buffer to the front buffer. */ void intelCopyBuffer( const __DRIdrawablePrivate *dPriv, const drm_clip_rect_t *rect ) { struct intel_context *intel; GLboolean missed_target; int64_t ust; DBG("%s\n", __FUNCTION__); assert(dPriv); assert(dPriv->driContextPriv); assert(dPriv->driContextPriv->driverPrivate); intel = (struct intel_context *) dPriv->driContextPriv->driverPrivate; intelFlush( &intel->ctx ); bmFinishFenceLock(intel, intel->last_swap_fence); /* The LOCK_HARDWARE is required for the cliprects. Buffer offsets * should work regardless. */ LOCK_HARDWARE( intel ); if (!rect) { UNLOCK_HARDWARE( intel ); driWaitForVBlank( dPriv, &intel->vbl_seq, intel->vblank_flags, & missed_target ); LOCK_HARDWARE( intel ); } { intelScreenPrivate *intelScreen = intel->intelScreen; __DRIdrawablePrivate *dPriv = intel->driDrawable; int nbox = dPriv->numClipRects; drm_clip_rect_t *pbox = dPriv->pClipRects; int cpp = intelScreen->cpp; struct intel_region *src, *dst; int BR13, CMD; int i; int src_pitch, dst_pitch; if (intel->sarea->pf_current_page == 0) { dst = intel->front_region; src = intel->back_region; } else { assert(0); src = intel->front_region; dst = intel->back_region; } src_pitch = src->pitch * src->cpp; dst_pitch = dst->pitch * 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_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB); } if (src->tiled) { CMD |= XY_SRC_TILED; src_pitch /= 4; } if (dst->tiled) { CMD |= XY_DST_TILED; dst_pitch /= 4; } for (i = 0 ; i < nbox; i++, pbox++) { drm_clip_rect_t tmp = *pbox; if (rect) { if (!intel_intersect_cliprects(&tmp, &tmp, rect)) continue; } if (tmp.x1 > tmp.x2 || tmp.y1 > tmp.y2 || tmp.x2 > intelScreen->width || tmp.y2 > intelScreen->height) continue; BEGIN_BATCH(8, INTEL_BATCH_NO_CLIPRECTS); OUT_BATCH( CMD ); OUT_BATCH( dst_pitch | BR13 ); OUT_BATCH( (tmp.y1 << 16) | tmp.x1 ); OUT_BATCH( (tmp.y2 << 16) | tmp.x2 ); OUT_BATCH( bmBufferOffset(intel, dst->buffer) ); OUT_BATCH( (tmp.y1 << 16) | tmp.x1 ); OUT_BATCH( src_pitch ); OUT_BATCH( bmBufferOffset(intel, src->buffer) ); ADVANCE_BATCH(); } } intel_batchbuffer_flush( intel->batch ); intel->second_last_swap_fence = intel->last_swap_fence; intel->last_swap_fence = bmSetFenceLock( intel ); UNLOCK_HARDWARE( intel ); if (!rect) { intel->swap_count++; (*dri_interface->getUST)(&ust); if (missed_target) { intel->swap_missed_count++; intel->swap_missed_ust = ust - intel->swap_ust; } intel->swap_ust = ust; } }
/* Pros: * - no waiting for idle before updating framebuffer. * * Cons: * - if upload is by memcpy, this may actually be slower than fallback path. * - uploads the whole image even if destination is clipped * * Need to benchmark. * * Given the questions about performance, implement for pbo's only. * This path is definitely a win if the pbo is already in agp. If it * turns out otherwise, we can add the code necessary to upload client * data to agp space before performing the blit. (Though it may turn * out to be better/simpler just to use the texture engine). */ static GLboolean do_blit_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 *dest = intel_drawbuf_region(intel); struct intel_buffer_object *src = intel_buffer_object(unpack->BufferObj); GLuint src_offset; GLuint rowLength; struct _DriFenceObject *fence = NULL; if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s\n", __FUNCTION__); if (!dest) { if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - no dest\n", __FUNCTION__); return GL_FALSE; } if (src) { /* This validation should be done by core mesa: */ 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: */ if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - not PBO\n", __FUNCTION__); return GL_FALSE; } if (!intel_check_blit_format(dest, format, type)) { if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - bad format for blit\n", __FUNCTION__); return GL_FALSE; } if (!intel_check_blit_fragment_ops(ctx)) { if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - bad GL fragment state for blitter\n", __FUNCTION__); return GL_FALSE; } if (ctx->Pixel.ZoomX != 1.0F) { if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - bad PixelZoomX for blit\n", __FUNCTION__); return GL_FALSE; } if (unpack->RowLength > 0) rowLength = unpack->RowLength; else rowLength = width; if (ctx->Pixel.ZoomY == -1.0F) { if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - bad PixelZoomY for blit\n", __FUNCTION__); return GL_FALSE; /* later */ y -= height; } else if (ctx->Pixel.ZoomY == 1.0F) { rowLength = -rowLength; } else { if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - bad PixelZoomY for blit\n", __FUNCTION__); return GL_FALSE; } src_offset = (GLuint) _mesa_image_address(2, unpack, pixels, width, height, format, type, 0, 0, 0); intelFlush(&intel->ctx); LOCK_HARDWARE(intel); if (intel->driDrawable->numClipRects) { __DRIdrawablePrivate *dPriv = intel->driDrawable; int nbox = dPriv->numClipRects; drm_clip_rect_t *box = dPriv->pClipRects; drm_clip_rect_t rect; drm_clip_rect_t dest_rect; struct _DriBufferObject *src_buffer = intel_bufferobj_buffer(intel, src, INTEL_READ); int i; dest_rect.x1 = dPriv->x + x; dest_rect.y1 = dPriv->y + dPriv->h - (y + height); dest_rect.x2 = dest_rect.x1 + width; dest_rect.y2 = dest_rect.y1 + height; for (i = 0; i < nbox; i++) { if (!intel_intersect_cliprects(&rect, &dest_rect, &box[i])) continue; intelEmitCopyBlit(intel, dest->cpp, rowLength, src_buffer, src_offset, dest->pitch, dest->buffer, 0, rect.x1 - dest_rect.x1, rect.y2 - dest_rect.y2, rect.x1, rect.y1, rect.x2 - rect.x1, rect.y2 - rect.y1, ctx->Color.ColorLogicOpEnabled ? ctx->Color.LogicOp : GL_COPY); } fence = intel_batchbuffer_flush(intel->batch); driFenceReference(fence); } UNLOCK_HARDWARE(intel); if (fence) { driFenceFinish(fence, DRM_FENCE_TYPE_EXE | DRM_I915_FENCE_TYPE_RW, GL_FALSE); driFenceUnReference(fence); } if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - DONE\n", __FUNCTION__); return GL_TRUE; }