diff --git a/src/i830.h b/src/i830.h index f8aa824e..229a4e68 100644 --- a/src/i830.h +++ b/src/i830.h @@ -469,8 +469,10 @@ void i830_set_gem_max_sizes(ScrnInfoPtr scrn); drm_intel_bo *i830_allocate_framebuffer(ScrnInfoPtr scrn); /* i830_render.c */ -Bool i830_check_composite(int op, PicturePtr source, PicturePtr mask, - PicturePtr dest); +Bool i830_check_composite(int op, + PicturePtr sourcec, PicturePtr mask, PicturePtr dest, + int width, int height); +Bool i830_check_composite_target(PixmapPtr pixmap); Bool i830_check_composite_texture(ScreenPtr screen, PicturePtr picture); Bool i830_prepare_composite(int op, PicturePtr sourcec, PicturePtr mask, PicturePtr dest, PixmapPtr sourcecPixmap, @@ -481,8 +483,10 @@ void i830_composite(PixmapPtr dest, int srcX, int srcY, int maskX, int maskY, int dstX, int dstY, int w, int h); void i830_done_composite(PixmapPtr dest); /* i915_render.c */ -Bool i915_check_composite(int op, PicturePtr sourcec, PicturePtr mask, - PicturePtr dest); +Bool i915_check_composite(int op, + PicturePtr sourcec, PicturePtr mask, PicturePtr dest, + int width, int height); +Bool i915_check_composite_target(PixmapPtr pixmap); Bool i915_check_composite_texture(ScreenPtr screen, PicturePtr picture); Bool i915_prepare_composite(int op, PicturePtr sourcec, PicturePtr mask, PicturePtr dest, PixmapPtr sourcecPixmap, @@ -496,8 +500,9 @@ void i830_batch_flush_notify(ScrnInfoPtr scrn); unsigned int gen4_render_state_size(ScrnInfoPtr scrn); void gen4_render_state_init(ScrnInfoPtr scrn); void gen4_render_state_cleanup(ScrnInfoPtr scrn); -Bool i965_check_composite(int op, PicturePtr sourcec, PicturePtr mask, - PicturePtr dest); +Bool i965_check_composite(int op, + PicturePtr sourcec, PicturePtr mask, PicturePtr dest, + int width, int height); Bool i965_check_composite_texture(ScreenPtr screen, PicturePtr picture); Bool i965_prepare_composite(int op, PicturePtr sourcec, PicturePtr mask, PicturePtr dest, PixmapPtr sourcecPixmap, diff --git a/src/i830_render.c b/src/i830_render.c index b0413c58..cba65eb3 100644 --- a/src/i830_render.c +++ b/src/i830_render.c @@ -340,8 +340,11 @@ static void i830_texture_setup(PicturePtr picture, PixmapPtr pixmap, int unit) } Bool -i830_check_composite(int op, PicturePtr source_picture, PicturePtr mask_picture, - PicturePtr dest_picture) +i830_check_composite(int op, + PicturePtr source_picture, + PicturePtr mask_picture, + PicturePtr dest_picture, + int width, int height) { ScrnInfoPtr scrn = xf86Screens[dest_picture->pDrawable->pScreen->myNum]; uint32_t tmp1; @@ -373,6 +376,23 @@ i830_check_composite(int op, PicturePtr source_picture, PicturePtr mask_picture, return FALSE; } + if (width > 2048 || height > 2048) { + intel_debug_fallback(scrn, "Operation is too large (%d, %d)\n", width, height); + return FALSE; + } + + return TRUE; +} + +Bool +i830_check_composite_target(PixmapPtr pixmap) +{ + if (pixmap->drawable.width > 2048 || pixmap->drawable.height > 2048) + return FALSE; + + if(!intel_check_pitch_3d(pixmap)) + return FALSE; + return TRUE; } diff --git a/src/i830_uxa.c b/src/i830_uxa.c index a79dde17..0a6b6f80 100644 --- a/src/i830_uxa.c +++ b/src/i830_uxa.c @@ -323,10 +323,10 @@ static void i830_uxa_done_solid(PixmapPtr pixmap) * - support planemask using FULL_BLT_CMD? */ static Bool -i830_uxa_check_copy(DrawablePtr source, DrawablePtr dest, +i830_uxa_check_copy(PixmapPtr source, PixmapPtr dest, int alu, Pixel planemask) { - ScrnInfoPtr scrn = xf86Screens[dest->pScreen->myNum]; + ScrnInfoPtr scrn = xf86Screens[dest->drawable.pScreen->myNum]; intel_screen_private *intel = intel_get_screen_private(scrn); if (IS_GEN6(intel)) { @@ -335,16 +335,16 @@ i830_uxa_check_copy(DrawablePtr source, DrawablePtr dest, return FALSE; } - if (!UXA_PM_IS_SOLID(source, planemask)) { + if (!UXA_PM_IS_SOLID(&source->drawable, planemask)) { intel_debug_fallback(scrn, "planemask is not solid"); return FALSE; } - if (source->bitsPerPixel != dest->bitsPerPixel) { + if (source->drawable.bitsPerPixel != dest->drawable.bitsPerPixel) { intel_debug_fallback(scrn, "mixed bpp copies unsupported\n"); return FALSE; } - switch (source->bitsPerPixel) { + switch (source->drawable.bitsPerPixel) { case 8: case 16: case 32: @@ -353,6 +353,11 @@ i830_uxa_check_copy(DrawablePtr source, DrawablePtr dest, return FALSE; } + if (!intel_check_pitch_2d(source)) + return FALSE; + if (!intel_check_pitch_2d(dest)) + return FALSE; + return TRUE; } @@ -368,11 +373,6 @@ i830_uxa_prepare_copy(PixmapPtr source, PixmapPtr dest, int xdir, i830_get_pixmap_bo(dest), }; - if (!intel_check_pitch_2d(source)) - return FALSE; - if (!intel_check_pitch_2d(dest)) - return FALSE; - if (!i830_get_aperture_space(scrn, bo_table, ARRAY_SIZE(bo_table))) return FALSE; @@ -1076,6 +1076,7 @@ Bool i830_uxa_init(ScreenPtr screen) /* Composite */ if (!IS_I9XX(intel)) { intel->uxa_driver->check_composite = i830_check_composite; + intel->uxa_driver->check_composite_target = i830_check_composite_target; intel->uxa_driver->check_composite_texture = i830_check_composite_texture; intel->uxa_driver->prepare_composite = i830_prepare_composite; intel->uxa_driver->composite = i830_composite; @@ -1083,6 +1084,7 @@ Bool i830_uxa_init(ScreenPtr screen) } else if (IS_I915G(intel) || IS_I915GM(intel) || IS_I945G(intel) || IS_I945GM(intel) || IS_G33CLASS(intel)) { intel->uxa_driver->check_composite = i915_check_composite; + intel->uxa_driver->check_composite_target = i915_check_composite_target; intel->uxa_driver->check_composite_texture = i915_check_composite_texture; intel->uxa_driver->prepare_composite = i915_prepare_composite; intel->uxa_driver->composite = i915_composite; diff --git a/src/i915_render.c b/src/i915_render.c index f9988b91..4eb40466 100644 --- a/src/i915_render.c +++ b/src/i915_render.c @@ -184,7 +184,8 @@ Bool i915_check_composite(int op, PicturePtr source_picture, PicturePtr mask_picture, - PicturePtr dest_picture) + PicturePtr dest_picture, + int width, int height) { ScrnInfoPtr scrn = xf86Screens[dest_picture->pDrawable->pScreen->myNum]; uint32_t tmp1; @@ -216,6 +217,21 @@ i915_check_composite(int op, return FALSE; } + if (width > 2048 || height > 2048) + return FALSE; + + return TRUE; +} + +Bool +i915_check_composite_target(PixmapPtr pixmap) +{ + if (pixmap->drawable.width > 2048 || pixmap->drawable.height > 2048) + return FALSE; + + if(!intel_check_pitch_3d(pixmap)) + return FALSE; + return TRUE; } diff --git a/src/i965_render.c b/src/i965_render.c index ccfc0088..ed4b4d90 100644 --- a/src/i965_render.c +++ b/src/i965_render.c @@ -196,8 +196,11 @@ static Bool i965_get_dest_format(PicturePtr dest_picture, uint32_t * dst_format) } Bool -i965_check_composite(int op, PicturePtr source_picture, PicturePtr mask_picture, - PicturePtr dest_picture) +i965_check_composite(int op, + PicturePtr source_picture, + PicturePtr mask_picture, + PicturePtr dest_picture, + int width, int height) { ScrnInfoPtr scrn = xf86Screens[dest_picture->pDrawable->pScreen->myNum]; intel_screen_private *intel = intel_get_screen_private(scrn); diff --git a/uxa/uxa-accel.c b/uxa/uxa-accel.c index 0528d796..77963f39 100644 --- a/uxa/uxa-accel.c +++ b/uxa/uxa-accel.c @@ -103,7 +103,7 @@ uxa_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int n, goto solid; } - if (!uxa_screen->info->check_composite(PictOpSrc, src, NULL, dst)) { + if (!uxa_screen->info->check_composite(PictOpSrc, src, NULL, dst, 0, 0)) { FreePicture(src, 0); FreePicture(dst, 0); goto solid; @@ -586,17 +586,17 @@ uxa_copy_n_to_n(DrawablePtr pSrcDrawable, int dst_off_x, dst_off_y; PixmapPtr pSrcPixmap, pDstPixmap; - if (uxa_screen->info->check_copy && - !uxa_screen->info->check_copy(pSrcDrawable, pDstDrawable, - pGC ? pGC->alu : GXcopy, - pGC ? pGC->planemask : FB_ALLONES)) - goto fallback; - pSrcPixmap = uxa_get_drawable_pixmap(pSrcDrawable); pDstPixmap = uxa_get_drawable_pixmap(pDstDrawable); if (!pSrcPixmap || !pDstPixmap) goto fallback; + if (uxa_screen->info->check_copy && + !uxa_screen->info->check_copy(pSrcPixmap, pDstPixmap, + pGC ? pGC->alu : GXcopy, + pGC ? pGC->planemask : FB_ALLONES)) + goto fallback; + uxa_get_drawable_deltas(pSrcDrawable, pSrcPixmap, &src_off_x, &src_off_y); uxa_get_drawable_deltas(pDstDrawable, pDstPixmap, &dst_off_x, @@ -1121,20 +1121,16 @@ uxa_fill_region_tiled(DrawablePtr pDrawable, uxa_get_pixmap_first_pixel(pTile), planemask, alu); - if (uxa_screen->info->check_copy && - !uxa_screen->info->check_copy(&pTile->drawable, pDrawable, alu, planemask)) - return FALSE; - - - pPixmap = uxa_get_drawable_pixmap(pDrawable); - uxa_get_drawable_deltas(pDrawable, pPixmap, &xoff, &yoff); - REGION_TRANSLATE(pScreen, pRegion, xoff, yoff); - pPixmap = uxa_get_offscreen_pixmap(pDrawable, &xoff, &yoff); - if (!pPixmap || !uxa_pixmap_is_offscreen(pTile)) goto out; + if (uxa_screen->info->check_copy && + !uxa_screen->info->check_copy(pTile, pPixmap, alu, planemask)) + return FALSE; + + REGION_TRANSLATE(pScreen, pRegion, xoff, yoff); + if ((*uxa_screen->info->prepare_copy) (pTile, pPixmap, 1, 1, alu, planemask)) { while (nbox--) { diff --git a/uxa/uxa-glyphs.c b/uxa/uxa-glyphs.c index 921297a5..93a738ed 100644 --- a/uxa/uxa-glyphs.c +++ b/uxa/uxa-glyphs.c @@ -656,7 +656,7 @@ uxa_glyphs_try_driver_composite(CARD8 op, int nrect; if (uxa_screen->info->check_composite && - !(*uxa_screen->info->check_composite) (op, pSrc, buffer->source, pDst)) { + !(*uxa_screen->info->check_composite) (op, pSrc, buffer->source, pDst, 0, 0)) { return -1; } @@ -787,7 +787,7 @@ uxa_glyphs_try_driver_add_to_mask(PicturePtr pDst, int nrect; if (uxa_screen->info->check_composite && - !(*uxa_screen->info->check_composite) (PictOpAdd, buffer->source, NULL, pDst)) { + !(*uxa_screen->info->check_composite) (PictOpAdd, buffer->source, NULL, pDst, 0, 0)) { return -1; } @@ -1109,13 +1109,12 @@ uxa_glyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, PictFormatPtr maskFormat, - INT16 xSrc, - INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs) + INT16 xSrc, INT16 ySrc, + int nlist, GlyphListPtr list, GlyphPtr * glyphs) { - ScreenPtr pScreen = pDst->pDrawable->pScreen; - uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); - PixmapPtr pMaskPixmap = 0; - PicturePtr pMask; + ScreenPtr screen = pDst->pDrawable->pScreen; + uxa_screen_t *uxa_screen = uxa_get_screen(screen); + PicturePtr pMask = NULL; int width = 0, height = 0; int x, y; int xDst = list->xOff, yDst = list->yOff; @@ -1123,13 +1122,16 @@ uxa_glyphs(CARD8 op, GlyphPtr glyph; int error; BoxRec extents = { 0, 0, 0, 0 }; + Bool have_extents = FALSE; CARD32 component_alpha; uxa_glyph_buffer_t buffer; + PicturePtr localDst = pDst; if (!uxa_screen->info->prepare_composite || uxa_screen->swappedOut || !uxa_drawable_is_offscreen(pDst->pDrawable) || pDst->alphaMap || pSrc->alphaMap) { +fallback: uxa_check_glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs); return; } @@ -1161,55 +1163,129 @@ uxa_glyphs(CARD8 op, } } - if (maskFormat) { - GCPtr pGC; - xRectangle rect; + x = y = 0; + if (!maskFormat && + uxa_screen->info->check_composite_target && + !uxa_screen->info->check_composite_target(uxa_get_drawable_pixmap(pDst->pDrawable))) { + int depth = pDst->pDrawable->depth; + PixmapPtr pixmap; + int error; + GCPtr gc; + + pixmap = uxa_get_drawable_pixmap(pDst->pDrawable); + if (uxa_screen->info->check_copy && + !uxa_screen->info->check_copy(pixmap, pixmap, GXcopy, FB_ALLONES)) + goto fallback; uxa_glyph_extents(nlist, list, glyphs, &extents); + /* clip against dst bounds */ + if (extents.x1 < 0) + extents.x1 = 0; + if (extents.y1 < 0) + extents.y1 = 0; + if (extents.x2 > pDst->pDrawable->width) + extents.x2 = pDst->pDrawable->width; + if (extents.y2 > pDst->pDrawable->height) + extents.y2 = pDst->pDrawable->height; + if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1) return; - width = extents.x2 - extents.x1; + width = extents.x2 - extents.x1; height = extents.y2 - extents.y1; + x = -extents.x1; + y = -extents.y1; + have_extents = TRUE; + + xDst += x; + yDst += y; + + pixmap = screen->CreatePixmap(screen, + width, height, depth, + CREATE_PIXMAP_USAGE_SCRATCH); + if (!pixmap) + return; + + gc = GetScratchGC(depth, screen); + if (!gc) { + screen->DestroyPixmap(pixmap); + return; + } + + ValidateGC(&pixmap->drawable, gc); + gc->ops->CopyArea(pDst->pDrawable, &pixmap->drawable, gc, + extents.x1, extents.y1, + width, height, + 0, 0); + FreeScratchGC(gc); + + localDst = CreatePicture(0, &pixmap->drawable, + PictureMatchFormat(screen, depth, pDst->format), + 0, 0, serverClient, &error); + screen->DestroyPixmap(pixmap); + + if (!localDst) + return; + + ValidatePicture(localDst); + } + + if (maskFormat) { + PixmapPtr pixmap; + GCPtr gc; + xRectangle rect; + + if (!have_extents) { + uxa_glyph_extents(nlist, list, glyphs, &extents); + + if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1) + return; + width = extents.x2 - extents.x1; + height = extents.y2 - extents.y1; + x = -extents.x1; + y = -extents.y1; + have_extents = TRUE; + } if (maskFormat->depth == 1) { PictFormatPtr a8Format = - PictureMatchFormat(pScreen, 8, PICT_a8); + PictureMatchFormat(screen, 8, PICT_a8); if (a8Format) maskFormat = a8Format; } - pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, - maskFormat->depth, - CREATE_PIXMAP_USAGE_SCRATCH); - if (!pMaskPixmap) - return; - component_alpha = NeedsComponent(maskFormat->format); - pMask = CreatePicture(0, &pMaskPixmap->drawable, - maskFormat, CPComponentAlpha, - &component_alpha, serverClient, &error); - if (!pMask) { - (*pScreen->DestroyPixmap) (pMaskPixmap); + pixmap = screen->CreatePixmap(screen, width, height, + maskFormat->depth, + CREATE_PIXMAP_USAGE_SCRATCH); + if (!pixmap) { + if (localDst != pDst) + FreePicture(localDst, 0); return; } - pGC = GetScratchGC(pMaskPixmap->drawable.depth, pScreen); - ValidateGC(&pMaskPixmap->drawable, pGC); + + gc = GetScratchGC(pixmap->drawable.depth, screen); + ValidateGC(&pixmap->drawable, gc); rect.x = 0; rect.y = 0; rect.width = width; rect.height = height; - (*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, - &rect); - FreeScratchGC(pGC); - x = -extents.x1; - y = -extents.y1; + gc->ops->PolyFillRect(&pixmap->drawable, gc, 1, &rect); + FreeScratchGC(gc); + + component_alpha = NeedsComponent(maskFormat->format); + pMask = CreatePicture(0, &pixmap->drawable, + maskFormat, CPComponentAlpha, + &component_alpha, serverClient, &error); + screen->DestroyPixmap(pixmap); + + if (!pMask) { + if (localDst != pDst) + FreePicture(localDst, 0); + return; + } ValidatePicture(pMask); - } else { - pMask = pDst; - x = 0; - y = 0; } buffer.count = 0; @@ -1222,19 +1298,19 @@ uxa_glyphs(CARD8 op, glyph = *glyphs++; if (glyph->info.width > 0 && glyph->info.height > 0 && - uxa_buffer_glyph(pScreen, &buffer, glyph, x, + uxa_buffer_glyph(screen, &buffer, glyph, x, y) == UXA_GLYPH_NEED_FLUSH) { if (maskFormat) uxa_glyphs_to_mask(pMask, &buffer); else - uxa_glyphs_to_dst(op, pSrc, pDst, + uxa_glyphs_to_dst(op, pSrc, localDst, &buffer, xSrc, ySrc, xDst, yDst); buffer.count = 0; buffer.source = NULL; - uxa_buffer_glyph(pScreen, &buffer, glyph, x, y); + uxa_buffer_glyph(screen, &buffer, glyph, x, y); } x += glyph->info.xOff; @@ -1247,20 +1323,41 @@ uxa_glyphs(CARD8 op, if (maskFormat) uxa_glyphs_to_mask(pMask, &buffer); else - uxa_glyphs_to_dst(op, pSrc, pDst, &buffer, + uxa_glyphs_to_dst(op, pSrc, localDst, &buffer, xSrc, ySrc, xDst, yDst); } if (maskFormat) { - x = extents.x1; - y = extents.y1; + if (localDst == pDst) { + x = extents.x1; + y = extents.y1; + } else + x = y = 0; CompositePicture(op, pSrc, pMask, - pDst, + localDst, xSrc + x - xDst, - ySrc + y - yDst, 0, 0, x, y, width, height); - FreePicture((pointer) pMask, (XID) 0); - (*pScreen->DestroyPixmap) (pMaskPixmap); + ySrc + y - yDst, + 0, 0, + x, y, + width, height); + FreePicture(pMask, 0); + } + + if (localDst != pDst) { + GCPtr gc; + + gc = GetScratchGC(pDst->pDrawable->depth, screen); + if (gc) { + ValidateGC(pDst->pDrawable, gc); + gc->ops->CopyArea(localDst->pDrawable, pDst->pDrawable, gc, + 0, 0, + width, height, + extents.x1, extents.y1); + FreeScratchGC(gc); + } + + FreePicture(localDst, 0); } } diff --git a/uxa/uxa-render.c b/uxa/uxa-render.c index c866b854..ec59871b 100644 --- a/uxa/uxa-render.c +++ b/uxa/uxa-render.c @@ -788,7 +788,9 @@ uxa_acquire_drawable(ScreenPtr pScreen, } } - pPixmap = pScreen->CreatePixmap(pScreen, width, height, depth, 0); + pPixmap = pScreen->CreatePixmap(pScreen, + width, height, depth, + CREATE_PIXMAP_USAGE_SCRATCH); if (!pPixmap) return 0; @@ -935,7 +937,7 @@ uxa_solid_rects (CARD8 op, uxa_screen_t *uxa_screen = uxa_get_screen(screen); PixmapPtr dst_pixmap, src_pixmap = NULL; pixman_region16_t region; - pixman_box16_t *boxes; + pixman_box16_t *boxes, *extents; PicturePtr src; int dst_x, dst_y; int num_boxes; @@ -960,6 +962,7 @@ uxa_solid_rects (CARD8 op, pixman_region_translate(®ion, dst_x, dst_y); boxes = pixman_region_rectangles(®ion, &num_boxes); + extents = pixman_region_extents (®ion); if (op == PictOpClear) color->red = color->green = color->blue = color->alpha = 0; @@ -970,6 +973,7 @@ uxa_solid_rects (CARD8 op, if (num_boxes == 1 && (op == PictOpSrc || op == PictOpClear)) { CARD32 pixel; +try_solid: if (uxa_screen->info->check_solid && !uxa_screen->info->check_solid(&dst_pixmap->drawable, GXcopy, FB_ALLONES)) goto err_region; @@ -985,9 +989,12 @@ uxa_solid_rects (CARD8 op, if (!uxa_screen->info->prepare_solid(dst_pixmap, GXcopy, FB_ALLONES, pixel)) goto err_region; - uxa_screen->info->solid(dst_pixmap, - boxes->x1, boxes->y1, - boxes->x2, boxes->y2); + while (num_boxes--) { + uxa_screen->info->solid(dst_pixmap, + boxes->x1, boxes->y1, + boxes->x2, boxes->y2); + boxes++; + } uxa_screen->info->done_solid(dst_pixmap); } else { @@ -997,8 +1004,16 @@ uxa_solid_rects (CARD8 op, if (!src) goto err_region; - if (!uxa_screen->info->check_composite(op, src, NULL, dst)) + if (!uxa_screen->info->check_composite(op, src, NULL, dst, + extents->x2 - extents->x1, + extents->y2 - extents->y1)) { + if (op == PictOpSrc || op == PictOpClear) { + FreePicture(src, 0); + goto try_solid; + } + goto err_src; + } if (!uxa_screen->info->check_composite_texture || !uxa_screen->info->check_composite_texture(screen, src)) { @@ -1053,53 +1068,109 @@ uxa_try_driver_composite(CARD8 op, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) { - uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); + ScreenPtr screen = pDst->pDrawable->pScreen; + uxa_screen_t *uxa_screen = uxa_get_screen(screen); RegionRec region; BoxPtr pbox; int nbox; + int xDst_copy, yDst_copy; int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y; PixmapPtr pSrcPix, pMaskPix = NULL, pDstPix; PicturePtr localSrc, localMask = NULL; + PicturePtr localDst = pDst; if (uxa_screen->info->check_composite && - !(*uxa_screen->info->check_composite) (op, pSrc, pMask, pDst)) + !(*uxa_screen->info->check_composite) (op, pSrc, pMask, pDst, width, height)) return -1; + if (uxa_screen->info->check_composite_target && + !uxa_screen->info->check_composite_target(uxa_get_drawable_pixmap(pDst->pDrawable))) { + int depth = pDst->pDrawable->depth; + PixmapPtr pixmap; + int error; + GCPtr gc; + + pixmap = uxa_get_drawable_pixmap(pDst->pDrawable); + if (uxa_screen->info->check_copy && + !uxa_screen->info->check_copy(pixmap, pixmap, GXcopy, FB_ALLONES)) + return -1; + + pixmap = screen->CreatePixmap(screen, + width, height, depth, + CREATE_PIXMAP_USAGE_SCRATCH); + if (!pixmap) + return 0; + + gc = GetScratchGC(depth, screen); + if (!gc) { + screen->DestroyPixmap(pixmap); + return 0; + } + + ValidateGC(&pixmap->drawable, gc); + gc->ops->CopyArea(pDst->pDrawable, &pixmap->drawable, gc, + xDst, yDst, width, height, 0, 0); + FreeScratchGC(gc); + + xDst_copy = xDst; xDst = 0; + yDst_copy = yDst; yDst = 0; + + localDst = CreatePicture(0, &pixmap->drawable, + PictureMatchFormat(screen, depth, pDst->format), + 0, 0, serverClient, &error); + screen->DestroyPixmap(pixmap); + + if (!localDst) + return 0; + + ValidatePicture(localDst); + } + pDstPix = - uxa_get_offscreen_pixmap(pDst->pDrawable, &dst_off_x, &dst_off_y); - if (!pDstPix) + uxa_get_offscreen_pixmap(localDst->pDrawable, &dst_off_x, &dst_off_y); + if (!pDstPix) { + if (localDst != pDst) + FreePicture(localDst, 0); return -1; + } - xDst += pDst->pDrawable->x; - yDst += pDst->pDrawable->y; + xDst += localDst->pDrawable->x; + yDst += localDst->pDrawable->y; - localSrc = uxa_acquire_source(pDst->pDrawable->pScreen, pSrc, + localSrc = uxa_acquire_source(screen, pSrc, xSrc, ySrc, width, height, &xSrc, &ySrc); - if (!localSrc) + if (!localSrc) { + if (localDst != pDst) + FreePicture(localDst, 0); return 0; + } if (pMask) { - localMask = uxa_acquire_mask(pDst->pDrawable->pScreen, pMask, + localMask = uxa_acquire_mask(screen, pMask, xMask, yMask, width, height, &xMask, &yMask); if (!localMask) { if (localSrc != pSrc) FreePicture(localSrc, 0); + if (localDst != pDst) + FreePicture(localDst, 0); return 0; } } - if (!miComputeCompositeRegion(®ion, localSrc, localMask, pDst, + if (!miComputeCompositeRegion(®ion, localSrc, localMask, localDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height)) { if (localSrc != pSrc) FreePicture(localSrc, 0); if (localMask && localMask != pMask) FreePicture(localMask, 0); + if (localDst != pDst) + FreePicture(localDst, 0); return 1; } @@ -1108,12 +1179,14 @@ uxa_try_driver_composite(CARD8 op, pSrcPix = uxa_get_offscreen_pixmap(localSrc->pDrawable, &src_off_x, &src_off_y); if (!pSrcPix) { - REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + REGION_UNINIT(screen, ®ion); if (localSrc != pSrc) FreePicture(localSrc, 0); if (localMask && localMask != pMask) FreePicture(localMask, 0); + if (localDst != pDst) + FreePicture(localDst, 0); return 0; } @@ -1126,12 +1199,14 @@ uxa_try_driver_composite(CARD8 op, pMaskPix = uxa_get_offscreen_pixmap(localMask->pDrawable, &mask_off_x, &mask_off_y); if (!pMaskPix) { - REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + REGION_UNINIT(screen, ®ion); if (localSrc != pSrc) FreePicture(localSrc, 0); if (localMask && localMask != pMask) FreePicture(localMask, 0); + if (localDst != pDst) + FreePicture(localDst, 0); return 0; } @@ -1141,13 +1216,15 @@ uxa_try_driver_composite(CARD8 op, } if (!(*uxa_screen->info->prepare_composite) - (op, localSrc, localMask, pDst, pSrcPix, pMaskPix, pDstPix)) { - REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + (op, localSrc, localMask, localDst, pSrcPix, pMaskPix, pDstPix)) { + REGION_UNINIT(screen, ®ion); if (localSrc != pSrc) FreePicture(localSrc, 0); if (localMask && localMask != pMask) FreePicture(localMask, 0); + if (localDst != pDst) + FreePicture(localDst, 0); return -1; } @@ -1176,13 +1253,27 @@ uxa_try_driver_composite(CARD8 op, } (*uxa_screen->info->done_composite) (pDstPix); - REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + REGION_UNINIT(screen, ®ion); if (localSrc != pSrc) FreePicture(localSrc, 0); if (localMask && localMask != pMask) FreePicture(localMask, 0); + if (localDst != pDst) { + GCPtr gc; + + gc = GetScratchGC(pDst->pDrawable->depth, screen); + if (gc) { + ValidateGC(pDst->pDrawable, gc); + gc->ops->CopyArea(localDst->pDrawable, pDst->pDrawable, gc, + 0, 0, width, height, xDst_copy, yDst_copy); + FreeScratchGC(gc); + } + + FreePicture(localDst, 0); + } + return 1; } @@ -1240,36 +1331,100 @@ uxa_try_magic_two_pass_composite_helper(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, - INT16 xSrc, - INT16 ySrc, - INT16 xMask, - INT16 yMask, - INT16 xDst, - INT16 yDst, CARD16 width, CARD16 height) + INT16 xSrc, INT16 ySrc, + INT16 xMask, INT16 yMask, + INT16 xDst, INT16 yDst, + CARD16 width, CARD16 height) { - uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); + ScreenPtr screen = pDst->pDrawable->pScreen; + uxa_screen_t *uxa_screen = uxa_get_screen(screen); + PicturePtr localDst = pDst; + int xDst_copy, yDst_copy; assert(op == PictOpOver); if (uxa_screen->info->check_composite && (!(*uxa_screen->info->check_composite) (PictOpOutReverse, pSrc, - pMask, pDst) + pMask, pDst, width, height) || !(*uxa_screen->info->check_composite) (PictOpAdd, pSrc, pMask, - pDst))) { + pDst, width, height))) { return -1; } + if (uxa_screen->info->check_composite_target && + !uxa_screen->info->check_composite_target(uxa_get_drawable_pixmap(pDst->pDrawable))) { + int depth = pDst->pDrawable->depth; + PixmapPtr pixmap; + int error; + GCPtr gc; + + pixmap = uxa_get_drawable_pixmap(pDst->pDrawable); + if (uxa_screen->info->check_copy && + !uxa_screen->info->check_copy(pixmap, pixmap, GXcopy, FB_ALLONES)) + return -1; + + pixmap = screen->CreatePixmap(screen, + width, height, depth, + CREATE_PIXMAP_USAGE_SCRATCH); + if (!pixmap) + return 0; + + gc = GetScratchGC(depth, screen); + if (!gc) { + screen->DestroyPixmap(pixmap); + return 0; + } + + ValidateGC(&pixmap->drawable, gc); + gc->ops->CopyArea(pDst->pDrawable, &pixmap->drawable, gc, + xDst, yDst, width, height, 0, 0); + FreeScratchGC(gc); + + xDst_copy = xDst; xDst = 0; + yDst_copy = yDst; yDst = 0; + + localDst = CreatePicture(0, &pixmap->drawable, + PictureMatchFormat(screen, depth, pDst->format), + 0, 0, serverClient, &error); + screen->DestroyPixmap(pixmap); + + if (!localDst) + return 0; + + ValidatePicture(localDst); + } + /* Now, we think we should be able to accelerate this operation. First, * composite the destination to be the destination times the source alpha * factors. */ - uxa_composite(PictOpOutReverse, pSrc, pMask, pDst, xSrc, ySrc, xMask, - yMask, xDst, yDst, width, height); + uxa_composite(PictOpOutReverse, pSrc, pMask, localDst, + xSrc, ySrc, + xMask, yMask, + xDst, yDst, + width, height); /* Then, add in the source value times the destination alpha factors (1.0). */ - uxa_composite(PictOpAdd, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, - xDst, yDst, width, height); + uxa_composite(PictOpAdd, pSrc, pMask, localDst, + xSrc, ySrc, + xMask, yMask, + xDst, yDst, + width, height); + + if (localDst != pDst) { + GCPtr gc; + + gc = GetScratchGC(pDst->pDrawable->depth, screen); + if (gc) { + ValidateGC(pDst->pDrawable, gc); + gc->ops->CopyArea(localDst->pDrawable, pDst->pDrawable, gc, + 0, 0, width, height, xDst_copy, yDst_copy); + FreeScratchGC(gc); + } + + FreePicture(localDst, 0); + } return 1; } @@ -1325,10 +1480,10 @@ uxa_composite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, - INT16 xSrc, - INT16 ySrc, - INT16 xMask, - INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) + INT16 xSrc, INT16 ySrc, + INT16 xMask, INT16 yMask, + INT16 xDst, INT16 yDst, + CARD16 width, CARD16 height) { uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen); int ret = -1; @@ -1343,9 +1498,11 @@ uxa_composite(CARD8 op, if (!uxa_drawable_is_offscreen(pDst->pDrawable)) goto fallback; + if (pDst->alphaMap || pSrc->alphaMap || (pMask && pMask->alphaMap)) goto fallback; + /* Remove repeat in source if useless */ if (pSrc->pDrawable && pSrc->repeat && pSrc->filter != PictFilterConvolution && transform_is_integer_translation(pSrc->transform, &tx, &ty) && diff --git a/uxa/uxa.h b/uxa/uxa.h index bf7ec0b5..23f9465b 100644 --- a/uxa/uxa.h +++ b/uxa/uxa.h @@ -151,9 +151,7 @@ typedef struct _UxaDriver { /** * check_copy() checks whether the driver can blit between the two Pictures */ - Bool(*check_copy) (DrawablePtr pSrcDrawable, - DrawablePtr pDstDrawable, - int alu, Pixel planemask); + Bool(*check_copy) (PixmapPtr pSrc, PixmapPtr pDst, int alu, Pixel planemask); /** * prepare_copy() sets up the driver for doing a copy within video * memory. @@ -249,6 +247,8 @@ typedef struct _UxaDriver { * @param pSrcPicture source Picture * @param pMaskPicture mask picture * @param pDstPicture destination Picture + * @param width The width of the composite operation + * @param height The height of the composite operation * * The check_composite() call checks if the driver could handle * acceleration of op with the given source, mask, and destination @@ -266,7 +266,19 @@ typedef struct _UxaDriver { Bool(*check_composite) (int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, - PicturePtr pDstPicture); + PicturePtr pDstPicture, + int width, int height); + + /** + * check_composite_target() checks to see if the destination of the composite + * operation can be used without midification. + * + * @param pixmap Destination Pixmap + * + * The check_composite_target() call is recommended if prepare_composite() is + * implemented, but is not required. + */ + Bool(*check_composite_target) (PixmapPtr pixmap); /** * check_composite_texture() checks to see if a source to the composite