diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2011-04-08 07:17:14 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2011-06-04 09:19:46 +0100 |
commit | bcef98af561939aa48d9236b2dfa2c5626adf4cb (patch) | |
tree | 9d05558947a97595a6fdece968b50eeae45bbfb1 /src/sna/sna_composite.c | |
parent | 340cfb7f5271fd1df4c8948e5c9336f5b69a6e6c (diff) |
sna: Introduce a new acceleration model.
The premise is that switching between rings (i.e. the BLT and
RENDER rings) on SandyBridge imposes a large latency overhead whilst
rendering. The cause is that in order to switch rings, we need to split
the batch earlier than is desired and to add serialisation between the
rings. Both of which incur large overhead.
By switching to using a pure 3D blit engine (ok, not so pure as the BLT
engine still has uses for the core drawing model which can not be easily
represented without a combinatorial explosion of shaders) we can take
advantage of additional efficiencies, such as relative relocations, that
have been incorporated into recent hardware advances. However, even
older hardware performs better from avoiding the implicit context
switches and from the batching efficiency of the 3D pipeline...
But this is X, and PolyGlyphBlt still exists and remains in use. So for
the operations that are not worth accelerating in hardware, we introduce a
shadow buffer mechanism through out and reintroduce pixmap migration.
Doing this efficiently is the cornerstone of ensuring that we do exploit
the increased potential of recent hardware for running old applications and
environments (i.e. so that the latest and greatest chip is actually faster
than gen2!)
For the curious, sna is SandyBridge's New Acceleration. If you are
running older chipsets and welcome the performance increase offered by
this patch, then you may choose to call it Snazzy instead.
Speedups
========
gen3 firefox-fishtank 1203584.56 (1203842.75 0.01%) -> 85561.71 (125146.44 14.87%): 14.07x speedup
gen5 grads-heat-map 3385.42 (3489.73 1.44%) -> 350.29 (350.75 0.18%): 9.66x speedup
gen3 xfce4-terminal-a1 4179.02 (4180.09 0.06%) -> 503.90 (531.88 4.48%): 8.29x speedup
gen4 grads-heat-map 2458.66 (2826.34 4.64%) -> 348.82 (349.20 0.29%): 7.05x speedup
gen3 grads-heat-map 1443.33 (1445.32 0.09%) -> 298.55 (298.76 0.05%): 4.83x speedup
gen3 swfdec-youtube 3836.14 (3894.14 0.95%) -> 889.84 (979.56 5.99%): 4.31x speedup
gen6 grads-heat-map 742.11 (744.44 0.15%) -> 172.51 (172.93 0.20%): 4.30x speedup
gen3 firefox-talos-svg 71740.44 (72370.13 0.59%) -> 21959.29 (21995.09 0.68%): 3.27x speedup
gen5 gvim 8045.51 (8071.47 0.17%) -> 2589.38 (3246.78 10.74%): 3.11x speedup
gen6 poppler 3800.78 (3817.92 0.24%) -> 1227.36 (1230.12 0.30%): 3.10x speedup
gen6 gnome-terminal-vim 9106.84 (9111.56 0.03%) -> 3459.49 (3478.52 0.25%): 2.63x speedup
gen5 midori-zoomed 9564.53 (9586.58 0.17%) -> 3677.73 (3837.02 2.02%): 2.60x speedup
gen5 gnome-terminal-vim 38167.25 (38215.82 0.08%) -> 14901.09 (14902.28 0.01%): 2.56x speedup
gen5 poppler 13575.66 (13605.04 0.16%) -> 5554.27 (5555.84 0.01%): 2.44x speedup
gen5 swfdec-giant-steps 8941.61 (8988.72 0.52%) -> 3851.98 (3871.01 0.93%): 2.32x speedup
gen5 xfce4-terminal-a1 18956.60 (18986.90 0.07%) -> 8362.75 (8365.70 0.01%): 2.27x speedup
gen5 firefox-fishtank 88750.31 (88858.23 0.14%) -> 39164.57 (39835.54 0.80%): 2.27x speedup
gen3 midori-zoomed 2392.13 (2397.82 0.14%) -> 1109.96 (1303.10 30.35%): 2.16x speedup
gen6 gvim 2510.34 (2513.34 0.20%) -> 1200.76 (1204.30 0.22%): 2.09x speedup
gen5 firefox-planet-gnome 40478.16 (40565.68 0.09%) -> 19606.22 (19648.79 0.16%): 2.06x speedup
gen5 gnome-system-monitor 10344.47 (10385.62 0.29%) -> 5136.69 (5256.85 1.15%): 2.01x speedup
gen3 poppler 2595.23 (2603.10 0.17%) -> 1297.56 (1302.42 0.61%): 2.00x speedup
gen6 firefox-talos-gfx 7184.03 (7194.97 0.13%) -> 3806.31 (3811.66 0.06%): 1.89x speedup
gen5 evolution 8739.25 (8766.12 0.27%) -> 4817.54 (5050.96 1.54%): 1.81x speedup
gen3 evolution 1684.06 (1696.88 0.35%) -> 1004.99 (1008.55 0.85%): 1.68x speedup
gen3 gnome-terminal-vim 4285.13 (4287.68 0.04%) -> 2715.97 (3202.17 13.52%): 1.58x speedup
gen5 swfdec-youtube 5843.94 (5951.07 0.91%) -> 3810.86 (3826.04 1.32%): 1.53x speedup
gen4 poppler 7496.72 (7558.83 0.58%) -> 5125.08 (5247.65 1.44%): 1.46x speedup
gen4 gnome-terminal-vim 21126.24 (21292.08 0.85%) -> 14590.25 (15066.33 1.80%): 1.45x speedup
gen5 firefox-talos-svg 99873.69 (100300.95 0.37%) -> 70745.66 (70818.86 0.05%): 1.41x speedup
gen4 firefox-planet-gnome 28205.10 (28304.45 0.27%) -> 19996.11 (20081.44 0.56%): 1.41x speedup
gen5 firefox-talos-gfx 93070.85 (93194.72 0.10%) -> 67687.93 (70374.37 1.30%): 1.37x speedup
gen4 evolution 6696.25 (6854.14 0.85%) -> 4958.62 (5027.73 0.85%): 1.35x speedup
gen3 swfdec-giant-steps 2538.03 (2539.30 0.04%) -> 1895.71 (2050.62 62.43%): 1.34x speedup
gen4 gvim 4356.18 (4422.78 0.70%) -> 3276.31 (3281.69 0.13%): 1.33x speedup
gen6 evolution 1242.13 (1245.44 0.72%) -> 953.76 (954.54 0.07%): 1.30x speedup
gen6 firefox-planet-gnome 4554.23 (4560.69 0.08%) -> 3758.76 (3768.97 0.28%): 1.21x speedup
gen3 firefox-talos-gfx 6264.13 (6284.65 0.30%) -> 5261.56 (5370.87 1.28%): 1.19x speedup
gen4 midori-zoomed 4771.13 (4809.90 0.73%) -> 4037.03 (4118.93 0.85%): 1.18x speedup
gen6 swfdec-giant-steps 1557.06 (1560.13 0.12%) -> 1336.34 (1341.29 0.32%): 1.17x speedup
gen4 firefox-talos-gfx 80767.28 (80986.31 0.17%) -> 69629.08 (69721.71 0.06%): 1.16x speedup
gen6 midori-zoomed 1463.70 (1463.76 0.08%) -> 1331.45 (1336.56 0.22%): 1.10x speedup
Slowdowns
=========
gen6 xfce4-terminal-a1 2030.25 (2036.23 0.25%) -> 2144.60 (2240.31 4.29%): 1.06x slowdown
gen4 swfdec-youtube 3580.00 (3597.23 3.92%) -> 3826.90 (3862.24 0.91%): 1.07x slowdown
gen4 firefox-talos-svg 66112.25 (66256.51 0.11%) -> 71433.40 (71584.31 0.14%): 1.08x slowdown
gen4 gnome-system-monitor 5691.60 (5724.03 0.56%) -> 6707.56 (6747.83 0.33%): 1.18x slowdown
gen3 ocitysmap 3494.05 (3502.44 0.20%) -> 4321.99 (4524.42 2.78%): 1.24x slowdown
gen4 ocitysmap 3628.42 (3641.66 9.37%) -> 5177.16 (5828.74 8.38%): 1.43x slowdown
gen5 ocitysmap 4027.77 (4068.11 0.80%) -> 5748.26 (6282.25 7.38%): 1.43x slowdown
gen6 ocitysmap 1401.61 (1402.24 0.40%) -> 2365.74 (2379.14 4.12%): 1.69x slowdown
[Note the performance regression for ocitysmap comes from that we now
attempt to support rendering to and (more importantly) from large
surfaces. By enabling such operations is the only way to one day be
faster than purely using the CPU, in the meantime we suffer regression
due to the increased migration and aperture thrashing. The other couple
of regressions will be eliminated with improved span and shader support,
now that the framework for such is in place.]
The performance increase for Cairo completely overlooks the other
critical aspects of the architecture:
World of Padman:
gen3 (800x600): 57.5 -> 96.2
gen4 (800x600): 47.8 -> 74.6
gen6 (1366x768): 100.4 -> 140.3 [F15]
144.3 -> 146.4 [drm-intel-next]
x11perf (gen6);
aa10text: 3.47 -> 14.3 Mglyphs/s [unthrottled!]
copywinwin10: 1.66 -> 1.99 Mops/s
copywinpix10: 2.28 -> 2.98 Mops/s
And we do not have a good measure for how much improvement the reworking
of the fallback paths give, except that xterm is now over 4x faster...
PS: This depends upon the Xorg patchset "Remove the cacheing of the last
scratch PixmapRec" for correct invalidations of scratch Pixmaps (used by
the dix to implement SHM operations, used by chromium and gtk+ pixbufs.
PPS: ./configure --enable-sna
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'src/sna/sna_composite.c')
-rw-r--r-- | src/sna/sna_composite.c | 722 |
1 files changed, 722 insertions, 0 deletions
diff --git a/src/sna/sna_composite.c b/src/sna/sna_composite.c new file mode 100644 index 00000000..27b1ff3c --- /dev/null +++ b/src/sna/sna_composite.c @@ -0,0 +1,722 @@ +/* + * Copyright (c) 2011 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Chris Wilson <chris@chris-wilson.co.uk> + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "sna.h" +#include "sna_render.h" +#include "sna_render_inline.h" + +#include <mipict.h> +#include <fbpict.h> + +#if DEBUG_COMPOSITE +#undef DBG +#define DBG(x) ErrorF x +#else +#define NDEBUG 1 +#endif + +static void dst_move_area_to_cpu(PicturePtr picture, + uint8_t op, + int x, int y, + int width, int height) +{ + RegionRec area; + BoxRec box; + + DBG(("%s: (%d, %d), (%d %d)\n", __FUNCTION__, x, y, width, height)); + + box.x1 = x; + box.y1 = y; + box.x2 = x + width; + box.y2 = y + height; + RegionInit(&area, &box, 1); + if (picture->pCompositeClip) + RegionIntersect(&area, &area, picture->pCompositeClip); + sna_drawable_move_region_to_cpu(picture->pDrawable, &area, true); + RegionUninit(&area); +} + +#define BOUND(v) (INT16) ((v) < MINSHORT ? MINSHORT : (v) > MAXSHORT ? MAXSHORT : (v)) + +static inline pixman_bool_t +clip_to_dst(pixman_region16_t *region, + pixman_region16_t *clip, + int dx, + int dy) +{ + DBG(("%s: region: %dx[(%d, %d), (%d, %d)], clip: %dx[(%d, %d), (%d, %d)]\n", + __FUNCTION__, + pixman_region_n_rects(region), + region->extents.x1, region->extents.y1, + region->extents.x2, region->extents.y2, + pixman_region_n_rects(clip), + clip->extents.x1, clip->extents.y1, + clip->extents.x2, clip->extents.y2)); + + if (pixman_region_n_rects(region) == 1 && + pixman_region_n_rects(clip) == 1) { + pixman_box16_t *r = pixman_region_rectangles(region, NULL); + pixman_box16_t *c = pixman_region_rectangles(clip, NULL); + int v; + + if (r->x1 < (v = c->x1 + dx)) + r->x1 = BOUND(v); + if (r->x2 > (v = c->x2 + dx)) + r->x2 = BOUND(v); + if (r->y1 < (v = c->y1 + dy)) + r->y1 = BOUND(v); + if (r->y2 > (v = c->y2 + dy)) + r->y2 = BOUND(v); + + if (r->x1 >= r->x2 || r->y1 >= r->y2) + pixman_region_init(region); + } else if (!pixman_region_not_empty(clip)) { + return FALSE; + } else { + if (dx || dy) + pixman_region_translate(region, -dx, -dy); + if (!pixman_region_intersect(region, region, clip)) + return FALSE; + if (dx || dy) + pixman_region_translate(region, dx, dy); + } + return pixman_region_not_empty(region); +} + +static inline Bool +clip_to_src(RegionPtr region, PicturePtr p, int dx, int dy) +{ + Bool result; + + if (p->clientClipType == CT_NONE) + return TRUE; + + pixman_region_translate(p->clientClip, + p->clipOrigin.x + dx, + p->clipOrigin.y + dy); + + result = RegionIntersect(region, region, p->clientClip); + + pixman_region_translate(p->clientClip, + -(p->clipOrigin.x + dx), + -(p->clipOrigin.y + dy)); + + return result && pixman_region_not_empty(region); +} + +Bool +sna_compute_composite_region(RegionPtr region, + PicturePtr src, PicturePtr mask, PicturePtr dst, + INT16 src_x, INT16 src_y, + INT16 mask_x, INT16 mask_y, + INT16 dst_x, INT16 dst_y, + CARD16 width, CARD16 height) +{ + int v; + + DBG(("%s: dst=(%d, %d)x(%d, %d)\n", + __FUNCTION__, + dst_x, dst_y, + width, height)); + + region->extents.x1 = dst_x < 0 ? 0 : dst_x; + v = dst_x + width; + if (v > dst->pDrawable->width) + v = dst->pDrawable->width; + region->extents.x2 = v; + + region->extents.y1 = dst_y < 0 ? 0 : dst_y; + v = dst_y + height; + if (v > dst->pDrawable->height) + v = dst->pDrawable->height; + region->extents.y2 = v; + + region->data = 0; + + DBG(("%s: initial clip against dst->pDrawable: (%d, %d), (%d, %d)\n", + __FUNCTION__, + region->extents.x1, region->extents.y1, + region->extents.x2, region->extents.y2)); + + if (region->extents.x1 >= region->extents.x2 || + region->extents.y1 >= region->extents.y2) + return FALSE; + + region->extents.x1 += dst->pDrawable->x; + region->extents.x2 += dst->pDrawable->x; + region->extents.y1 += dst->pDrawable->y; + region->extents.y2 += dst->pDrawable->y; + + dst_x += dst->pDrawable->x; + dst_y += dst->pDrawable->y; + + /* clip against dst */ + if (!clip_to_dst(region, dst->pCompositeClip, 0, 0)) + return FALSE; + + DBG(("%s: clip against dst->pCompositeClip: (%d, %d), (%d, %d)\n", + __FUNCTION__, + region->extents.x1, region->extents.y1, + region->extents.x2, region->extents.y2)); + + if (dst->alphaMap) { + if (!clip_to_dst(region, dst->alphaMap->pCompositeClip, + -dst->alphaOrigin.x, + -dst->alphaOrigin.y)) { + pixman_region_fini (region); + return FALSE; + } + } + + /* clip against src */ + if (src->pDrawable) { + src_x += src->pDrawable->x; + src_y += src->pDrawable->y; + } + if (!clip_to_src(region, src, dst_x - src_x, dst_y - src_y)) { + pixman_region_fini (region); + return FALSE; + } + DBG(("%s: clip against src: (%d, %d), (%d, %d)\n", + __FUNCTION__, + region->extents.x1, region->extents.y1, + region->extents.x2, region->extents.y2)); + + if (src->alphaMap) { + if (!clip_to_src(region, src->alphaMap, + dst_x - (src_x - src->alphaOrigin.x), + dst_y - (src_y - src->alphaOrigin.y))) { + pixman_region_fini(region); + return FALSE; + } + } + + /* clip against mask */ + if (mask) { + if (mask->pDrawable) { + mask_x += mask->pDrawable->x; + mask_y += mask->pDrawable->y; + } + if (!clip_to_src(region, mask, dst_x - mask_x, dst_y - mask_y)) { + pixman_region_fini(region); + return FALSE; + } + if (mask->alphaMap) { + if (!clip_to_src(region, mask->alphaMap, + dst_x - (mask_x - mask->alphaOrigin.x), + dst_y - (mask_y - mask->alphaOrigin.y))) { + pixman_region_fini(region); + return FALSE; + } + } + + DBG(("%s: clip against mask: (%d, %d), (%d, %d)\n", + __FUNCTION__, + region->extents.x1, region->extents.y1, + region->extents.x2, region->extents.y2)); + } + + return pixman_region_not_empty(region); +} + +static void +trim_extents(BoxPtr extents, const PicturePtr p, int dx, int dy) +{ + const BoxPtr box = REGION_EXTENTS(NULL, p->pCompositeClip); + + DBG(("%s: trim((%d, %d), (%d, %d)) against ((%d, %d), (%d, %d)) + (%d, %d)\n", + __FUNCTION__, + extents->x1, extents->y1, extents->x2, extents->y2, + box->x1, box->y1, box->x2, box->y2, + dx, dy)); + + if (extents->x1 < box->x1 + dx) + extents->x1 = box->x1 + dx; + if (extents->x2 > box->x2 + dx) + extents->x2 = box->x2 + dx; + + if (extents->y1 < box->y1 + dy) + extents->y1 = box->y1 + dy; + if (extents->y2 > box->y2 + dy) + extents->y2 = box->y2 + dy; +} + +static void +_trim_source_extents(BoxPtr extents, const PicturePtr p, int dx, int dy) +{ + if (p->clientClipType != CT_NONE) + trim_extents(extents, p, dx, dy); +} + +static void +trim_source_extents(BoxPtr extents, const PicturePtr p, int dx, int dy) +{ + if (p->pDrawable) { + dx += p->pDrawable->x; + dy += p->pDrawable->y; + } + _trim_source_extents(extents, p, dx, dy); + if (p->alphaMap) + _trim_source_extents(extents, p->alphaMap, + dx - p->alphaOrigin.x, + dy - p->alphaOrigin.y); + + DBG(("%s: -> (%d, %d), (%d, %d)\n", + __FUNCTION__, + extents->x1, extents->y1, + extents->x2, extents->y2)); +} + +Bool +sna_compute_composite_extents(BoxPtr extents, + PicturePtr src, PicturePtr mask, PicturePtr dst, + INT16 src_x, INT16 src_y, + INT16 mask_x, INT16 mask_y, + INT16 dst_x, INT16 dst_y, + CARD16 width, CARD16 height) +{ + int v; + + DBG(("%s: dst=(%d, %d)x(%d, %d)\n", + __FUNCTION__, + dst_x, dst_y, + width, height)); + + extents->x1 = dst_x < 0 ? 0 : dst_x; + v = dst_x + width; + if (v > dst->pDrawable->width) + v = dst->pDrawable->width; + extents->x2 = v; + + extents->y1 = dst_y < 0 ? 0 : dst_y; + v = dst_y + height; + if (v > dst->pDrawable->height) + v = dst->pDrawable->height; + + DBG(("%s: initial clip against dst->pDrawable: (%d, %d), (%d, %d)\n", + __FUNCTION__, + extents->x1, extents->y1, + extents->x2, extents->y2)); + + if (extents->x1 >= extents->x2 || + extents->y1 >= extents->y2) + return FALSE; + + extents->x1 += dst->pDrawable->x; + extents->x2 += dst->pDrawable->x; + extents->y1 += dst->pDrawable->y; + extents->y2 += dst->pDrawable->y; + + dst_x += dst->pDrawable->x; + dst_y += dst->pDrawable->y; + + /* clip against dst */ + trim_extents(extents, dst, 0, 0); + if (dst->alphaMap) + trim_extents(extents, dst->alphaMap, + -dst->alphaOrigin.x, + -dst->alphaOrigin.y); + + DBG(("%s: clip against dst: (%d, %d), (%d, %d)\n", + __FUNCTION__, + extents->x1, extents->y1, + extents->x2, extents->y2)); + + trim_source_extents(extents, src, dst_x - src_x, dst_y - src_y); + if (mask) + trim_source_extents(extents, mask, + dst_x - mask_x, dst_y - mask_y); + + return extents->x1 < extents->x2 && extents->y1 < extents->y2; +} + +#if DEBUG_COMPOSITE +static void _assert_pixmap_contains_box(PixmapPtr pixmap, BoxPtr box, const char *function) +{ + if (box->x1 < 0 || box->y1 < 0 || + box->x2 > pixmap->drawable.width || + box->y2 > pixmap->drawable.height) + { + ErrorF("%s: damage box is beyond the pixmap: box=(%d, %d), (%d, %d), pixmap=(%d, %d)\n", + __FUNCTION__, + box->x1, box->y1, box->x2, box->y2, + pixmap->drawable.width, + pixmap->drawable.height); + assert(0); + } +} +#define assert_pixmap_contains_box(p, b) _assert_pixmap_contains_box(p, b, __FUNCTION__) +#else +#define assert_pixmap_contains_box(p, b) +#endif + +static void apply_damage(struct sna_composite_op *op, RegionPtr region) +{ + DBG(("%s: damage=%p, region=%d\n", + __FUNCTION__, op->damage, REGION_NUM_RECTS(region))); + + if (op->damage == NULL) + return; + + RegionTranslate(region, op->dst.x, op->dst.y); + + assert_pixmap_contains_box(op->dst.pixmap, RegionExtents(region)); + sna_damage_add(op->damage, region); +} + +void +sna_composite(CARD8 op, + PicturePtr src, + PicturePtr mask, + PicturePtr dst, + INT16 src_x, INT16 src_y, + INT16 mask_x, INT16 mask_y, + INT16 dst_x, INT16 dst_y, + CARD16 width, CARD16 height) +{ + struct sna *sna = to_sna_from_drawable(dst->pDrawable); + struct sna_composite_op tmp; + RegionRec region; + + DBG(("%s(%d src=(%d, %d), mask=(%d, %d), dst=(%d, %d)+(%d, %d), size=(%d, %d)\n", + __FUNCTION__, op, + src_x, src_y, + mask_x, mask_y, + dst_x, dst_y, dst->pDrawable->x, dst->pDrawable->y, + width, height)); + + if (sna->kgem.wedged) { + DBG(("%s: fallback -- wedged\n", __FUNCTION__)); + goto fallback; + } + + if (dst->alphaMap || src->alphaMap || (mask && mask->alphaMap)) { + DBG(("%s: fallback due to unhandled alpha-map\n", __FUNCTION__)); + goto fallback; + } + + if (too_small(sna, dst->pDrawable) && + !picture_is_gpu(src) && !picture_is_gpu(mask)) { + DBG(("%s: fallback due to too small\n", __FUNCTION__)); + goto fallback; + } + + if (!sna_compute_composite_region(®ion, + src, mask, dst, + src_x, src_y, + mask_x, mask_y, + dst_x, dst_y, + width, height)) + return; + + DBG(("%s: composite region extents: (%d, %d), (%d, %d) + (%d, %d)\n", + __FUNCTION__, + region.extents.x1, region.extents.y1, + region.extents.x2, region.extents.y2, + get_drawable_dx(dst->pDrawable), + get_drawable_dy(dst->pDrawable))); + + memset(&tmp, 0, sizeof(tmp)); + if (!sna->render.composite(sna, + op, src, mask, dst, + src_x, src_y, + mask_x, mask_y, + dst_x + dst->pDrawable->x, + dst_y + dst->pDrawable->y, + width, height, + &tmp)) { + DBG(("%s: fallback due unhandled composite op\n", __FUNCTION__)); + goto fallback; + } + + tmp.boxes(sna, &tmp, + REGION_RECTS(®ion), + REGION_NUM_RECTS(®ion)); + apply_damage(&tmp, ®ion); + tmp.done(sna, &tmp); + + REGION_UNINIT(NULL, ®ion); + return; + +fallback: + DBG(("%s -- fallback dst=(%d, %d)+(%d, %d), size=(%d, %d)\n", + __FUNCTION__, + dst_x, dst_y, + dst->pDrawable->x, dst->pDrawable->y, + width, height)); + + dst_move_area_to_cpu(dst, op, + dst_x + dst->pDrawable->x, + dst_y + dst->pDrawable->y, + width, height); + if (src->pDrawable) + sna_drawable_move_to_cpu(src->pDrawable, false); + if (mask && mask->pDrawable) + sna_drawable_move_to_cpu(mask->pDrawable, false); + + DBG(("%s: fallback -- fbCompposite\n", __FUNCTION__)); + fbComposite(op, src, mask, dst, + src_x, src_y, + mask_x, mask_y, + dst_x, dst_y, + width, height); +} + +static Bool +_pixman_region_init_clipped_rectangles(pixman_region16_t *region, + int num_rects, xRectangle *rects, + int tx, int ty, + int maxx, int maxy) +{ + pixman_box16_t stack_boxes[64], *boxes = stack_boxes; + pixman_bool_t ret; + int i, j; + + if (num_rects > ARRAY_SIZE(stack_boxes)) { + boxes = malloc(sizeof(pixman_box16_t) * num_rects); + if (boxes == NULL) + return FALSE; + } + + for (i = j = 0; i < num_rects; i++) { + boxes[j].x1 = rects[i].x + tx; + if (boxes[j].x1 < 0) + boxes[j].x1 = 0; + + boxes[j].y1 = rects[i].y + ty; + if (boxes[j].y1 < 0) + boxes[j].y1 = 0; + + boxes[j].x2 = rects[i].x + rects[i].width; + if (boxes[j].x2 > maxx) + boxes[j].x2 = maxx; + boxes[j].x2 += tx; + + boxes[j].y2 = rects[i].y + rects[i].height; + if (boxes[j].y2 > maxy) + boxes[j].y2 = maxy; + boxes[j].y2 += ty; + + if (boxes[j].x2 > boxes[j].x1 && boxes[j].y2 > boxes[j].y1) + j++; + } + + ret = TRUE; + if (j) + ret = pixman_region_init_rects(region, boxes, j); + else + pixman_region_init(region); + + if (boxes != stack_boxes) + free(boxes); + + DBG(("%s: nrects=%d, region=(%d, %d), (%d, %d) x %d\n", + __FUNCTION__, num_rects, + region->extents.x1, region->extents.y1, + region->extents.x2, region->extents.y2, + pixman_region_n_rects(region))); + return ret; +} + +void +sna_composite_rectangles(CARD8 op, + PicturePtr dst, + xRenderColor *color, + int num_rects, + xRectangle *rects) +{ + struct sna *sna = to_sna_from_drawable(dst->pDrawable); + PixmapPtr pixmap; + struct sna_pixmap *priv; + pixman_region16_t region; + pixman_box16_t *boxes; + int16_t dst_x, dst_y; + int num_boxes; + int error; + + DBG(("%s(op=%d, %08x x %d [(%d, %d)x(%d, %d) ...])\n", + __FUNCTION__, op, + (color->alpha >> 8 << 24) | + (color->red >> 8 << 16) | + (color->green >> 8 << 8) | + (color->blue >> 8 << 0), + num_rects, + rects[0].x, rects[0].y, rects[0].width, rects[0].height)); + + if (!num_rects) + return; + + if (!pixman_region_not_empty(dst->pCompositeClip)) { + DBG(("%s: empty clip, skipping\n", __FUNCTION__)); + return; + } + + if (!_pixman_region_init_clipped_rectangles(®ion, + num_rects, rects, + dst->pDrawable->x, dst->pDrawable->y, + dst->pDrawable->width, dst->pDrawable->height)) + { + DBG(("%s: allocation failed for region\n", __FUNCTION__)); + return; + } + + DBG(("%s: drawable extents (%d, %d),(%d, %d) x %d\n", + __FUNCTION__, + RegionExtents(®ion)->x1, RegionExtents(®ion)->y1, + RegionExtents(®ion)->x2, RegionExtents(®ion)->y2, + RegionNumRects(®ion))); + + if (!pixman_region_intersect(®ion, ®ion, dst->pCompositeClip) || + !pixman_region_not_empty(®ion)) { + DBG(("%s: zero-intersection between rectangles and clip\n", + __FUNCTION__)); + pixman_region_fini(®ion); + return; + } + + DBG(("%s: clipped extents (%d, %d),(%d, %d) x %d\n", + __FUNCTION__, + RegionExtents(®ion)->x1, RegionExtents(®ion)->y1, + RegionExtents(®ion)->x2, RegionExtents(®ion)->y2, + RegionNumRects(®ion))); + + pixmap = get_drawable_pixmap(dst->pDrawable); + get_drawable_deltas(dst->pDrawable, pixmap, &dst_x, &dst_y); + pixman_region_translate(®ion, dst_x, dst_y); + + DBG(("%s: pixmap +(%d, %d) extents (%d, %d),(%d, %d)\n", + __FUNCTION__, dst_x, dst_y, + RegionExtents(®ion)->x1, RegionExtents(®ion)->y1, + RegionExtents(®ion)->x2, RegionExtents(®ion)->y2)); + + if (sna->kgem.wedged) + goto fallback; + + if (dst->alphaMap) { + DBG(("%s: fallback, dst has an alpha-map\n", __FUNCTION__)); + goto fallback; + } + + boxes = pixman_region_rectangles(®ion, &num_boxes); + + if (op == PictOpClear) { + color->red = color->green = color->blue = color->alpha = 0; + } else if (color->alpha >= 0xff00 && op == PictOpOver) { + color->alpha = 0xffff; + op = PictOpSrc; + } + + if (too_small(sna, dst->pDrawable)) { + DBG(("%s: fallback, dst is too small\n", __FUNCTION__)); + goto fallback; + } + + priv = sna_pixmap_move_to_gpu(pixmap); + if (priv == NULL) { + DBG(("%s: fallback due to no GPU bo\n", __FUNCTION__)); + goto fallback; + } + + if (!sna->render.fill_boxes(sna, op, dst->format, color, + pixmap, priv->gpu_bo, + boxes, num_boxes)) { + DBG(("%s: fallback - acceleration failed\n", __FUNCTION__)); + goto fallback; + } + + if (!priv->gpu_only) { + assert_pixmap_contains_box(pixmap, RegionExtents(®ion)); + sna_damage_add(&priv->gpu_damage, ®ion); + } + + goto done; + +fallback: + DBG(("%s: fallback\n", __FUNCTION__)); + sna_drawable_move_region_to_cpu(&pixmap->drawable, ®ion, true); + + if (op == PictOpSrc || op == PictOpClear) { + PixmapPtr pixmap = get_drawable_pixmap(dst->pDrawable); + int nbox = REGION_NUM_RECTS(®ion); + BoxPtr box = REGION_RECTS(®ion); + uint32_t pixel; + + if (sna_get_pixel_from_rgba(&pixel, + color->red, + color->green, + color->blue, + color->alpha, + dst->format)) { + do { + DBG(("%s: fallback fill: (%d, %d)x(%d, %d) %08x\n", + __FUNCTION__, + box->x1, box->y1, + box->x2 - box->x1, + box->y2 - box->y1, + pixel)); + + pixman_fill(pixmap->devPrivate.ptr, + pixmap->devKind/sizeof(uint32_t), + pixmap->drawable.bitsPerPixel, + box->x1, box->y1, + box->x2 - box->x1, + box->y2 - box->y1, + pixel); + box++; + } while (--nbox); + } + } else { + PicturePtr src; + + src = CreateSolidPicture(0, color, &error); + if (src) { + do { + fbComposite(op, src, NULL, dst, + 0, 0, + 0, 0, + rects->x, rects->y, + rects->width, rects->height); + rects++; + } while (--num_rects); + FreePicture(src, 0); + } + } + +done: + /* XXX xserver-1.8: CompositeRects is not tracked by Damage, so we must + * manually append the damaged regions ourselves. + */ + DamageRegionAppend(&pixmap->drawable, ®ion); + DamageRegionProcessPending(&pixmap->drawable); + + pixman_region_fini(®ion); + return; +} |