1/* 2 * Copyright © 2009 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 * 23 * Authors: 24 * Zhigang Gong <zhigang.gong@linux.intel.com> 25 * 26 * original author is Chris Wilson at sna. 27 * 28 */ 29 30#include "glamor_priv.h" 31#include "mipict.h" 32#include "damage.h" 33 34/** @file glamor_compositerects. 35 * 36 * compositeRects acceleration implementation 37 */ 38 39static int16_t 40bound(int16_t a, uint16_t b) 41{ 42 int v = (int) a + (int) b; 43 44 if (v > MAXSHORT) 45 return MAXSHORT; 46 return v; 47} 48 49static Bool 50_pixman_region_init_clipped_rectangles(pixman_region16_t * region, 51 unsigned int num_rects, 52 xRectangle *rects, 53 int tx, int ty, BoxPtr extents) 54{ 55 pixman_box16_t stack_boxes[64], *boxes = stack_boxes; 56 pixman_bool_t ret; 57 unsigned int i, j; 58 59 if (num_rects > ARRAY_SIZE(stack_boxes)) { 60 boxes = xallocarray(num_rects, sizeof(pixman_box16_t)); 61 if (boxes == NULL) 62 return FALSE; 63 } 64 65 for (i = j = 0; i < num_rects; i++) { 66 boxes[j].x1 = rects[i].x + tx; 67 if (boxes[j].x1 < extents->x1) 68 boxes[j].x1 = extents->x1; 69 70 boxes[j].y1 = rects[i].y + ty; 71 if (boxes[j].y1 < extents->y1) 72 boxes[j].y1 = extents->y1; 73 74 boxes[j].x2 = bound(rects[i].x + tx, rects[i].width); 75 if (boxes[j].x2 > extents->x2) 76 boxes[j].x2 = extents->x2; 77 78 boxes[j].y2 = bound(rects[i].y + ty, rects[i].height); 79 if (boxes[j].y2 > extents->y2) 80 boxes[j].y2 = extents->y2; 81 82 if (boxes[j].x2 > boxes[j].x1 && boxes[j].y2 > boxes[j].y1) 83 j++; 84 } 85 86 ret = FALSE; 87 if (j) 88 ret = pixman_region_init_rects(region, boxes, j); 89 90 if (boxes != stack_boxes) 91 free(boxes); 92 93 DEBUGF("%s: nrects=%d, region=(%d, %d), (%d, %d) x %d\n", 94 __FUNCTION__, num_rects, 95 region->extents.x1, region->extents.y1, 96 region->extents.x2, region->extents.y2, j); 97 return ret; 98} 99 100void 101glamor_composite_rectangles(CARD8 op, 102 PicturePtr dst, 103 xRenderColor * color, 104 int num_rects, xRectangle *rects) 105{ 106 PixmapPtr pixmap; 107 struct glamor_pixmap_private *priv; 108 pixman_region16_t region; 109 pixman_box16_t *boxes; 110 int num_boxes; 111 PicturePtr source = NULL; 112 Bool need_free_region = FALSE; 113 114 DEBUGF("%s(op=%d, %08x x %d [(%d, %d)x(%d, %d) ...])\n", 115 __FUNCTION__, op, 116 (color->alpha >> 8 << 24) | 117 (color->red >> 8 << 16) | 118 (color->green >> 8 << 8) | 119 (color->blue >> 8 << 0), 120 num_rects, rects[0].x, rects[0].y, rects[0].width, rects[0].height); 121 122 if (!num_rects) 123 return; 124 125 if (RegionNil(dst->pCompositeClip)) { 126 DEBUGF("%s: empty clip, skipping\n", __FUNCTION__); 127 return; 128 } 129 130 if ((color->red | color->green | color->blue | color->alpha) <= 0x00ff) { 131 switch (op) { 132 case PictOpOver: 133 case PictOpOutReverse: 134 case PictOpAdd: 135 return; 136 case PictOpInReverse: 137 case PictOpSrc: 138 op = PictOpClear; 139 break; 140 case PictOpAtopReverse: 141 op = PictOpOut; 142 break; 143 case PictOpXor: 144 op = PictOpOverReverse; 145 break; 146 } 147 } 148 if (color->alpha <= 0x00ff) { 149 switch (op) { 150 case PictOpOver: 151 case PictOpOutReverse: 152 return; 153 case PictOpInReverse: 154 op = PictOpClear; 155 break; 156 case PictOpAtopReverse: 157 op = PictOpOut; 158 break; 159 case PictOpXor: 160 op = PictOpOverReverse; 161 break; 162 } 163 } 164 else if (color->alpha >= 0xff00) { 165 switch (op) { 166 case PictOpOver: 167 op = PictOpSrc; 168 break; 169 case PictOpInReverse: 170 return; 171 case PictOpOutReverse: 172 op = PictOpClear; 173 break; 174 case PictOpAtopReverse: 175 op = PictOpOverReverse; 176 break; 177 case PictOpXor: 178 op = PictOpOut; 179 break; 180 } 181 } 182 DEBUGF("%s: converted to op %d\n", __FUNCTION__, op); 183 184 if (!_pixman_region_init_clipped_rectangles(®ion, 185 num_rects, rects, 186 dst->pDrawable->x, 187 dst->pDrawable->y, 188 &dst->pCompositeClip->extents)) 189 { 190 DEBUGF("%s: allocation failed for region\n", __FUNCTION__); 191 return; 192 } 193 194 pixmap = glamor_get_drawable_pixmap(dst->pDrawable); 195 priv = glamor_get_pixmap_private(pixmap); 196 197 if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(priv)) 198 goto fallback; 199 if (dst->alphaMap) { 200 DEBUGF("%s: fallback, dst has an alpha-map\n", __FUNCTION__); 201 goto fallback; 202 } 203 204 need_free_region = TRUE; 205 206 DEBUGF("%s: drawable extents (%d, %d),(%d, %d) x %d\n", 207 __FUNCTION__, 208 RegionExtents(®ion)->x1, RegionExtents(®ion)->y1, 209 RegionExtents(®ion)->x2, RegionExtents(®ion)->y2, 210 RegionNumRects(®ion)); 211 212 if (dst->pCompositeClip->data && 213 (!pixman_region_intersect(®ion, ®ion, dst->pCompositeClip) || 214 RegionNil(®ion))) { 215 DEBUGF("%s: zero-intersection between rectangles and clip\n", 216 __FUNCTION__); 217 pixman_region_fini(®ion); 218 return; 219 } 220 221 DEBUGF("%s: clipped extents (%d, %d),(%d, %d) x %d\n", 222 __FUNCTION__, 223 RegionExtents(®ion)->x1, RegionExtents(®ion)->y1, 224 RegionExtents(®ion)->x2, RegionExtents(®ion)->y2, 225 RegionNumRects(®ion)); 226 227 boxes = pixman_region_rectangles(®ion, &num_boxes); 228 if (op == PictOpSrc || op == PictOpClear) { 229 CARD32 pixel; 230 int dst_x, dst_y; 231 232 glamor_get_drawable_deltas(dst->pDrawable, pixmap, &dst_x, &dst_y); 233 pixman_region_translate(®ion, dst_x, dst_y); 234 235 DEBUGF("%s: pixmap +(%d, %d) extents (%d, %d),(%d, %d)\n", 236 __FUNCTION__, dst_x, dst_y, 237 RegionExtents(®ion)->x1, RegionExtents(®ion)->y1, 238 RegionExtents(®ion)->x2, RegionExtents(®ion)->y2); 239 240 if (op == PictOpClear) 241 pixel = 0; 242 else 243 miRenderColorToPixel(dst->pFormat, color, &pixel); 244 glamor_solid_boxes(pixmap, boxes, num_boxes, pixel); 245 246 goto done; 247 } 248 else { 249 if (_X_LIKELY(glamor_pixmap_priv_is_small(priv))) { 250 int error; 251 252 source = CreateSolidPicture(0, color, &error); 253 if (!source) 254 goto done; 255 if (glamor_composite_clipped_region(op, source, 256 NULL, dst, 257 NULL, NULL, pixmap, 258 ®ion, 0, 0, 0, 0, 0, 0)) 259 goto done; 260 } 261 } 262 fallback: 263 miCompositeRects(op, dst, color, num_rects, rects); 264 done: 265 /* XXX xserver-1.8: CompositeRects is not tracked by Damage, so we must 266 * manually append the damaged regions ourselves. 267 */ 268 DamageRegionAppend(&pixmap->drawable, ®ion); 269 DamageRegionProcessPending(&pixmap->drawable); 270 271 if (need_free_region) 272 pixman_region_fini(®ion); 273 if (source) 274 FreePicture(source, 0); 275 return; 276} 277