1428d7b3dSmrg/* 2428d7b3dSmrg * Copyright (c) 2011 Intel Corporation 3428d7b3dSmrg * 4428d7b3dSmrg * Permission is hereby granted, free of charge, to any person obtaining a 5428d7b3dSmrg * copy of this software and associated documentation files (the "Software"), 6428d7b3dSmrg * to deal in the Software without restriction, including without limitation 7428d7b3dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8428d7b3dSmrg * and/or sell copies of the Software, and to permit persons to whom the 9428d7b3dSmrg * Software is furnished to do so, subject to the following conditions: 10428d7b3dSmrg * 11428d7b3dSmrg * The above copyright notice and this permission notice (including the next 12428d7b3dSmrg * paragraph) shall be included in all copies or substantial portions of the 13428d7b3dSmrg * Software. 14428d7b3dSmrg * 15428d7b3dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16428d7b3dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17428d7b3dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18428d7b3dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19428d7b3dSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20428d7b3dSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21428d7b3dSmrg * SOFTWARE. 22428d7b3dSmrg * 23428d7b3dSmrg * Authors: 24428d7b3dSmrg * Chris Wilson <chris@chris-wilson.co.uk> 25428d7b3dSmrg * 26428d7b3dSmrg */ 27428d7b3dSmrg 28428d7b3dSmrg#ifdef HAVE_CONFIG_H 29428d7b3dSmrg#include "config.h" 30428d7b3dSmrg#endif 31428d7b3dSmrg 32428d7b3dSmrg#include "sna.h" 33428d7b3dSmrg#include "sna_render.h" 34428d7b3dSmrg#include "sna_render_inline.h" 35428d7b3dSmrg#include "fb/fbpict.h" 36428d7b3dSmrg 37428d7b3dSmrg#include <mipict.h> 38428d7b3dSmrg 39428d7b3dSmrg#define NO_COMPOSITE 0 40428d7b3dSmrg#define NO_COMPOSITE_RECTANGLES 0 41428d7b3dSmrg 42428d7b3dSmrg#define BOUND(v) (INT16) ((v) < MINSHORT ? MINSHORT : (v) > MAXSHORT ? MAXSHORT : (v)) 43428d7b3dSmrg 44428d7b3dSmrgbool sna_composite_create(struct sna *sna) 45428d7b3dSmrg{ 46428d7b3dSmrg xRenderColor color = { 0 }; 47428d7b3dSmrg int error; 48428d7b3dSmrg 49428d7b3dSmrg sna->clear = CreateSolidPicture(0, &color, &error); 50428d7b3dSmrg return sna->clear != NULL; 51428d7b3dSmrg} 52428d7b3dSmrg 53428d7b3dSmrgvoid sna_composite_close(struct sna *sna) 54428d7b3dSmrg{ 55428d7b3dSmrg DBG(("%s\n", __FUNCTION__)); 56428d7b3dSmrg 57428d7b3dSmrg if (sna->clear) { 58428d7b3dSmrg FreePicture(sna->clear, 0); 59428d7b3dSmrg sna->clear = NULL; 60428d7b3dSmrg } 61428d7b3dSmrg} 62428d7b3dSmrg 63428d7b3dSmrgstatic inline bool 64428d7b3dSmrgregion_is_singular(pixman_region16_t *region) 65428d7b3dSmrg{ 66428d7b3dSmrg return region->data == NULL; 67428d7b3dSmrg} 68428d7b3dSmrg 69428d7b3dSmrgstatic inline bool 70428d7b3dSmrgregion_is_empty(pixman_region16_t *region) 71428d7b3dSmrg{ 72428d7b3dSmrg return region->data && region->data->numRects == 0; 73428d7b3dSmrg} 74428d7b3dSmrg 75428d7b3dSmrgstatic inline pixman_bool_t 76428d7b3dSmrgclip_to_dst(pixman_region16_t *region, 77428d7b3dSmrg pixman_region16_t *clip, 78428d7b3dSmrg int dx, 79428d7b3dSmrg int dy) 80428d7b3dSmrg{ 81428d7b3dSmrg DBG(("%s: region: %dx[(%d, %d), (%d, %d)], clip: %dx[(%d, %d), (%d, %d)]\n", 82428d7b3dSmrg __FUNCTION__, 83428d7b3dSmrg pixman_region_n_rects(region), 84428d7b3dSmrg region->extents.x1, region->extents.y1, 85428d7b3dSmrg region->extents.x2, region->extents.y2, 86428d7b3dSmrg pixman_region_n_rects(clip), 87428d7b3dSmrg clip->extents.x1, clip->extents.y1, 88428d7b3dSmrg clip->extents.x2, clip->extents.y2)); 89428d7b3dSmrg 90428d7b3dSmrg if (region_is_singular(region) && region_is_singular(clip)) { 91428d7b3dSmrg pixman_box16_t *r = ®ion->extents; 92428d7b3dSmrg pixman_box16_t *c = &clip->extents; 93428d7b3dSmrg int v; 94428d7b3dSmrg 95428d7b3dSmrg if (r->x1 < (v = c->x1 + dx)) 96428d7b3dSmrg r->x1 = BOUND(v); 97428d7b3dSmrg if (r->x2 > (v = c->x2 + dx)) 98428d7b3dSmrg r->x2 = BOUND(v); 99428d7b3dSmrg if (r->y1 < (v = c->y1 + dy)) 100428d7b3dSmrg r->y1 = BOUND(v); 101428d7b3dSmrg if (r->y2 > (v = c->y2 + dy)) 102428d7b3dSmrg r->y2 = BOUND(v); 103428d7b3dSmrg 104428d7b3dSmrg if (r->x1 >= r->x2 || r->y1 >= r->y2) { 105428d7b3dSmrg pixman_region_init(region); 106428d7b3dSmrg return FALSE; 107428d7b3dSmrg } 108428d7b3dSmrg 109428d7b3dSmrg return true; 110428d7b3dSmrg } else if (region_is_empty(clip)) { 111428d7b3dSmrg return FALSE; 112428d7b3dSmrg } else { 113428d7b3dSmrg if (dx | dy) 114428d7b3dSmrg pixman_region_translate(region, -dx, -dy); 115428d7b3dSmrg if (!pixman_region_intersect(region, region, clip)) 116428d7b3dSmrg return FALSE; 117428d7b3dSmrg if (dx | dy) 118428d7b3dSmrg pixman_region_translate(region, dx, dy); 119428d7b3dSmrg 120428d7b3dSmrg return !region_is_empty(region); 121428d7b3dSmrg } 122428d7b3dSmrg} 123428d7b3dSmrg 124428d7b3dSmrgstatic inline bool 125428d7b3dSmrgpicture_has_clip(PicturePtr p) 126428d7b3dSmrg{ 127428d7b3dSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,16,99,1,0) 128428d7b3dSmrg return p->clientClip; 129428d7b3dSmrg#else 130428d7b3dSmrg return p->clientClipType != CT_NONE; 131428d7b3dSmrg#endif 132428d7b3dSmrg} 133428d7b3dSmrg 134428d7b3dSmrgstatic inline bool 135428d7b3dSmrgclip_to_src(RegionPtr region, PicturePtr p, int dx, int dy) 136428d7b3dSmrg{ 137428d7b3dSmrg bool result; 138428d7b3dSmrg 139428d7b3dSmrg if (!picture_has_clip(p)) 140428d7b3dSmrg return true; 141428d7b3dSmrg 142428d7b3dSmrg pixman_region_translate(p->clientClip, 143428d7b3dSmrg p->clipOrigin.x + dx, 144428d7b3dSmrg p->clipOrigin.y + dy); 145428d7b3dSmrg 146428d7b3dSmrg result = RegionIntersect(region, region, p->clientClip); 147428d7b3dSmrg 148428d7b3dSmrg pixman_region_translate(p->clientClip, 149428d7b3dSmrg -(p->clipOrigin.x + dx), 150428d7b3dSmrg -(p->clipOrigin.y + dy)); 151428d7b3dSmrg 152428d7b3dSmrg return result && !region_is_empty(region); 153428d7b3dSmrg} 154428d7b3dSmrg 155428d7b3dSmrgbool 156428d7b3dSmrgsna_compute_composite_region(RegionPtr region, 157428d7b3dSmrg PicturePtr src, PicturePtr mask, PicturePtr dst, 158428d7b3dSmrg INT16 src_x, INT16 src_y, 159428d7b3dSmrg INT16 mask_x, INT16 mask_y, 160428d7b3dSmrg INT16 dst_x, INT16 dst_y, 161428d7b3dSmrg CARD16 width, CARD16 height) 162428d7b3dSmrg{ 163428d7b3dSmrg int v; 164428d7b3dSmrg 165428d7b3dSmrg DBG(("%s: dst=(%d, %d)x(%d, %d)\n", 166428d7b3dSmrg __FUNCTION__, 167428d7b3dSmrg dst_x, dst_y, 168428d7b3dSmrg width, height)); 169428d7b3dSmrg 170428d7b3dSmrg region->extents.x1 = dst_x < 0 ? 0 : dst_x; 171428d7b3dSmrg v = dst_x + width; 172428d7b3dSmrg if (v > dst->pDrawable->width) 173428d7b3dSmrg v = dst->pDrawable->width; 174428d7b3dSmrg region->extents.x2 = v; 175428d7b3dSmrg 176428d7b3dSmrg region->extents.y1 = dst_y < 0 ? 0 : dst_y; 177428d7b3dSmrg v = dst_y + height; 178428d7b3dSmrg if (v > dst->pDrawable->height) 179428d7b3dSmrg v = dst->pDrawable->height; 180428d7b3dSmrg region->extents.y2 = v; 181428d7b3dSmrg 182428d7b3dSmrg region->data = 0; 183428d7b3dSmrg 184428d7b3dSmrg DBG(("%s: initial clip against dst->pDrawable: (%d, %d), (%d, %d)\n", 185428d7b3dSmrg __FUNCTION__, 186428d7b3dSmrg region->extents.x1, region->extents.y1, 187428d7b3dSmrg region->extents.x2, region->extents.y2)); 188428d7b3dSmrg 189428d7b3dSmrg if (region->extents.x1 >= region->extents.x2 || 190428d7b3dSmrg region->extents.y1 >= region->extents.y2) 191428d7b3dSmrg return false; 192428d7b3dSmrg 193428d7b3dSmrg region->extents.x1 += dst->pDrawable->x; 194428d7b3dSmrg region->extents.x2 += dst->pDrawable->x; 195428d7b3dSmrg region->extents.y1 += dst->pDrawable->y; 196428d7b3dSmrg region->extents.y2 += dst->pDrawable->y; 197428d7b3dSmrg 198428d7b3dSmrg dst_x += dst->pDrawable->x; 199428d7b3dSmrg dst_y += dst->pDrawable->y; 200428d7b3dSmrg 201428d7b3dSmrg /* clip against dst */ 202428d7b3dSmrg if (!clip_to_dst(region, dst->pCompositeClip, 0, 0)) 203428d7b3dSmrg return false; 204428d7b3dSmrg 205428d7b3dSmrg DBG(("%s: clip against dst->pCompositeClip: (%d, %d), (%d, %d)\n", 206428d7b3dSmrg __FUNCTION__, 207428d7b3dSmrg region->extents.x1, region->extents.y1, 208428d7b3dSmrg region->extents.x2, region->extents.y2)); 209428d7b3dSmrg 210428d7b3dSmrg if (dst->alphaMap) { 211428d7b3dSmrg if (!clip_to_dst(region, dst->alphaMap->pCompositeClip, 212428d7b3dSmrg -dst->alphaOrigin.x, 213428d7b3dSmrg -dst->alphaOrigin.y)) { 214428d7b3dSmrg pixman_region_fini (region); 215428d7b3dSmrg return false; 216428d7b3dSmrg } 217428d7b3dSmrg } 218428d7b3dSmrg 219428d7b3dSmrg /* clip against src */ 220428d7b3dSmrg if (src) { 221428d7b3dSmrg if (src->pDrawable) { 222428d7b3dSmrg src_x += src->pDrawable->x; 223428d7b3dSmrg src_y += src->pDrawable->y; 224428d7b3dSmrg } 225428d7b3dSmrg if (!clip_to_src(region, src, dst_x - src_x, dst_y - src_y)) { 226428d7b3dSmrg pixman_region_fini (region); 227428d7b3dSmrg return false; 228428d7b3dSmrg } 229428d7b3dSmrg DBG(("%s: clip against src (%dx%d clip=%d): (%d, %d), (%d, %d)\n", 230428d7b3dSmrg __FUNCTION__, 231428d7b3dSmrg src->pDrawable ? src->pDrawable->width : 0, 232428d7b3dSmrg src->pDrawable ? src->pDrawable->height : 0, 233428d7b3dSmrg picture_has_clip(src), 234428d7b3dSmrg region->extents.x1, region->extents.y1, 235428d7b3dSmrg region->extents.x2, region->extents.y2)); 236428d7b3dSmrg 237428d7b3dSmrg if (src->alphaMap) { 238428d7b3dSmrg if (!clip_to_src(region, src->alphaMap, 239428d7b3dSmrg dst_x - (src_x - src->alphaOrigin.x), 240428d7b3dSmrg dst_y - (src_y - src->alphaOrigin.y))) { 241428d7b3dSmrg pixman_region_fini(region); 242428d7b3dSmrg return false; 243428d7b3dSmrg } 244428d7b3dSmrg } 245428d7b3dSmrg } 246428d7b3dSmrg 247428d7b3dSmrg /* clip against mask */ 248428d7b3dSmrg if (mask) { 249428d7b3dSmrg if (mask->pDrawable) { 250428d7b3dSmrg mask_x += mask->pDrawable->x; 251428d7b3dSmrg mask_y += mask->pDrawable->y; 252428d7b3dSmrg } 253428d7b3dSmrg if (!clip_to_src(region, mask, dst_x - mask_x, dst_y - mask_y)) { 254428d7b3dSmrg pixman_region_fini(region); 255428d7b3dSmrg return false; 256428d7b3dSmrg } 257428d7b3dSmrg if (mask->alphaMap) { 258428d7b3dSmrg if (!clip_to_src(region, mask->alphaMap, 259428d7b3dSmrg dst_x - (mask_x - mask->alphaOrigin.x), 260428d7b3dSmrg dst_y - (mask_y - mask->alphaOrigin.y))) { 261428d7b3dSmrg pixman_region_fini(region); 262428d7b3dSmrg return false; 263428d7b3dSmrg } 264428d7b3dSmrg } 265428d7b3dSmrg 266428d7b3dSmrg DBG(("%s: clip against mask: (%d, %d), (%d, %d)\n", 267428d7b3dSmrg __FUNCTION__, 268428d7b3dSmrg region->extents.x1, region->extents.y1, 269428d7b3dSmrg region->extents.x2, region->extents.y2)); 270428d7b3dSmrg } 271428d7b3dSmrg 272428d7b3dSmrg return !region_is_empty(region); 273428d7b3dSmrg} 274428d7b3dSmrg 275428d7b3dSmrgstatic void 276428d7b3dSmrgtrim_extents(BoxPtr extents, const PicturePtr p, int dx, int dy) 277428d7b3dSmrg{ 278428d7b3dSmrg const BoxPtr box = REGION_EXTENTS(NULL, p->pCompositeClip); 279428d7b3dSmrg 280428d7b3dSmrg DBG(("%s: trim((%d, %d), (%d, %d)) against ((%d, %d), (%d, %d)) + (%d, %d)\n", 281428d7b3dSmrg __FUNCTION__, 282428d7b3dSmrg extents->x1, extents->y1, extents->x2, extents->y2, 283428d7b3dSmrg box->x1, box->y1, box->x2, box->y2, 284428d7b3dSmrg dx, dy)); 285428d7b3dSmrg 286428d7b3dSmrg if (extents->x1 < box->x1 + dx) 287428d7b3dSmrg extents->x1 = box->x1 + dx; 288428d7b3dSmrg if (extents->x2 > box->x2 + dx) 289428d7b3dSmrg extents->x2 = box->x2 + dx; 290428d7b3dSmrg 291428d7b3dSmrg if (extents->y1 < box->y1 + dy) 292428d7b3dSmrg extents->y1 = box->y1 + dy; 293428d7b3dSmrg if (extents->y2 > box->y2 + dy) 294428d7b3dSmrg extents->y2 = box->y2 + dy; 295428d7b3dSmrg} 296428d7b3dSmrg 297428d7b3dSmrgstatic void 298428d7b3dSmrg_trim_source_extents(BoxPtr extents, const PicturePtr p, int dx, int dy) 299428d7b3dSmrg{ 300428d7b3dSmrg if (picture_has_clip(p)) 301428d7b3dSmrg trim_extents(extents, p, dx, dy); 302428d7b3dSmrg} 303428d7b3dSmrg 304428d7b3dSmrgstatic void 305428d7b3dSmrgtrim_source_extents(BoxPtr extents, const PicturePtr p, int dx, int dy) 306428d7b3dSmrg{ 307428d7b3dSmrg if (p->pDrawable) { 308428d7b3dSmrg dx += p->pDrawable->x; 309428d7b3dSmrg dy += p->pDrawable->y; 310428d7b3dSmrg } 311428d7b3dSmrg _trim_source_extents(extents, p, dx, dy); 312428d7b3dSmrg if (p->alphaMap) 313428d7b3dSmrg _trim_source_extents(extents, p->alphaMap, 314428d7b3dSmrg dx - p->alphaOrigin.x, 315428d7b3dSmrg dy - p->alphaOrigin.y); 316428d7b3dSmrg 317428d7b3dSmrg DBG(("%s: -> (%d, %d), (%d, %d)\n", 318428d7b3dSmrg __FUNCTION__, 319428d7b3dSmrg extents->x1, extents->y1, 320428d7b3dSmrg extents->x2, extents->y2)); 321428d7b3dSmrg} 322428d7b3dSmrg 323428d7b3dSmrgbool 324428d7b3dSmrgsna_compute_composite_extents(BoxPtr extents, 325428d7b3dSmrg PicturePtr src, PicturePtr mask, PicturePtr dst, 326428d7b3dSmrg INT16 src_x, INT16 src_y, 327428d7b3dSmrg INT16 mask_x, INT16 mask_y, 328428d7b3dSmrg INT16 dst_x, INT16 dst_y, 329428d7b3dSmrg CARD16 width, CARD16 height) 330428d7b3dSmrg{ 331428d7b3dSmrg int v; 332428d7b3dSmrg 333428d7b3dSmrg DBG(("%s: dst=(%d, %d)x(%d, %d)\n", 334428d7b3dSmrg __FUNCTION__, 335428d7b3dSmrg dst_x, dst_y, 336428d7b3dSmrg width, height)); 337428d7b3dSmrg 338428d7b3dSmrg extents->x1 = dst_x < 0 ? 0 : dst_x; 339428d7b3dSmrg v = dst_x + width; 340428d7b3dSmrg if (v > dst->pDrawable->width) 341428d7b3dSmrg v = dst->pDrawable->width; 342428d7b3dSmrg extents->x2 = v; 343428d7b3dSmrg 344428d7b3dSmrg extents->y1 = dst_y < 0 ? 0 : dst_y; 345428d7b3dSmrg v = dst_y + height; 346428d7b3dSmrg if (v > dst->pDrawable->height) 347428d7b3dSmrg v = dst->pDrawable->height; 348428d7b3dSmrg extents->y2 = v; 349428d7b3dSmrg 350428d7b3dSmrg DBG(("%s: initial clip against dst->pDrawable: (%d, %d), (%d, %d)\n", 351428d7b3dSmrg __FUNCTION__, 352428d7b3dSmrg extents->x1, extents->y1, 353428d7b3dSmrg extents->x2, extents->y2)); 354428d7b3dSmrg 355428d7b3dSmrg if (extents->x1 >= extents->x2 || extents->y1 >= extents->y2) 356428d7b3dSmrg return false; 357428d7b3dSmrg 358428d7b3dSmrg extents->x1 += dst->pDrawable->x; 359428d7b3dSmrg extents->x2 += dst->pDrawable->x; 360428d7b3dSmrg extents->y1 += dst->pDrawable->y; 361428d7b3dSmrg extents->y2 += dst->pDrawable->y; 362428d7b3dSmrg 363428d7b3dSmrg if (extents->x1 < dst->pCompositeClip->extents.x1) 364428d7b3dSmrg extents->x1 = dst->pCompositeClip->extents.x1; 365428d7b3dSmrg if (extents->x2 > dst->pCompositeClip->extents.x2) 366428d7b3dSmrg extents->x2 = dst->pCompositeClip->extents.x2; 367428d7b3dSmrg 368428d7b3dSmrg if (extents->y1 < dst->pCompositeClip->extents.y1) 369428d7b3dSmrg extents->y1 = dst->pCompositeClip->extents.y1; 370428d7b3dSmrg if (extents->y2 > dst->pCompositeClip->extents.y2) 371428d7b3dSmrg extents->y2 = dst->pCompositeClip->extents.y2; 372428d7b3dSmrg 373428d7b3dSmrg DBG(("%s: initial clip against dst->pCompositeClip: (%d, %d), (%d, %d)\n", 374428d7b3dSmrg __FUNCTION__, 375428d7b3dSmrg extents->x1, extents->y1, 376428d7b3dSmrg extents->x2, extents->y2)); 377428d7b3dSmrg 378428d7b3dSmrg if (extents->x1 >= extents->x2 || extents->y1 >= extents->y2) 379428d7b3dSmrg return false; 380428d7b3dSmrg 381428d7b3dSmrg dst_x += dst->pDrawable->x; 382428d7b3dSmrg dst_y += dst->pDrawable->y; 383428d7b3dSmrg 384428d7b3dSmrg /* clip against dst */ 385428d7b3dSmrg trim_extents(extents, dst, 0, 0); 386428d7b3dSmrg if (dst->alphaMap) 387428d7b3dSmrg trim_extents(extents, dst->alphaMap, 388428d7b3dSmrg -dst->alphaOrigin.x, 389428d7b3dSmrg -dst->alphaOrigin.y); 390428d7b3dSmrg 391428d7b3dSmrg DBG(("%s: clip against dst: (%d, %d), (%d, %d)\n", 392428d7b3dSmrg __FUNCTION__, 393428d7b3dSmrg extents->x1, extents->y1, 394428d7b3dSmrg extents->x2, extents->y2)); 395428d7b3dSmrg 396428d7b3dSmrg if (src) 397428d7b3dSmrg trim_source_extents(extents, src, dst_x - src_x, dst_y - src_y); 398428d7b3dSmrg if (mask) 399428d7b3dSmrg trim_source_extents(extents, mask, 400428d7b3dSmrg dst_x - mask_x, dst_y - mask_y); 401428d7b3dSmrg 402428d7b3dSmrg if (extents->x1 >= extents->x2 || extents->y1 >= extents->y2) 403428d7b3dSmrg return false; 404428d7b3dSmrg 405428d7b3dSmrg if (region_is_singular(dst->pCompositeClip)) 406428d7b3dSmrg return true; 407428d7b3dSmrg 408428d7b3dSmrg return pixman_region_contains_rectangle(dst->pCompositeClip, 409428d7b3dSmrg extents) != PIXMAN_REGION_OUT; 410428d7b3dSmrg} 411428d7b3dSmrg 412428d7b3dSmrg#if HAS_DEBUG_FULL 413428d7b3dSmrgstatic void _assert_pixmap_contains_box(PixmapPtr pixmap, BoxPtr box, const char *function) 414428d7b3dSmrg{ 415428d7b3dSmrg if (box->x1 < 0 || box->y1 < 0 || 416428d7b3dSmrg box->x2 > pixmap->drawable.width || 417428d7b3dSmrg box->y2 > pixmap->drawable.height) 418428d7b3dSmrg { 419428d7b3dSmrg FatalError("%s: damage box is beyond the pixmap: box=(%d, %d), (%d, %d), pixmap=(%d, %d)\n", 420428d7b3dSmrg function, 421428d7b3dSmrg box->x1, box->y1, box->x2, box->y2, 422428d7b3dSmrg pixmap->drawable.width, 423428d7b3dSmrg pixmap->drawable.height); 424428d7b3dSmrg } 425428d7b3dSmrg} 426428d7b3dSmrg#define assert_pixmap_contains_box(p, b) _assert_pixmap_contains_box(p, b, __FUNCTION__) 427428d7b3dSmrg#else 428428d7b3dSmrg#define assert_pixmap_contains_box(p, b) 429428d7b3dSmrg#endif 430428d7b3dSmrg 431428d7b3dSmrgstatic void apply_damage(struct sna_composite_op *op, RegionPtr region) 432428d7b3dSmrg{ 433428d7b3dSmrg DBG(("%s: damage=%p, region=%d [(%d, %d), (%d, %d) + (%d, %d)]\n", 434428d7b3dSmrg __FUNCTION__, op->damage, region_num_rects(region), 435428d7b3dSmrg region->extents.x1, region->extents.y1, 436428d7b3dSmrg region->extents.x2, region->extents.y2, 437428d7b3dSmrg op->dst.x, op->dst.y)); 438428d7b3dSmrg 439428d7b3dSmrg if (op->damage == NULL) 440428d7b3dSmrg return; 441428d7b3dSmrg 442428d7b3dSmrg if (op->dst.x | op->dst.y) 443428d7b3dSmrg RegionTranslate(region, op->dst.x, op->dst.y); 444428d7b3dSmrg 445428d7b3dSmrg assert_pixmap_contains_box(op->dst.pixmap, RegionExtents(region)); 446428d7b3dSmrg if (region->data == NULL && 447428d7b3dSmrg region->extents.x2 - region->extents.x1 == op->dst.width && 448428d7b3dSmrg region->extents.y2 - region->extents.y1 == op->dst.height) { 449428d7b3dSmrg *op->damage = _sna_damage_all(*op->damage, 450428d7b3dSmrg op->dst.width, 451428d7b3dSmrg op->dst.height); 452428d7b3dSmrg op->damage = NULL; 453428d7b3dSmrg } else 454428d7b3dSmrg sna_damage_add(op->damage, region); 455428d7b3dSmrg} 456428d7b3dSmrg 457428d7b3dSmrgstatic inline bool use_cpu(PixmapPtr pixmap, struct sna_pixmap *priv, 458428d7b3dSmrg CARD8 op, INT16 width, INT16 height) 459428d7b3dSmrg{ 460428d7b3dSmrg if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) 461428d7b3dSmrg return false; 462428d7b3dSmrg 463428d7b3dSmrg if (DAMAGE_IS_ALL(priv->cpu_damage) && 464428d7b3dSmrg (op > PictOpSrc || 465428d7b3dSmrg width < pixmap->drawable.width || 466428d7b3dSmrg height < pixmap->drawable.height)) 467428d7b3dSmrg return true; 468428d7b3dSmrg 469428d7b3dSmrg if (priv->gpu_bo) 470428d7b3dSmrg return false; 471428d7b3dSmrg 472428d7b3dSmrg return (priv->create & KGEM_CAN_CREATE_GPU) == 0; 473428d7b3dSmrg} 474428d7b3dSmrg 475428d7b3dSmrgstatic void validate_source(PicturePtr picture) 476428d7b3dSmrg{ 477428d7b3dSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,10,99,901,0) 478428d7b3dSmrg miCompositeSourceValidate(picture); 479428d7b3dSmrg#else 480428d7b3dSmrg miCompositeSourceValidate(picture, 481428d7b3dSmrg 0, 0, 482428d7b3dSmrg picture->pDrawable ? picture->pDrawable->width : 0, 483428d7b3dSmrg picture->pDrawable ? picture->pDrawable->height : 0); 484428d7b3dSmrg#endif 485428d7b3dSmrg} 486428d7b3dSmrg 487428d7b3dSmrgvoid 488428d7b3dSmrgsna_composite_fb(CARD8 op, 489428d7b3dSmrg PicturePtr src, 490428d7b3dSmrg PicturePtr mask, 491428d7b3dSmrg PicturePtr dst, 492428d7b3dSmrg RegionPtr region, 493428d7b3dSmrg INT16 src_x, INT16 src_y, 494428d7b3dSmrg INT16 msk_x, INT16 msk_y, 495428d7b3dSmrg INT16 dst_x, INT16 dst_y, 496428d7b3dSmrg CARD16 width, CARD16 height) 497428d7b3dSmrg{ 498428d7b3dSmrg pixman_image_t *src_image, *mask_image, *dest_image; 499428d7b3dSmrg int src_xoff, src_yoff; 500428d7b3dSmrg int msk_xoff, msk_yoff; 501428d7b3dSmrg int dst_xoff, dst_yoff; 502428d7b3dSmrg int16_t tx, ty; 503428d7b3dSmrg unsigned flags; 504428d7b3dSmrg 505428d7b3dSmrg DBG(("%s -- op=%d, fallback dst=(%d, %d)+(%d, %d), size=(%d, %d): region=((%d,%d), (%d, %d))\n", 506428d7b3dSmrg __FUNCTION__, op, 507428d7b3dSmrg dst_x, dst_y, 508428d7b3dSmrg dst->pDrawable->x, dst->pDrawable->y, 509428d7b3dSmrg width, height, 510428d7b3dSmrg region->extents.x1, region->extents.y1, 511428d7b3dSmrg region->extents.x2, region->extents.y2)); 512428d7b3dSmrg 513428d7b3dSmrg if (src->pDrawable) { 514428d7b3dSmrg DBG(("%s: fallback -- move src to cpu\n", __FUNCTION__)); 515428d7b3dSmrg if (!sna_drawable_move_to_cpu(src->pDrawable, 516428d7b3dSmrg MOVE_READ)) 517428d7b3dSmrg return; 518428d7b3dSmrg 519428d7b3dSmrg if (src->alphaMap && 520428d7b3dSmrg !sna_drawable_move_to_cpu(src->alphaMap->pDrawable, 521428d7b3dSmrg MOVE_READ)) 522428d7b3dSmrg return; 523428d7b3dSmrg } 524428d7b3dSmrg 525428d7b3dSmrg validate_source(src); 526428d7b3dSmrg 527428d7b3dSmrg if (mask) { 528428d7b3dSmrg if (mask->pDrawable) { 529428d7b3dSmrg DBG(("%s: fallback -- move mask to cpu\n", __FUNCTION__)); 530428d7b3dSmrg if (!sna_drawable_move_to_cpu(mask->pDrawable, 531428d7b3dSmrg MOVE_READ)) 532428d7b3dSmrg return; 533428d7b3dSmrg 534428d7b3dSmrg if (mask->alphaMap && 535428d7b3dSmrg !sna_drawable_move_to_cpu(mask->alphaMap->pDrawable, 536428d7b3dSmrg MOVE_READ)) 537428d7b3dSmrg return; 538428d7b3dSmrg } 539428d7b3dSmrg 540428d7b3dSmrg validate_source(mask); 541428d7b3dSmrg } 542428d7b3dSmrg 543428d7b3dSmrg DBG(("%s: fallback -- move dst to cpu\n", __FUNCTION__)); 544428d7b3dSmrg if (op <= PictOpSrc && !dst->alphaMap) 545428d7b3dSmrg flags = MOVE_WRITE | MOVE_INPLACE_HINT; 546428d7b3dSmrg else 547428d7b3dSmrg flags = MOVE_WRITE | MOVE_READ; 548428d7b3dSmrg if (!sna_drawable_move_region_to_cpu(dst->pDrawable, region, flags)) 549428d7b3dSmrg return; 550428d7b3dSmrg if (dst->alphaMap && 551428d7b3dSmrg !sna_drawable_move_to_cpu(dst->alphaMap->pDrawable, flags)) 552428d7b3dSmrg return; 553428d7b3dSmrg 554428d7b3dSmrg if (mask == NULL && 555428d7b3dSmrg src->pDrawable && 556428d7b3dSmrg dst->pDrawable->bitsPerPixel >= 8 && 557428d7b3dSmrg src->filter != PictFilterConvolution && 558428d7b3dSmrg (op == PictOpSrc || (op == PictOpOver && !PICT_FORMAT_A(src->format))) && 559428d7b3dSmrg (dst->format == src->format || dst->format == alphaless(src->format)) && 560428d7b3dSmrg sna_transform_is_imprecise_integer_translation(src->transform, src->filter, 561428d7b3dSmrg dst->polyMode == PolyModePrecise, 562428d7b3dSmrg &tx, &ty)) { 563428d7b3dSmrg PixmapPtr dst_pixmap = get_drawable_pixmap(dst->pDrawable); 564428d7b3dSmrg PixmapPtr src_pixmap = get_drawable_pixmap(src->pDrawable); 565428d7b3dSmrg int16_t sx = src_x + tx - (dst->pDrawable->x + dst_x); 566428d7b3dSmrg int16_t sy = src_y + ty - (dst->pDrawable->y + dst_y); 567428d7b3dSmrg 568428d7b3dSmrg assert(src->pDrawable->bitsPerPixel == dst->pDrawable->bitsPerPixel); 569428d7b3dSmrg assert(src_pixmap->drawable.bitsPerPixel == dst_pixmap->drawable.bitsPerPixel); 570428d7b3dSmrg 571428d7b3dSmrg if (region->extents.x1 + sx >= 0 && 572428d7b3dSmrg region->extents.y1 + sy >= 0 && 573428d7b3dSmrg region->extents.x2 + sx <= src->pDrawable->width && 574428d7b3dSmrg region->extents.y2 + sy <= src->pDrawable->height) { 575428d7b3dSmrg if (sigtrap_get() == 0) { 576428d7b3dSmrg const BoxRec *box = region_rects(region); 577428d7b3dSmrg int nbox = region_num_rects(region); 578428d7b3dSmrg 579428d7b3dSmrg sx += src->pDrawable->x; 580428d7b3dSmrg sy += src->pDrawable->y; 581428d7b3dSmrg if (get_drawable_deltas(src->pDrawable, src_pixmap, &tx, &ty)) 582428d7b3dSmrg sx += tx, sy += ty; 583428d7b3dSmrg 584428d7b3dSmrg assert(region->extents.x1 + sx >= 0); 585428d7b3dSmrg assert(region->extents.x2 + sx <= src_pixmap->drawable.width); 586428d7b3dSmrg assert(region->extents.y1 + sy >= 0); 587428d7b3dSmrg assert(region->extents.y2 + sy <= src_pixmap->drawable.height); 588428d7b3dSmrg 589428d7b3dSmrg get_drawable_deltas(dst->pDrawable, dst_pixmap, &tx, &ty); 590428d7b3dSmrg 591428d7b3dSmrg assert(nbox); 592428d7b3dSmrg do { 593428d7b3dSmrg assert(box->x1 + sx >= 0); 594428d7b3dSmrg assert(box->x2 + sx <= src_pixmap->drawable.width); 595428d7b3dSmrg assert(box->y1 + sy >= 0); 596428d7b3dSmrg assert(box->y2 + sy <= src_pixmap->drawable.height); 597428d7b3dSmrg 598428d7b3dSmrg assert(box->x1 + tx >= 0); 599428d7b3dSmrg assert(box->x2 + tx <= dst_pixmap->drawable.width); 600428d7b3dSmrg assert(box->y1 + ty >= 0); 601428d7b3dSmrg assert(box->y2 + ty <= dst_pixmap->drawable.height); 602428d7b3dSmrg 603428d7b3dSmrg assert(box->x2 > box->x1 && box->y2 > box->y1); 604428d7b3dSmrg 605428d7b3dSmrg sigtrap_assert_active(); 606428d7b3dSmrg memcpy_blt(src_pixmap->devPrivate.ptr, 607428d7b3dSmrg dst_pixmap->devPrivate.ptr, 608428d7b3dSmrg dst_pixmap->drawable.bitsPerPixel, 609428d7b3dSmrg src_pixmap->devKind, 610428d7b3dSmrg dst_pixmap->devKind, 611428d7b3dSmrg box->x1 + sx, box->y1 + sy, 612428d7b3dSmrg box->x1 + tx, box->y1 + ty, 613428d7b3dSmrg box->x2 - box->x1, box->y2 - box->y1); 614428d7b3dSmrg box++; 615428d7b3dSmrg } while (--nbox); 616428d7b3dSmrg sigtrap_put(); 617428d7b3dSmrg } 618428d7b3dSmrg 619428d7b3dSmrg return; 620428d7b3dSmrg } 621428d7b3dSmrg } 622428d7b3dSmrg 623428d7b3dSmrg src_image = image_from_pict(src, FALSE, &src_xoff, &src_yoff); 624428d7b3dSmrg mask_image = image_from_pict(mask, FALSE, &msk_xoff, &msk_yoff); 625428d7b3dSmrg dest_image = image_from_pict(dst, TRUE, &dst_xoff, &dst_yoff); 626428d7b3dSmrg 627428d7b3dSmrg if (src_image && dest_image && !(mask && !mask_image)) 628428d7b3dSmrg sna_image_composite(op, src_image, mask_image, dest_image, 629428d7b3dSmrg src_x + src_xoff, src_y + src_yoff, 630428d7b3dSmrg msk_x + msk_xoff, msk_y + msk_yoff, 631428d7b3dSmrg dst_x + dst_xoff, dst_y + dst_yoff, 632428d7b3dSmrg width, height); 633428d7b3dSmrg 634428d7b3dSmrg free_pixman_pict(src, src_image); 635428d7b3dSmrg free_pixman_pict(mask, mask_image); 636428d7b3dSmrg free_pixman_pict(dst, dest_image); 637428d7b3dSmrg} 638428d7b3dSmrg 639428d7b3dSmrgvoid 640428d7b3dSmrgsna_composite(CARD8 op, 641428d7b3dSmrg PicturePtr src, 642428d7b3dSmrg PicturePtr mask, 643428d7b3dSmrg PicturePtr dst, 644428d7b3dSmrg INT16 src_x, INT16 src_y, 645428d7b3dSmrg INT16 mask_x, INT16 mask_y, 646428d7b3dSmrg INT16 dst_x, INT16 dst_y, 647428d7b3dSmrg CARD16 width, CARD16 height) 648428d7b3dSmrg{ 649428d7b3dSmrg PixmapPtr pixmap = get_drawable_pixmap(dst->pDrawable); 650428d7b3dSmrg struct sna *sna = to_sna_from_pixmap(pixmap); 651428d7b3dSmrg struct sna_pixmap *priv; 652428d7b3dSmrg struct sna_composite_op tmp; 653428d7b3dSmrg RegionRec region; 654428d7b3dSmrg int dx, dy; 655428d7b3dSmrg 656428d7b3dSmrg DBG(("%s(%d src=%ld+(%d, %d), mask=%ld+(%d, %d), dst=%ld+(%d, %d)+(%d, %d), size=(%d, %d)\n", 657428d7b3dSmrg __FUNCTION__, op, 658428d7b3dSmrg get_picture_id(src), src_x, src_y, 659428d7b3dSmrg get_picture_id(mask), mask_x, mask_y, 660428d7b3dSmrg get_picture_id(dst), dst_x, dst_y, 661428d7b3dSmrg dst->pDrawable->x, dst->pDrawable->y, 662428d7b3dSmrg width, height)); 663428d7b3dSmrg 664428d7b3dSmrg if (region_is_empty(dst->pCompositeClip)) { 665428d7b3dSmrg DBG(("%s: empty clip, skipping\n", __FUNCTION__)); 666428d7b3dSmrg return; 667428d7b3dSmrg } 668428d7b3dSmrg 669428d7b3dSmrg if (op == PictOpClear) { 670428d7b3dSmrg DBG(("%s: discarding source and mask for clear\n", __FUNCTION__)); 671428d7b3dSmrg mask = NULL; 672428d7b3dSmrg if (sna->clear) 673428d7b3dSmrg src = sna->clear; 674428d7b3dSmrg } 675428d7b3dSmrg 676428d7b3dSmrg if (mask && sna_composite_mask_is_opaque(mask)) { 677428d7b3dSmrg DBG(("%s: removing opaque %smask\n", 678428d7b3dSmrg __FUNCTION__, 679428d7b3dSmrg mask->componentAlpha && PICT_FORMAT_RGB(mask->format) ? "CA " : "")); 680428d7b3dSmrg mask = NULL; 681428d7b3dSmrg } 682428d7b3dSmrg 683428d7b3dSmrg if (!sna_compute_composite_region(®ion, 684428d7b3dSmrg src, mask, dst, 685428d7b3dSmrg src_x, src_y, 686428d7b3dSmrg mask_x, mask_y, 687428d7b3dSmrg dst_x, dst_y, 688428d7b3dSmrg width, height)) 689428d7b3dSmrg return; 690428d7b3dSmrg 691428d7b3dSmrg if (NO_COMPOSITE) 692428d7b3dSmrg goto fallback; 693428d7b3dSmrg 694428d7b3dSmrg if (wedged(sna)) { 695428d7b3dSmrg DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 696428d7b3dSmrg goto fallback; 697428d7b3dSmrg } 698428d7b3dSmrg 699428d7b3dSmrg if (!can_render_to_picture(dst)) { 700428d7b3dSmrg DBG(("%s: fallback due to unhandled picture\n", __FUNCTION__)); 701428d7b3dSmrg goto fallback; 702428d7b3dSmrg } 703428d7b3dSmrg 704428d7b3dSmrg priv = sna_pixmap(pixmap); 705428d7b3dSmrg if (priv == NULL) { 706428d7b3dSmrg DBG(("%s: fallback as destination pixmap=%ld is unattached\n", 707428d7b3dSmrg __FUNCTION__, pixmap->drawable.serialNumber)); 708428d7b3dSmrg goto fallback; 709428d7b3dSmrg } 710428d7b3dSmrg 711428d7b3dSmrg if (use_cpu(pixmap, priv, op, width, height) && 712428d7b3dSmrg !picture_is_gpu(sna, src, PREFER_GPU_RENDER) && 713428d7b3dSmrg !picture_is_gpu(sna, mask, PREFER_GPU_RENDER)) { 714428d7b3dSmrg DBG(("%s: fallback, dst pixmap=%ld is too small (or completely damaged)\n", 715428d7b3dSmrg __FUNCTION__, pixmap->drawable.serialNumber)); 716428d7b3dSmrg goto fallback; 717428d7b3dSmrg } 718428d7b3dSmrg 719428d7b3dSmrg dx = region.extents.x1 - (dst_x + dst->pDrawable->x); 720428d7b3dSmrg dy = region.extents.y1 - (dst_y + dst->pDrawable->y); 721428d7b3dSmrg 722428d7b3dSmrg DBG(("%s: composite region extents:+(%d, %d) -> (%d, %d), (%d, %d) + (%d, %d)\n", 723428d7b3dSmrg __FUNCTION__, 724428d7b3dSmrg dx, dy, 725428d7b3dSmrg region.extents.x1, region.extents.y1, 726428d7b3dSmrg region.extents.x2, region.extents.y2, 727428d7b3dSmrg get_drawable_dx(dst->pDrawable), 728428d7b3dSmrg get_drawable_dy(dst->pDrawable))); 729428d7b3dSmrg 730428d7b3dSmrg if (op <= PictOpSrc && priv->cpu_damage) { 731428d7b3dSmrg int16_t x, y; 732428d7b3dSmrg 733428d7b3dSmrg if (get_drawable_deltas(dst->pDrawable, pixmap, &x, &y)) 734428d7b3dSmrg pixman_region_translate(®ion, x, y); 735428d7b3dSmrg 736428d7b3dSmrg sna_damage_subtract(&priv->cpu_damage, ®ion); 737428d7b3dSmrg if (priv->cpu_damage == NULL) { 738428d7b3dSmrg list_del(&priv->flush_list); 739428d7b3dSmrg priv->cpu = false; 740428d7b3dSmrg } 741428d7b3dSmrg 742428d7b3dSmrg if (x|y) 743428d7b3dSmrg pixman_region_translate(®ion, -x, -y); 744428d7b3dSmrg } 745428d7b3dSmrg 746428d7b3dSmrg if (!sna->render.composite(sna, 747428d7b3dSmrg op, src, mask, dst, 748428d7b3dSmrg src_x + dx, src_y + dy, 749428d7b3dSmrg mask_x + dx, mask_y + dy, 750428d7b3dSmrg region.extents.x1, 751428d7b3dSmrg region.extents.y1, 752428d7b3dSmrg region.extents.x2 - region.extents.x1, 753428d7b3dSmrg region.extents.y2 - region.extents.y1, 754428d7b3dSmrg region.data ? COMPOSITE_PARTIAL : 0, 755428d7b3dSmrg memset(&tmp, 0, sizeof(tmp)))) { 756428d7b3dSmrg DBG(("%s: fallback due unhandled composite op\n", __FUNCTION__)); 757428d7b3dSmrg goto fallback; 758428d7b3dSmrg } 759428d7b3dSmrg 760428d7b3dSmrg if (region.data == NULL) 761428d7b3dSmrg tmp.box(sna, &tmp, ®ion.extents); 762428d7b3dSmrg else 763428d7b3dSmrg tmp.boxes(sna, &tmp, 764428d7b3dSmrg RegionBoxptr(®ion), 765428d7b3dSmrg region_num_rects(®ion)); 766428d7b3dSmrg apply_damage(&tmp, ®ion); 767428d7b3dSmrg tmp.done(sna, &tmp); 768428d7b3dSmrg 769428d7b3dSmrg goto out; 770428d7b3dSmrg 771428d7b3dSmrgfallback: 772428d7b3dSmrg DBG(("%s: fallback -- fbComposite\n", __FUNCTION__)); 773428d7b3dSmrg sna_composite_fb(op, src, mask, dst, ®ion, 774428d7b3dSmrg src_x, src_y, 775428d7b3dSmrg mask_x, mask_y, 776428d7b3dSmrg dst_x, dst_y, 777428d7b3dSmrg width, height); 778428d7b3dSmrgout: 779428d7b3dSmrg REGION_UNINIT(NULL, ®ion); 780428d7b3dSmrg} 781428d7b3dSmrg 782428d7b3dSmrgvoid 783428d7b3dSmrgsna_composite_rectangles(CARD8 op, 784428d7b3dSmrg PicturePtr dst, 785428d7b3dSmrg xRenderColor *color, 786428d7b3dSmrg int num_rects, 787428d7b3dSmrg xRectangle *rects) 788428d7b3dSmrg{ 789428d7b3dSmrg struct sna *sna = to_sna_from_drawable(dst->pDrawable); 790428d7b3dSmrg PixmapPtr pixmap; 791428d7b3dSmrg struct sna_pixmap *priv; 792428d7b3dSmrg struct kgem_bo *bo; 793428d7b3dSmrg struct sna_damage **damage; 794428d7b3dSmrg pixman_region16_t region; 795428d7b3dSmrg pixman_box16_t stack_boxes[64], *boxes = stack_boxes, *b; 796428d7b3dSmrg int16_t dst_x, dst_y; 797428d7b3dSmrg int i, num_boxes; 798428d7b3dSmrg unsigned hint; 799428d7b3dSmrg 800428d7b3dSmrg DBG(("%s(op=%d, %08x x %d [(%d, %d)x(%d, %d) ...])\n", 801428d7b3dSmrg __FUNCTION__, op, 802428d7b3dSmrg (color->alpha >> 8 << 24) | 803428d7b3dSmrg (color->red >> 8 << 16) | 804428d7b3dSmrg (color->green >> 8 << 8) | 805428d7b3dSmrg (color->blue >> 8 << 0), 806428d7b3dSmrg num_rects, 807428d7b3dSmrg rects[0].x, rects[0].y, rects[0].width, rects[0].height)); 808428d7b3dSmrg 809428d7b3dSmrg if (!num_rects) 810428d7b3dSmrg return; 811428d7b3dSmrg 812428d7b3dSmrg if (region_is_empty(dst->pCompositeClip)) { 813428d7b3dSmrg DBG(("%s: empty clip, skipping\n", __FUNCTION__)); 814428d7b3dSmrg return; 815428d7b3dSmrg } 816428d7b3dSmrg 817428d7b3dSmrg if ((color->red|color->green|color->blue|color->alpha) <= 0x00ff) { 818428d7b3dSmrg switch (op) { 819428d7b3dSmrg case PictOpOver: 820428d7b3dSmrg case PictOpOutReverse: 821428d7b3dSmrg case PictOpAdd: 822428d7b3dSmrg return; 823428d7b3dSmrg case PictOpInReverse: 824428d7b3dSmrg case PictOpSrc: 825428d7b3dSmrg op = PictOpClear; 826428d7b3dSmrg break; 827428d7b3dSmrg case PictOpAtopReverse: 828428d7b3dSmrg op = PictOpOut; 829428d7b3dSmrg break; 830428d7b3dSmrg case PictOpXor: 831428d7b3dSmrg op = PictOpOverReverse; 832428d7b3dSmrg break; 833428d7b3dSmrg } 834428d7b3dSmrg } 835428d7b3dSmrg if (color->alpha <= 0x00ff) { 836428d7b3dSmrg switch (op) { 837428d7b3dSmrg case PictOpOver: 838428d7b3dSmrg case PictOpOutReverse: 839428d7b3dSmrg return; 840428d7b3dSmrg case PictOpInReverse: 841428d7b3dSmrg op = PictOpClear; 842428d7b3dSmrg break; 843428d7b3dSmrg case PictOpAtopReverse: 844428d7b3dSmrg op = PictOpOut; 845428d7b3dSmrg break; 846428d7b3dSmrg case PictOpXor: 847428d7b3dSmrg op = PictOpOverReverse; 848428d7b3dSmrg break; 849428d7b3dSmrg } 850428d7b3dSmrg } else if (color->alpha >= 0xff00) { 851428d7b3dSmrg switch (op) { 852428d7b3dSmrg case PictOpOver: 853428d7b3dSmrg op = PictOpSrc; 854428d7b3dSmrg break; 855428d7b3dSmrg case PictOpInReverse: 856428d7b3dSmrg return; 857428d7b3dSmrg case PictOpOutReverse: 858428d7b3dSmrg op = PictOpClear; 859428d7b3dSmrg break; 860428d7b3dSmrg case PictOpAtopReverse: 861428d7b3dSmrg op = PictOpOverReverse; 862428d7b3dSmrg break; 863428d7b3dSmrg case PictOpXor: 864428d7b3dSmrg op = PictOpOut; 865428d7b3dSmrg break; 866428d7b3dSmrg } 867428d7b3dSmrg } 868428d7b3dSmrg 869428d7b3dSmrg /* Avoid reducing overlapping translucent rectangles */ 870428d7b3dSmrg if (op == PictOpOver && 871428d7b3dSmrg num_rects == 1 && 872428d7b3dSmrg sna_drawable_is_clear(dst->pDrawable)) 873428d7b3dSmrg op = PictOpSrc; 874428d7b3dSmrg 875428d7b3dSmrg DBG(("%s: converted to op %d\n", __FUNCTION__, op)); 876428d7b3dSmrg 877428d7b3dSmrg if (num_rects > ARRAY_SIZE(stack_boxes)) { 878428d7b3dSmrg boxes = malloc(sizeof(pixman_box16_t) * num_rects); 879428d7b3dSmrg if (boxes == NULL) 880428d7b3dSmrg return; 881428d7b3dSmrg } 882428d7b3dSmrg 883428d7b3dSmrg for (i = num_boxes = 0; i < num_rects; i++) { 884428d7b3dSmrg boxes[num_boxes].x1 = rects[i].x + dst->pDrawable->x; 885428d7b3dSmrg if (boxes[num_boxes].x1 < dst->pCompositeClip->extents.x1) 886428d7b3dSmrg boxes[num_boxes].x1 = dst->pCompositeClip->extents.x1; 887428d7b3dSmrg 888428d7b3dSmrg boxes[num_boxes].y1 = rects[i].y + dst->pDrawable->y; 889428d7b3dSmrg if (boxes[num_boxes].y1 < dst->pCompositeClip->extents.y1) 890428d7b3dSmrg boxes[num_boxes].y1 = dst->pCompositeClip->extents.y1; 891428d7b3dSmrg 892428d7b3dSmrg boxes[num_boxes].x2 = bound(rects[i].x + dst->pDrawable->x, rects[i].width); 893428d7b3dSmrg if (boxes[num_boxes].x2 > dst->pCompositeClip->extents.x2) 894428d7b3dSmrg boxes[num_boxes].x2 = dst->pCompositeClip->extents.x2; 895428d7b3dSmrg 896428d7b3dSmrg boxes[num_boxes].y2 = bound(rects[i].y + dst->pDrawable->y, rects[i].height); 897428d7b3dSmrg if (boxes[num_boxes].y2 > dst->pCompositeClip->extents.y2) 898428d7b3dSmrg boxes[num_boxes].y2 = dst->pCompositeClip->extents.y2; 899428d7b3dSmrg 900428d7b3dSmrg DBG(("%s[%d] (%d, %d)x(%d, %d) -> (%d, %d), (%d, %d)\n", 901428d7b3dSmrg __FUNCTION__, i, 902428d7b3dSmrg rects[i].x, rects[i].y, rects[i].width, rects[i].height, 903428d7b3dSmrg boxes[num_boxes].x1, boxes[num_boxes].y1, boxes[num_boxes].x2, boxes[num_boxes].y2)); 904428d7b3dSmrg 905428d7b3dSmrg if (boxes[num_boxes].x2 > boxes[num_boxes].x1 && 906428d7b3dSmrg boxes[num_boxes].y2 > boxes[num_boxes].y1) 907428d7b3dSmrg num_boxes++; 908428d7b3dSmrg } 909428d7b3dSmrg 910428d7b3dSmrg if (num_boxes == 0) 911428d7b3dSmrg goto cleanup_boxes; 912428d7b3dSmrg 913428d7b3dSmrg if (!pixman_region_init_rects(®ion, boxes, num_boxes)) 914428d7b3dSmrg goto cleanup_boxes; 915428d7b3dSmrg 916428d7b3dSmrg DBG(("%s: nrects=%d, region=(%d, %d), (%d, %d) x %d\n", 917428d7b3dSmrg __FUNCTION__, num_rects, 918428d7b3dSmrg region.extents.x1, region.extents.y1, 919428d7b3dSmrg region.extents.x2, region.extents.y2, 920428d7b3dSmrg num_boxes)); 921428d7b3dSmrg 922428d7b3dSmrg if (dst->pCompositeClip->data && 923428d7b3dSmrg (!pixman_region_intersect(®ion, ®ion, dst->pCompositeClip) || 924428d7b3dSmrg region_is_empty(®ion))) { 925428d7b3dSmrg DBG(("%s: zero-intersection between rectangles and clip\n", 926428d7b3dSmrg __FUNCTION__)); 927428d7b3dSmrg goto cleanup_region; 928428d7b3dSmrg } 929428d7b3dSmrg 930428d7b3dSmrg DBG(("%s: clipped extents (%d, %d),(%d, %d) x %d\n", 931428d7b3dSmrg __FUNCTION__, 932428d7b3dSmrg RegionExtents(®ion)->x1, RegionExtents(®ion)->y1, 933428d7b3dSmrg RegionExtents(®ion)->x2, RegionExtents(®ion)->y2, 934428d7b3dSmrg region_num_rects(®ion))); 935428d7b3dSmrg 936428d7b3dSmrg /* XXX xserver-1.8: CompositeRects is not tracked by Damage, so we must 937428d7b3dSmrg * manually append the damaged regions ourselves. 938428d7b3dSmrg * 939428d7b3dSmrg * Note that DamageRegionAppend() will apply the drawable-deltas itself. 940428d7b3dSmrg */ 941428d7b3dSmrg DamageRegionAppend(dst->pDrawable, ®ion); 942428d7b3dSmrg 943428d7b3dSmrg pixmap = get_drawable_pixmap(dst->pDrawable); 944428d7b3dSmrg if (get_drawable_deltas(dst->pDrawable, pixmap, &dst_x, &dst_y)) 945428d7b3dSmrg pixman_region_translate(®ion, dst_x, dst_y); 946428d7b3dSmrg 947428d7b3dSmrg DBG(("%s: pixmap +(%d, %d) extents (%d, %d),(%d, %d)\n", 948428d7b3dSmrg __FUNCTION__, dst_x, dst_y, 949428d7b3dSmrg RegionExtents(®ion)->x1, RegionExtents(®ion)->y1, 950428d7b3dSmrg RegionExtents(®ion)->x2, RegionExtents(®ion)->y2)); 951428d7b3dSmrg assert_pixmap_contains_box(pixmap, RegionExtents(®ion)); 952428d7b3dSmrg 953428d7b3dSmrg if (NO_COMPOSITE_RECTANGLES) 954428d7b3dSmrg goto fallback; 955428d7b3dSmrg 956428d7b3dSmrg if (wedged(sna)) 957428d7b3dSmrg goto fallback; 958428d7b3dSmrg 959428d7b3dSmrg if (!can_render_to_picture(dst)) { 960428d7b3dSmrg DBG(("%s: fallback, dst has an incompatible picture\n", __FUNCTION__)); 961428d7b3dSmrg goto fallback; 962428d7b3dSmrg } 963428d7b3dSmrg 964428d7b3dSmrg priv = sna_pixmap(pixmap); 965428d7b3dSmrg if (priv == NULL || too_small(priv)) { 966428d7b3dSmrg DBG(("%s: fallback, dst pixmap=%ld too small or not attached\n", 967428d7b3dSmrg __FUNCTION__, pixmap->drawable.serialNumber)); 968428d7b3dSmrg goto fallback; 969428d7b3dSmrg } 970428d7b3dSmrg 971428d7b3dSmrg /* If we going to be overwriting any CPU damage with a subsequent 972428d7b3dSmrg * operation, then we may as well delete it without moving it 973428d7b3dSmrg * first to the GPU. 974428d7b3dSmrg */ 975428d7b3dSmrg hint = can_render(sna) ? PREFER_GPU : 0; 976428d7b3dSmrg if (op <= PictOpSrc) { 977428d7b3dSmrg if (priv->clear) { 978428d7b3dSmrg uint32_t pixel; 979428d7b3dSmrg bool ok; 980428d7b3dSmrg 981428d7b3dSmrg if (op == PictOpClear) { 982428d7b3dSmrg ok = sna_get_pixel_from_rgba(&pixel, 983428d7b3dSmrg 0, 0, 0, 0, 984428d7b3dSmrg dst->format); 985428d7b3dSmrg } else { 986428d7b3dSmrg ok = sna_get_pixel_from_rgba(&pixel, 987428d7b3dSmrg color->red, 988428d7b3dSmrg color->green, 989428d7b3dSmrg color->blue, 990428d7b3dSmrg color->alpha, 991428d7b3dSmrg dst->format); 992428d7b3dSmrg } 993428d7b3dSmrg if (ok && priv->clear_color == pixel) 994428d7b3dSmrg goto done; 995428d7b3dSmrg } 996428d7b3dSmrg 997428d7b3dSmrg if (region.data == NULL) { 998428d7b3dSmrg hint |= IGNORE_DAMAGE; 999428d7b3dSmrg if (region_subsumes_drawable(®ion, &pixmap->drawable)) 1000428d7b3dSmrg hint |= REPLACES; 1001428d7b3dSmrg if (priv->cpu_damage && 1002428d7b3dSmrg (hint & REPLACES || 1003428d7b3dSmrg region_subsumes_damage(®ion, priv->cpu_damage))) { 1004428d7b3dSmrg DBG(("%s: discarding existing CPU damage\n", __FUNCTION__)); 1005428d7b3dSmrg if (priv->gpu_bo && priv->gpu_bo->proxy) { 1006428d7b3dSmrg assert(priv->gpu_damage == NULL); 1007428d7b3dSmrg kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 1008428d7b3dSmrg priv->gpu_bo = NULL; 1009428d7b3dSmrg } 1010428d7b3dSmrg sna_damage_destroy(&priv->cpu_damage); 1011428d7b3dSmrg list_del(&priv->flush_list); 1012428d7b3dSmrg } 1013428d7b3dSmrg if (hint & REPLACES || 1014428d7b3dSmrg box_inplace(pixmap, ®ion.extents)) { 1015428d7b3dSmrg if (priv->gpu_bo && priv->cpu_damage == NULL) { 1016428d7b3dSmrg DBG(("%s: promoting to full GPU\n", __FUNCTION__)); 1017428d7b3dSmrg assert(priv->gpu_bo->proxy == NULL); 1018428d7b3dSmrg sna_damage_all(&priv->gpu_damage, pixmap); 1019428d7b3dSmrg } 1020428d7b3dSmrg } 1021428d7b3dSmrg } 1022428d7b3dSmrg if (priv->cpu_damage == NULL) { 1023428d7b3dSmrg DBG(("%s: dropping last-cpu hint\n", __FUNCTION__)); 1024428d7b3dSmrg priv->cpu = false; 1025428d7b3dSmrg } 1026428d7b3dSmrg } 1027428d7b3dSmrg 1028428d7b3dSmrg bo = sna_drawable_use_bo(&pixmap->drawable, hint, 1029428d7b3dSmrg ®ion.extents, &damage); 1030428d7b3dSmrg if (bo == NULL) { 1031428d7b3dSmrg DBG(("%s: fallback due to no GPU bo\n", __FUNCTION__)); 1032428d7b3dSmrg goto fallback; 1033428d7b3dSmrg } 1034428d7b3dSmrg if (hint & REPLACES) 1035428d7b3dSmrg kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo); 1036428d7b3dSmrg 1037428d7b3dSmrg if (op <= PictOpSrc) { 1038428d7b3dSmrg b = pixman_region_rectangles(®ion, &num_boxes); 1039428d7b3dSmrg if (!sna->render.fill_boxes(sna, op, dst->format, color, 1040428d7b3dSmrg &pixmap->drawable, bo, b, num_boxes)) { 1041428d7b3dSmrg DBG(("%s: fallback - acceleration failed\n", __FUNCTION__)); 1042428d7b3dSmrg goto fallback; 1043428d7b3dSmrg } 1044428d7b3dSmrg } else if (dst->pCompositeClip->data == NULL) { 1045428d7b3dSmrg for (i = 0; i < num_boxes; i++) { 1046428d7b3dSmrg boxes[i].x1 += dst_x; 1047428d7b3dSmrg boxes[i].x2 += dst_x; 1048428d7b3dSmrg boxes[i].y1 += dst_y; 1049428d7b3dSmrg boxes[i].y2 += dst_y; 1050428d7b3dSmrg } 1051428d7b3dSmrg if (!sna->render.fill_boxes(sna, op, dst->format, color, 1052428d7b3dSmrg &pixmap->drawable, bo, boxes, num_boxes)) { 1053428d7b3dSmrg DBG(("%s: fallback - acceleration failed\n", __FUNCTION__)); 1054428d7b3dSmrg goto fallback; 1055428d7b3dSmrg } 1056428d7b3dSmrg } else { 1057428d7b3dSmrg for (i = 0; i < num_boxes; i++) { 1058428d7b3dSmrg RegionRec tmp = { boxes[i] }; 1059428d7b3dSmrg if (pixman_region_intersect(&tmp, &tmp, dst->pCompositeClip)) { 1060428d7b3dSmrg int n = 0; 1061428d7b3dSmrg 1062428d7b3dSmrg b = pixman_region_rectangles(&tmp, &n); 1063428d7b3dSmrg if (n) { 1064428d7b3dSmrg if (dst_x | dst_y) 1065428d7b3dSmrg pixman_region_translate(&tmp, dst_x, dst_y); 1066428d7b3dSmrg 1067428d7b3dSmrg n = !sna->render.fill_boxes(sna, op, dst->format, color, 1068428d7b3dSmrg &pixmap->drawable, bo, b, n); 1069428d7b3dSmrg } 1070428d7b3dSmrg 1071428d7b3dSmrg pixman_region_fini(&tmp); 1072428d7b3dSmrg 1073428d7b3dSmrg if (n) { 1074428d7b3dSmrg DBG(("%s: fallback - acceleration failed\n", __FUNCTION__)); 1075428d7b3dSmrg goto fallback; 1076428d7b3dSmrg } 1077428d7b3dSmrg } 1078428d7b3dSmrg } 1079428d7b3dSmrg } 1080428d7b3dSmrg 1081428d7b3dSmrg if (damage) 1082428d7b3dSmrg sna_damage_add(damage, ®ion); 1083428d7b3dSmrg 1084428d7b3dSmrg /* Clearing a pixmap after creation is a common operation, so take 1085428d7b3dSmrg * advantage and reduce further damage operations. 1086428d7b3dSmrg */ 1087428d7b3dSmrg if (region_subsumes_drawable(®ion, &pixmap->drawable)) { 1088428d7b3dSmrg if (damage) { 1089428d7b3dSmrg sna_damage_all(damage, pixmap); 1090428d7b3dSmrg sna_damage_destroy(damage == &priv->gpu_damage ? 1091428d7b3dSmrg &priv->cpu_damage : &priv->gpu_damage); 1092428d7b3dSmrg } 1093428d7b3dSmrg 1094428d7b3dSmrg if (op <= PictOpSrc && bo == priv->gpu_bo) { 1095428d7b3dSmrg bool ok; 1096428d7b3dSmrg 1097428d7b3dSmrg assert(DAMAGE_IS_ALL(priv->gpu_damage)); 1098428d7b3dSmrg 1099428d7b3dSmrg priv->clear_color = 0; 1100428d7b3dSmrg ok = true; 1101428d7b3dSmrg if (op == PictOpSrc) 1102428d7b3dSmrg ok = sna_get_pixel_from_rgba(&priv->clear_color, 1103428d7b3dSmrg color->red, 1104428d7b3dSmrg color->green, 1105428d7b3dSmrg color->blue, 1106428d7b3dSmrg color->alpha, 1107428d7b3dSmrg dst->format); 1108428d7b3dSmrg priv->clear = ok; 1109428d7b3dSmrg DBG(("%s: pixmap=%ld marking clear [%08x]? %d\n", 1110428d7b3dSmrg __FUNCTION__, pixmap->drawable.serialNumber, 1111428d7b3dSmrg priv->clear_color, ok)); 1112428d7b3dSmrg } 1113428d7b3dSmrg } 1114428d7b3dSmrg goto done; 1115428d7b3dSmrg 1116428d7b3dSmrgfallback: 1117428d7b3dSmrg DBG(("%s: fallback\n", __FUNCTION__)); 1118428d7b3dSmrg if (op <= PictOpSrc) 1119428d7b3dSmrg hint = MOVE_WRITE; 1120428d7b3dSmrg else 1121428d7b3dSmrg hint = MOVE_WRITE | MOVE_READ; 1122428d7b3dSmrg if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, ®ion, hint)) 1123428d7b3dSmrg goto done; 1124428d7b3dSmrg 1125428d7b3dSmrg if (dst->alphaMap && 1126428d7b3dSmrg !sna_drawable_move_to_cpu(dst->alphaMap->pDrawable, hint)) 1127428d7b3dSmrg goto done; 1128428d7b3dSmrg 1129428d7b3dSmrg assert(pixmap->devPrivate.ptr); 1130428d7b3dSmrg 1131428d7b3dSmrg if (sigtrap_get() == 0) { 1132428d7b3dSmrg if (op <= PictOpSrc) { 1133428d7b3dSmrg int nbox = region_num_rects(®ion); 1134428d7b3dSmrg const BoxRec *box = region_rects(®ion); 1135428d7b3dSmrg uint32_t pixel; 1136428d7b3dSmrg 1137428d7b3dSmrg if (op == PictOpClear) 1138428d7b3dSmrg pixel = 0; 1139428d7b3dSmrg else if (!sna_get_pixel_from_rgba(&pixel, 1140428d7b3dSmrg color->red, 1141428d7b3dSmrg color->green, 1142428d7b3dSmrg color->blue, 1143428d7b3dSmrg color->alpha, 1144428d7b3dSmrg dst->format)) 1145428d7b3dSmrg goto fallback_composite; 1146428d7b3dSmrg 1147428d7b3dSmrg sigtrap_assert_active(); 1148428d7b3dSmrg if (pixel == 0 && 1149428d7b3dSmrg box->x2 - box->x1 == pixmap->drawable.width && 1150428d7b3dSmrg box->y2 - box->y1 == pixmap->drawable.height) { 1151428d7b3dSmrg memset(pixmap->devPrivate.ptr, 0, 1152428d7b3dSmrg pixmap->devKind*pixmap->drawable.height); 1153428d7b3dSmrg } else do { 1154428d7b3dSmrg DBG(("%s: fallback fill: (%d, %d)x(%d, %d) %08x\n", 1155428d7b3dSmrg __FUNCTION__, 1156428d7b3dSmrg box->x1, box->y1, 1157428d7b3dSmrg box->x2 - box->x1, 1158428d7b3dSmrg box->y2 - box->y1, 1159428d7b3dSmrg pixel)); 1160428d7b3dSmrg 1161428d7b3dSmrg pixman_fill(pixmap->devPrivate.ptr, 1162428d7b3dSmrg pixmap->devKind/sizeof(uint32_t), 1163428d7b3dSmrg pixmap->drawable.bitsPerPixel, 1164428d7b3dSmrg box->x1, box->y1, 1165428d7b3dSmrg box->x2 - box->x1, 1166428d7b3dSmrg box->y2 - box->y1, 1167428d7b3dSmrg pixel); 1168428d7b3dSmrg box++; 1169428d7b3dSmrg } while (--nbox); 1170428d7b3dSmrg } else { 1171428d7b3dSmrg PicturePtr src; 1172428d7b3dSmrg int error; 1173428d7b3dSmrg 1174428d7b3dSmrgfallback_composite: 1175428d7b3dSmrg DBG(("%s: fallback -- fbComposite()\n", __FUNCTION__)); 1176428d7b3dSmrg src = CreateSolidPicture(0, color, &error); 1177428d7b3dSmrg if (src) { 1178428d7b3dSmrg do { 1179428d7b3dSmrg fbComposite(op, src, NULL, dst, 1180428d7b3dSmrg 0, 0, 1181428d7b3dSmrg 0, 0, 1182428d7b3dSmrg rects->x, rects->y, 1183428d7b3dSmrg rects->width, rects->height); 1184428d7b3dSmrg rects++; 1185428d7b3dSmrg } while (--num_rects); 1186428d7b3dSmrg FreePicture(src, 0); 1187428d7b3dSmrg } 1188428d7b3dSmrg } 1189428d7b3dSmrg sigtrap_put(); 1190428d7b3dSmrg } 1191428d7b3dSmrg 1192428d7b3dSmrgdone: 1193428d7b3dSmrg DamageRegionProcessPending(dst->pDrawable); 1194428d7b3dSmrg 1195428d7b3dSmrgcleanup_region: 1196428d7b3dSmrg pixman_region_fini(®ion); 1197428d7b3dSmrgcleanup_boxes: 1198428d7b3dSmrg if (boxes != stack_boxes) 1199428d7b3dSmrg free(boxes); 1200428d7b3dSmrg} 1201