1428d7b3dSmrg/* 2428d7b3dSmrg * Copyright © 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#define NO_REDIRECT 0 38428d7b3dSmrg#define NO_CONVERT 0 39428d7b3dSmrg#define NO_FIXUP 0 40428d7b3dSmrg#define NO_EXTRACT 0 41428d7b3dSmrg 42428d7b3dSmrg#define DBG_FORCE_UPLOAD 0 43428d7b3dSmrg#define DBG_NO_CPU_BO 0 44428d7b3dSmrg 45428d7b3dSmrg#define alphaless(format) PICT_FORMAT(PICT_FORMAT_BPP(format), \ 46428d7b3dSmrg PICT_FORMAT_TYPE(format), \ 47428d7b3dSmrg 0, \ 48428d7b3dSmrg PICT_FORMAT_R(format), \ 49428d7b3dSmrg PICT_FORMAT_G(format), \ 50428d7b3dSmrg PICT_FORMAT_B(format)) 51428d7b3dSmrg 52428d7b3dSmrgCARD32 53428d7b3dSmrgsna_format_for_depth(int depth) 54428d7b3dSmrg{ 55428d7b3dSmrg switch (depth) { 56428d7b3dSmrg case 1: return PICT_a1; 57428d7b3dSmrg case 4: return PICT_a4; 58428d7b3dSmrg case 8: return PICT_a8; 59428d7b3dSmrg case 15: return PICT_x1r5g5b5; 60428d7b3dSmrg case 16: return PICT_r5g6b5; 61428d7b3dSmrg default: assert(0); 62428d7b3dSmrg case 24: return PICT_x8r8g8b8; 63428d7b3dSmrg#ifdef PICT_x2r10g10b10 64428d7b3dSmrg case 30: return PICT_x2r10g10b10; 65428d7b3dSmrg#endif 66428d7b3dSmrg case 32: return PICT_a8r8g8b8; 67428d7b3dSmrg } 68428d7b3dSmrg} 69428d7b3dSmrg 70428d7b3dSmrgCARD32 71428d7b3dSmrgsna_render_format_for_depth(int depth) 72428d7b3dSmrg{ 73428d7b3dSmrg switch (depth) { 74428d7b3dSmrg case 1: return PIXMAN_a1; 75428d7b3dSmrg case 4: return PIXMAN_a4; 76428d7b3dSmrg case 8: return PIXMAN_a8; 77428d7b3dSmrg case 15: return PIXMAN_a1r5g5b5; 78428d7b3dSmrg case 16: return PIXMAN_r5g6b5; 79428d7b3dSmrg case 30: return PIXMAN_a2r10g10b10; 80428d7b3dSmrg default: assert(0); 81428d7b3dSmrg case 24: 82428d7b3dSmrg case 32: return PIXMAN_a8r8g8b8; 83428d7b3dSmrg } 84428d7b3dSmrg} 85428d7b3dSmrg 86428d7b3dSmrgstatic bool 87428d7b3dSmrgno_render_composite(struct sna *sna, 88428d7b3dSmrg uint8_t op, 89428d7b3dSmrg PicturePtr src, 90428d7b3dSmrg PicturePtr mask, 91428d7b3dSmrg PicturePtr dst, 92428d7b3dSmrg int16_t src_x, int16_t src_y, 93428d7b3dSmrg int16_t mask_x, int16_t mask_y, 94428d7b3dSmrg int16_t dst_x, int16_t dst_y, 95428d7b3dSmrg int16_t width, int16_t height, 96428d7b3dSmrg unsigned flags, 97428d7b3dSmrg struct sna_composite_op *tmp) 98428d7b3dSmrg{ 99428d7b3dSmrg DBG(("%s (op=%d, mask? %d)\n", __FUNCTION__, op, mask != NULL)); 100428d7b3dSmrg 101428d7b3dSmrg if (mask) 102428d7b3dSmrg return false; 103428d7b3dSmrg 104428d7b3dSmrg if (!is_gpu(sna, dst->pDrawable, PREFER_GPU_BLT) && 105428d7b3dSmrg (src->pDrawable == NULL || !is_gpu(sna, src->pDrawable, PREFER_GPU_BLT))) 106428d7b3dSmrg return false; 107428d7b3dSmrg 108428d7b3dSmrg return sna_blt_composite(sna, 109428d7b3dSmrg op, src, dst, 110428d7b3dSmrg src_x, src_y, 111428d7b3dSmrg dst_x, dst_y, 112428d7b3dSmrg width, height, 113428d7b3dSmrg flags | COMPOSITE_FALLBACK, tmp); 114428d7b3dSmrg (void)mask_x; 115428d7b3dSmrg (void)mask_y; 116428d7b3dSmrg} 117428d7b3dSmrg 118428d7b3dSmrgstatic bool 119428d7b3dSmrgno_render_check_composite_spans(struct sna *sna, 120428d7b3dSmrg uint8_t op, PicturePtr src, PicturePtr dst, 121428d7b3dSmrg int16_t width, int16_t height, unsigned flags) 122428d7b3dSmrg{ 123428d7b3dSmrg return false; 124428d7b3dSmrg} 125428d7b3dSmrg 126428d7b3dSmrgstatic bool 127428d7b3dSmrgno_render_copy_boxes(struct sna *sna, uint8_t alu, 128428d7b3dSmrg const DrawableRec *src, struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy, 129428d7b3dSmrg const DrawableRec *dst, struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy, 130428d7b3dSmrg const BoxRec *box, int n, unsigned flags) 131428d7b3dSmrg{ 132428d7b3dSmrg DBG(("%s (n=%d)\n", __FUNCTION__, n)); 133428d7b3dSmrg 134428d7b3dSmrg if (!sna_blt_compare_depth(src, dst)) 135428d7b3dSmrg return false; 136428d7b3dSmrg 137428d7b3dSmrg return sna_blt_copy_boxes(sna, alu, 138428d7b3dSmrg src_bo, src_dx, src_dy, 139428d7b3dSmrg dst_bo, dst_dx, dst_dy, 140428d7b3dSmrg dst->bitsPerPixel, 141428d7b3dSmrg box, n); 142428d7b3dSmrg} 143428d7b3dSmrg 144428d7b3dSmrgstatic bool 145428d7b3dSmrgno_render_copy(struct sna *sna, uint8_t alu, 146428d7b3dSmrg PixmapPtr src, struct kgem_bo *src_bo, 147428d7b3dSmrg PixmapPtr dst, struct kgem_bo *dst_bo, 148428d7b3dSmrg struct sna_copy_op *tmp) 149428d7b3dSmrg{ 150428d7b3dSmrg DBG(("%s ()\n", __FUNCTION__)); 151428d7b3dSmrg 152428d7b3dSmrg if (sna_blt_compare_depth(&src->drawable, &dst->drawable) && 153428d7b3dSmrg sna_blt_copy(sna, alu, 154428d7b3dSmrg src_bo, dst_bo, dst->drawable.bitsPerPixel, 155428d7b3dSmrg tmp)) 156428d7b3dSmrg return true; 157428d7b3dSmrg 158428d7b3dSmrg return false; 159428d7b3dSmrg} 160428d7b3dSmrg 161428d7b3dSmrgstatic bool 162428d7b3dSmrgno_render_fill_boxes(struct sna *sna, 163428d7b3dSmrg CARD8 op, 164428d7b3dSmrg PictFormat format, 165428d7b3dSmrg const xRenderColor *color, 166428d7b3dSmrg const DrawableRec *dst, struct kgem_bo *dst_bo, 167428d7b3dSmrg const BoxRec *box, int n) 168428d7b3dSmrg{ 169428d7b3dSmrg uint8_t alu = GXcopy; 170428d7b3dSmrg uint32_t pixel; 171428d7b3dSmrg 172428d7b3dSmrg DBG(("%s (op=%d, color=(%04x,%04x,%04x, %04x))\n", 173428d7b3dSmrg __FUNCTION__, op, 174428d7b3dSmrg color->red, color->green, color->blue, color->alpha)); 175428d7b3dSmrg 176428d7b3dSmrg if (op == PictOpClear) { 177428d7b3dSmrg pixel = 0; 178428d7b3dSmrg alu = GXclear; 179428d7b3dSmrg op = PictOpSrc; 180428d7b3dSmrg } 181428d7b3dSmrg 182428d7b3dSmrg if (op == PictOpOver) { 183428d7b3dSmrg if ((color->alpha >= 0xff00)) 184428d7b3dSmrg op = PictOpSrc; 185428d7b3dSmrg } 186428d7b3dSmrg 187428d7b3dSmrg if (op != PictOpSrc) 188428d7b3dSmrg return false; 189428d7b3dSmrg 190428d7b3dSmrg if (alu == GXcopy && 191428d7b3dSmrg !sna_get_pixel_from_rgba(&pixel, 192428d7b3dSmrg color->red, 193428d7b3dSmrg color->green, 194428d7b3dSmrg color->blue, 195428d7b3dSmrg color->alpha, 196428d7b3dSmrg format)) 197428d7b3dSmrg return false; 198428d7b3dSmrg 199428d7b3dSmrg return sna_blt_fill_boxes(sna, alu, 200428d7b3dSmrg dst_bo, dst->bitsPerPixel, 201428d7b3dSmrg pixel, box, n); 202428d7b3dSmrg} 203428d7b3dSmrg 204428d7b3dSmrgstatic bool 205428d7b3dSmrgno_render_fill(struct sna *sna, uint8_t alu, 206428d7b3dSmrg PixmapPtr dst, struct kgem_bo *dst_bo, 207428d7b3dSmrg uint32_t color, unsigned flags, 208428d7b3dSmrg struct sna_fill_op *tmp) 209428d7b3dSmrg{ 210428d7b3dSmrg DBG(("%s (alu=%d, color=%08x)\n", __FUNCTION__, alu, color)); 211428d7b3dSmrg return sna_blt_fill(sna, alu, 212428d7b3dSmrg dst_bo, dst->drawable.bitsPerPixel, 213428d7b3dSmrg color, 214428d7b3dSmrg tmp); 215428d7b3dSmrg} 216428d7b3dSmrg 217428d7b3dSmrgstatic bool 218428d7b3dSmrgno_render_fill_one(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo, 219428d7b3dSmrg uint32_t color, 220428d7b3dSmrg int16_t x1, int16_t y1, int16_t x2, int16_t y2, 221428d7b3dSmrg uint8_t alu) 222428d7b3dSmrg{ 223428d7b3dSmrg BoxRec box; 224428d7b3dSmrg 225428d7b3dSmrg box.x1 = x1; 226428d7b3dSmrg box.y1 = y1; 227428d7b3dSmrg box.x2 = x2; 228428d7b3dSmrg box.y2 = y2; 229428d7b3dSmrg 230428d7b3dSmrg DBG(("%s (alu=%d, color=%08x) (%d,%d), (%d, %d)\n", 231428d7b3dSmrg __FUNCTION__, alu, color, x1, y1, x2, y2)); 232428d7b3dSmrg return sna_blt_fill_boxes(sna, alu, 233428d7b3dSmrg bo, dst->drawable.bitsPerPixel, 234428d7b3dSmrg color, &box, 1); 235428d7b3dSmrg} 236428d7b3dSmrg 237428d7b3dSmrgstatic bool 238428d7b3dSmrgno_render_clear(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo) 239428d7b3dSmrg{ 240428d7b3dSmrg DBG(("%s: pixmap=%ld %dx%d\n", __FUNCTION__, 241428d7b3dSmrg dst->drawable.serialNumber, 242428d7b3dSmrg dst->drawable.width, 243428d7b3dSmrg dst->drawable.height)); 244428d7b3dSmrg return sna->render.fill_one(sna, dst, bo, 0, 245428d7b3dSmrg 0, 0, dst->drawable.width, dst->drawable.height, 246428d7b3dSmrg GXclear); 247428d7b3dSmrg} 248428d7b3dSmrg 249428d7b3dSmrgstatic void no_render_reset(struct sna *sna) 250428d7b3dSmrg{ 251428d7b3dSmrg (void)sna; 252428d7b3dSmrg} 253428d7b3dSmrg 254428d7b3dSmrgstatic void no_render_flush(struct sna *sna) 255428d7b3dSmrg{ 256428d7b3dSmrg (void)sna; 257428d7b3dSmrg} 258428d7b3dSmrg 259428d7b3dSmrgstatic void 260428d7b3dSmrgno_render_context_switch(struct kgem *kgem, 261428d7b3dSmrg int new_mode) 262428d7b3dSmrg{ 263428d7b3dSmrg if (!kgem->nbatch) 264428d7b3dSmrg return; 265428d7b3dSmrg 266428d7b3dSmrg if (kgem_ring_is_idle(kgem, kgem->ring)) { 267428d7b3dSmrg DBG(("%s: GPU idle, flushing\n", __FUNCTION__)); 268428d7b3dSmrg _kgem_submit(kgem); 269428d7b3dSmrg } 270428d7b3dSmrg 271428d7b3dSmrg (void)new_mode; 272428d7b3dSmrg} 273428d7b3dSmrg 274428d7b3dSmrgstatic void 275428d7b3dSmrgno_render_retire(struct kgem *kgem) 276428d7b3dSmrg{ 277428d7b3dSmrg (void)kgem; 278428d7b3dSmrg} 279428d7b3dSmrg 280428d7b3dSmrgstatic void 281428d7b3dSmrgno_render_expire(struct kgem *kgem) 282428d7b3dSmrg{ 283428d7b3dSmrg (void)kgem; 284428d7b3dSmrg} 285428d7b3dSmrg 286428d7b3dSmrgstatic void 287428d7b3dSmrgno_render_fini(struct sna *sna) 288428d7b3dSmrg{ 289428d7b3dSmrg (void)sna; 290428d7b3dSmrg} 291428d7b3dSmrg 292428d7b3dSmrgconst char *no_render_init(struct sna *sna) 293428d7b3dSmrg{ 294428d7b3dSmrg struct sna_render *render = &sna->render; 295428d7b3dSmrg 296428d7b3dSmrg memset (render, 0, sizeof (*render)); 297428d7b3dSmrg 298428d7b3dSmrg render->prefer_gpu = PREFER_GPU_BLT; 299428d7b3dSmrg 300428d7b3dSmrg render->vertices = render->vertex_data; 301428d7b3dSmrg render->vertex_size = ARRAY_SIZE(render->vertex_data); 302428d7b3dSmrg 303428d7b3dSmrg render->composite = no_render_composite; 304428d7b3dSmrg render->check_composite_spans = no_render_check_composite_spans; 305428d7b3dSmrg 306428d7b3dSmrg render->copy_boxes = no_render_copy_boxes; 307428d7b3dSmrg render->copy = no_render_copy; 308428d7b3dSmrg 309428d7b3dSmrg render->fill_boxes = no_render_fill_boxes; 310428d7b3dSmrg render->fill = no_render_fill; 311428d7b3dSmrg render->fill_one = no_render_fill_one; 312428d7b3dSmrg render->clear = no_render_clear; 313428d7b3dSmrg 314428d7b3dSmrg render->reset = no_render_reset; 315428d7b3dSmrg render->flush = no_render_flush; 316428d7b3dSmrg render->fini = no_render_fini; 317428d7b3dSmrg 318428d7b3dSmrg sna->kgem.context_switch = no_render_context_switch; 319428d7b3dSmrg sna->kgem.retire = no_render_retire; 320428d7b3dSmrg sna->kgem.expire = no_render_expire; 321428d7b3dSmrg if (sna->kgem.has_blt) 322428d7b3dSmrg sna->kgem.ring = KGEM_BLT; 323428d7b3dSmrg 324428d7b3dSmrg sna_vertex_init(sna); 325428d7b3dSmrg return "generic"; 326428d7b3dSmrg} 327428d7b3dSmrg 328428d7b3dSmrgstatic struct kgem_bo * 329428d7b3dSmrguse_cpu_bo(struct sna *sna, PixmapPtr pixmap, const BoxRec *box, bool blt) 330428d7b3dSmrg{ 331428d7b3dSmrg struct sna_pixmap *priv; 332428d7b3dSmrg 333428d7b3dSmrg if (DBG_NO_CPU_BO) 334428d7b3dSmrg return NULL; 335428d7b3dSmrg 336428d7b3dSmrg priv = sna_pixmap(pixmap); 337428d7b3dSmrg if (priv == NULL || priv->cpu_bo == NULL) { 338428d7b3dSmrg DBG(("%s: no cpu bo\n", __FUNCTION__)); 339428d7b3dSmrg return NULL; 340428d7b3dSmrg } 341428d7b3dSmrg 342428d7b3dSmrg if (!blt && priv->cpu_bo->snoop && priv->source_count > SOURCE_BIAS) { 343428d7b3dSmrg DBG(("%s: promoting snooped CPU bo due to reuse\n", 344428d7b3dSmrg __FUNCTION__)); 345428d7b3dSmrg return NULL; 346428d7b3dSmrg } 347428d7b3dSmrg 348428d7b3dSmrg if (priv->gpu_bo) { 349428d7b3dSmrg switch (sna_damage_contains_box(&priv->cpu_damage, box)) { 350428d7b3dSmrg case PIXMAN_REGION_OUT: 351428d7b3dSmrg DBG(("%s: has GPU bo and no damage to upload\n", 352428d7b3dSmrg __FUNCTION__)); 353428d7b3dSmrg return NULL; 354428d7b3dSmrg 355428d7b3dSmrg case PIXMAN_REGION_IN: 356428d7b3dSmrg DBG(("%s: has GPU bo but box is completely on CPU\n", 357428d7b3dSmrg __FUNCTION__)); 358428d7b3dSmrg break; 359428d7b3dSmrg default: 360428d7b3dSmrg if (kgem_bo_is_busy(priv->gpu_bo)){ 361428d7b3dSmrg DBG(("%s: box is partially damaged on the CPU, and the GPU is busy\n", 362428d7b3dSmrg __FUNCTION__)); 363428d7b3dSmrg return NULL; 364428d7b3dSmrg } 365428d7b3dSmrg if (sna_damage_contains_box(&priv->gpu_damage, 366428d7b3dSmrg box) != PIXMAN_REGION_OUT) { 367428d7b3dSmrg DBG(("%s: box is damaged on the GPU\n", 368428d7b3dSmrg __FUNCTION__)); 369428d7b3dSmrg return NULL; 370428d7b3dSmrg } 371428d7b3dSmrg break; 372428d7b3dSmrg } 373428d7b3dSmrg } 374428d7b3dSmrg 375428d7b3dSmrg if (!blt) { 376428d7b3dSmrg int w = box->x2 - box->x1; 377428d7b3dSmrg int h = box->y2 - box->y1; 378428d7b3dSmrg 379428d7b3dSmrg if (w < pixmap->drawable.width || 380428d7b3dSmrg h < pixmap->drawable.height || 381428d7b3dSmrg priv->source_count != SOURCE_BIAS) { 382428d7b3dSmrg bool want_tiling; 383428d7b3dSmrg 384428d7b3dSmrg if (priv->cpu_bo->pitch >= 4096) { 385428d7b3dSmrg DBG(("%s: size=%dx%d, promoting reused (%d) CPU bo due to TLB miss (%dx%d, pitch=%d)\n", 386428d7b3dSmrg __FUNCTION__, w, h, priv->source_count, 387428d7b3dSmrg pixmap->drawable.width, 388428d7b3dSmrg pixmap->drawable.height, 389428d7b3dSmrg priv->cpu_bo->pitch)); 390428d7b3dSmrg return NULL; 391428d7b3dSmrg } 392428d7b3dSmrg 393428d7b3dSmrg if (priv->gpu_bo) 394428d7b3dSmrg want_tiling = priv->gpu_bo->tiling != I915_TILING_NONE; 395428d7b3dSmrg else 396428d7b3dSmrg want_tiling = kgem_choose_tiling(&sna->kgem, 397428d7b3dSmrg I915_TILING_Y, 398428d7b3dSmrg pixmap->drawable.width, 399428d7b3dSmrg pixmap->drawable.height, 400428d7b3dSmrg pixmap->drawable.bitsPerPixel) != I915_TILING_NONE; 401428d7b3dSmrg if (want_tiling && 402428d7b3dSmrg priv->source_count*w*h >= (int)pixmap->drawable.width * pixmap->drawable.height) { 403428d7b3dSmrg DBG(("%s: pitch (%d) requires tiling\n", 404428d7b3dSmrg __FUNCTION__, priv->cpu_bo->pitch)); 405428d7b3dSmrg return NULL; 406428d7b3dSmrg } 407428d7b3dSmrg } 408428d7b3dSmrg } 409428d7b3dSmrg 410428d7b3dSmrg if (priv->shm) { 411428d7b3dSmrg assert(!priv->flush); 412428d7b3dSmrg sna_add_flush_pixmap(sna, priv, priv->cpu_bo); 413428d7b3dSmrg } 414428d7b3dSmrg 415428d7b3dSmrg DBG(("%s for box=(%d, %d), (%d, %d)\n", 416428d7b3dSmrg __FUNCTION__, box->x1, box->y1, box->x2, box->y2)); 417428d7b3dSmrg ++priv->source_count; 418428d7b3dSmrg return priv->cpu_bo; 419428d7b3dSmrg} 420428d7b3dSmrg 421428d7b3dSmrgstatic struct kgem_bo * 422428d7b3dSmrgmove_to_gpu(PixmapPtr pixmap, const BoxRec *box, bool blt) 423428d7b3dSmrg{ 424428d7b3dSmrg struct sna_pixmap *priv; 425428d7b3dSmrg int count, w, h; 426428d7b3dSmrg bool migrate = false; 427428d7b3dSmrg 428428d7b3dSmrg if (DBG_FORCE_UPLOAD > 0) 429428d7b3dSmrg return NULL; 430428d7b3dSmrg 431428d7b3dSmrg priv = sna_pixmap(pixmap); 432428d7b3dSmrg if (priv == NULL) { 433428d7b3dSmrg DBG(("%s: not migrating unattached pixmap=%ld\n", 434428d7b3dSmrg __FUNCTION__, pixmap->drawable.serialNumber)); 435428d7b3dSmrg return NULL; 436428d7b3dSmrg } 437428d7b3dSmrg 438428d7b3dSmrg if (priv->shm) 439428d7b3dSmrg blt = true; 440428d7b3dSmrg 441428d7b3dSmrg if (priv->gpu_bo) { 442428d7b3dSmrg if (priv->cpu_damage && 443428d7b3dSmrg sna_damage_contains_box(&priv->cpu_damage, 444428d7b3dSmrg box) != PIXMAN_REGION_OUT) 445428d7b3dSmrg goto upload; 446428d7b3dSmrg 447428d7b3dSmrg return priv->gpu_bo; 448428d7b3dSmrg } 449428d7b3dSmrg 450428d7b3dSmrg if (priv->cpu_damage == NULL) { 451428d7b3dSmrg DBG(("%s: not migrating uninitialised pixmap=%ld\n", 452428d7b3dSmrg __FUNCTION__, pixmap->drawable.serialNumber)); 453428d7b3dSmrg return NULL; 454428d7b3dSmrg } 455428d7b3dSmrg 456428d7b3dSmrg if (pixmap->usage_hint) { 457428d7b3dSmrg DBG(("%s: not migrating pixmap=%ld due to usage_hint=%d\n", 458428d7b3dSmrg __FUNCTION__, 459428d7b3dSmrg pixmap->drawable.serialNumber, 460428d7b3dSmrg pixmap->usage_hint)); 461428d7b3dSmrg return NULL; 462428d7b3dSmrg } 463428d7b3dSmrg 464428d7b3dSmrg if (DBG_FORCE_UPLOAD < 0) { 465428d7b3dSmrg if (!sna_pixmap_force_to_gpu(pixmap, 466428d7b3dSmrg blt ? MOVE_READ : MOVE_SOURCE_HINT | MOVE_ASYNC_HINT | MOVE_READ)) 467428d7b3dSmrg return NULL; 468428d7b3dSmrg 469428d7b3dSmrg return priv->gpu_bo; 470428d7b3dSmrg } 471428d7b3dSmrg 472428d7b3dSmrg w = box->x2 - box->x1; 473428d7b3dSmrg h = box->y2 - box->y1; 474428d7b3dSmrg if (priv->cpu_bo && !priv->cpu_bo->flush) { 475428d7b3dSmrg migrate = true; 476428d7b3dSmrg } else if (w == pixmap->drawable.width && h == pixmap->drawable.height) { 477428d7b3dSmrg migrate = priv->source_count++ > SOURCE_BIAS; 478428d7b3dSmrg 479428d7b3dSmrg DBG(("%s: migrating whole pixmap (%dx%d) for source (%d,%d),(%d,%d), count %d? %d\n", 480428d7b3dSmrg __FUNCTION__, 481428d7b3dSmrg pixmap->drawable.width, pixmap->drawable.height, 482428d7b3dSmrg box->x1, box->y1, box->x2, box->y2, priv->source_count, 483428d7b3dSmrg migrate)); 484428d7b3dSmrg } else if (kgem_choose_tiling(&to_sna_from_pixmap(pixmap)->kgem, 485428d7b3dSmrg blt ? I915_TILING_X : I915_TILING_Y, w, h, 486428d7b3dSmrg pixmap->drawable.bitsPerPixel) != I915_TILING_NONE) { 487428d7b3dSmrg count = priv->source_count++; 488428d7b3dSmrg if ((priv->create & KGEM_CAN_CREATE_GPU) == 0) 489428d7b3dSmrg count -= SOURCE_BIAS; 490428d7b3dSmrg 491428d7b3dSmrg DBG(("%s: migrate box (%d, %d), (%d, %d)? source count=%d, fraction=%d/%d [%d]\n", 492428d7b3dSmrg __FUNCTION__, 493428d7b3dSmrg box->x1, box->y1, box->x2, box->y2, 494428d7b3dSmrg count, w*h, 495428d7b3dSmrg pixmap->drawable.width * pixmap->drawable.height, 496428d7b3dSmrg pixmap->drawable.width * pixmap->drawable.height / (w*h))); 497428d7b3dSmrg 498428d7b3dSmrg migrate = count*w*h > pixmap->drawable.width * pixmap->drawable.height; 499428d7b3dSmrg } 500428d7b3dSmrg 501428d7b3dSmrg if (!migrate) 502428d7b3dSmrg return NULL; 503428d7b3dSmrg 504428d7b3dSmrgupload: 505428d7b3dSmrg if (blt) { 506428d7b3dSmrg if (!sna_pixmap_move_area_to_gpu(pixmap, box, 507428d7b3dSmrg __MOVE_FORCE | MOVE_READ)) 508428d7b3dSmrg return NULL; 509428d7b3dSmrg } else { 510428d7b3dSmrg if (!sna_pixmap_move_to_gpu(pixmap, 511428d7b3dSmrg __MOVE_FORCE | MOVE_ASYNC_HINT | MOVE_SOURCE_HINT | MOVE_READ)) 512428d7b3dSmrg return NULL; 513428d7b3dSmrg } 514428d7b3dSmrg 515428d7b3dSmrg return priv->gpu_bo; 516428d7b3dSmrg} 517428d7b3dSmrg 518428d7b3dSmrgstatic struct kgem_bo *upload(struct sna *sna, 519428d7b3dSmrg struct sna_composite_channel *channel, 520428d7b3dSmrg PixmapPtr pixmap, 521428d7b3dSmrg const BoxRec *box) 522428d7b3dSmrg{ 523428d7b3dSmrg struct sna_pixmap *priv; 524428d7b3dSmrg struct kgem_bo *bo; 525428d7b3dSmrg 526428d7b3dSmrg DBG(("%s: box=(%d, %d), (%d, %d), pixmap=%dx%d\n", 527428d7b3dSmrg __FUNCTION__, box->x1, box->y1, box->x2, box->y2, pixmap->drawable.width, pixmap->drawable.height)); 528428d7b3dSmrg assert(box->x1 >= 0); 529428d7b3dSmrg assert(box->y1 >= 0); 530428d7b3dSmrg assert(box->x2 <= pixmap->drawable.width); 531428d7b3dSmrg assert(box->y2 <= pixmap->drawable.height); 532428d7b3dSmrg 533428d7b3dSmrg priv = sna_pixmap(pixmap); 534428d7b3dSmrg if (priv) { 535428d7b3dSmrg RegionRec region; 536428d7b3dSmrg 537428d7b3dSmrg if (priv->cpu_damage == NULL) 538428d7b3dSmrg return NULL; /* uninitialised */ 539428d7b3dSmrg 540428d7b3dSmrg region.extents = *box; 541428d7b3dSmrg region.data = NULL; 542428d7b3dSmrg if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, 543428d7b3dSmrg ®ion, MOVE_READ)) 544428d7b3dSmrg return NULL; 545428d7b3dSmrg 546428d7b3dSmrg assert(!priv->mapped); 547428d7b3dSmrg if (pixmap->devPrivate.ptr == NULL) 548428d7b3dSmrg return NULL; /* uninitialised */ 549428d7b3dSmrg } 550428d7b3dSmrg 551428d7b3dSmrg bo = kgem_upload_source_image(&sna->kgem, 552428d7b3dSmrg pixmap->devPrivate.ptr, box, 553428d7b3dSmrg pixmap->devKind, 554428d7b3dSmrg pixmap->drawable.bitsPerPixel); 555428d7b3dSmrg if (channel && bo) { 556428d7b3dSmrg channel->width = box->x2 - box->x1; 557428d7b3dSmrg channel->height = box->y2 - box->y1; 558428d7b3dSmrg channel->offset[0] -= box->x1; 559428d7b3dSmrg channel->offset[1] -= box->y1; 560428d7b3dSmrg 561428d7b3dSmrg if (priv && 562428d7b3dSmrg pixmap->usage_hint == 0 && 563428d7b3dSmrg channel->width == pixmap->drawable.width && 564428d7b3dSmrg channel->height == pixmap->drawable.height) { 565428d7b3dSmrg DBG(("%s: adding upload cache to pixmap=%ld\n", 566428d7b3dSmrg __FUNCTION__, pixmap->drawable.serialNumber)); 567428d7b3dSmrg assert(priv->gpu_damage == NULL); 568428d7b3dSmrg assert(priv->gpu_bo == NULL); 569428d7b3dSmrg assert(bo->proxy != NULL); 570428d7b3dSmrg kgem_proxy_bo_attach(bo, &priv->gpu_bo); 571428d7b3dSmrg } 572428d7b3dSmrg } 573428d7b3dSmrg 574428d7b3dSmrg return bo; 575428d7b3dSmrg} 576428d7b3dSmrg 577428d7b3dSmrgstruct kgem_bo * 578428d7b3dSmrg__sna_render_pixmap_bo(struct sna *sna, 579428d7b3dSmrg PixmapPtr pixmap, 580428d7b3dSmrg const BoxRec *box, 581428d7b3dSmrg bool blt) 582428d7b3dSmrg{ 583428d7b3dSmrg struct kgem_bo *bo; 584428d7b3dSmrg 585428d7b3dSmrg bo = use_cpu_bo(sna, pixmap, box, blt); 586428d7b3dSmrg if (bo == NULL) { 587428d7b3dSmrg bo = move_to_gpu(pixmap, box, blt); 588428d7b3dSmrg if (bo == NULL) 589428d7b3dSmrg return NULL; 590428d7b3dSmrg } 591428d7b3dSmrg 592428d7b3dSmrg return bo; 593428d7b3dSmrg} 594428d7b3dSmrg 595428d7b3dSmrgint 596428d7b3dSmrgsna_render_pixmap_bo(struct sna *sna, 597428d7b3dSmrg struct sna_composite_channel *channel, 598428d7b3dSmrg PixmapPtr pixmap, 599428d7b3dSmrg int16_t x, int16_t y, 600428d7b3dSmrg int16_t w, int16_t h, 601428d7b3dSmrg int16_t dst_x, int16_t dst_y) 602428d7b3dSmrg{ 603428d7b3dSmrg struct sna_pixmap *priv; 604428d7b3dSmrg BoxRec box; 605428d7b3dSmrg 606428d7b3dSmrg DBG(("%s pixmap=%ld, (%d, %d)x(%d, %d)/(%d, %d)\n", 607428d7b3dSmrg __FUNCTION__, pixmap->drawable.serialNumber, 608428d7b3dSmrg x, y, w,h, pixmap->drawable.width, pixmap->drawable.height)); 609428d7b3dSmrg 610428d7b3dSmrg channel->width = pixmap->drawable.width; 611428d7b3dSmrg channel->height = pixmap->drawable.height; 612428d7b3dSmrg channel->offset[0] = x - dst_x; 613428d7b3dSmrg channel->offset[1] = y - dst_y; 614428d7b3dSmrg 615428d7b3dSmrg priv = sna_pixmap(pixmap); 616428d7b3dSmrg if (priv) { 617428d7b3dSmrg if (priv->gpu_bo && 618428d7b3dSmrg (DAMAGE_IS_ALL(priv->gpu_damage) || !priv->cpu_damage || 619428d7b3dSmrg priv->gpu_bo->proxy)) { 620428d7b3dSmrg DBG(("%s: GPU all damaged\n", __FUNCTION__)); 621428d7b3dSmrg channel->bo = priv->gpu_bo; 622428d7b3dSmrg goto done; 623428d7b3dSmrg } 624428d7b3dSmrg 625428d7b3dSmrg if (priv->cpu_bo && 626428d7b3dSmrg (DAMAGE_IS_ALL(priv->cpu_damage) || !priv->gpu_damage) && 627428d7b3dSmrg !priv->cpu_bo->snoop && priv->cpu_bo->pitch < 4096) { 628428d7b3dSmrg DBG(("%s: CPU all damaged\n", __FUNCTION__)); 629428d7b3dSmrg channel->bo = priv->cpu_bo; 630428d7b3dSmrg if (priv->shm) { 631428d7b3dSmrg assert(!priv->flush); 632428d7b3dSmrg sna_add_flush_pixmap(sna, priv, priv->cpu_bo); 633428d7b3dSmrg } 634428d7b3dSmrg goto done; 635428d7b3dSmrg } 636428d7b3dSmrg } 637428d7b3dSmrg 638428d7b3dSmrg /* XXX handle transformed repeat */ 639428d7b3dSmrg if (w == 0 || h == 0 || channel->transform) { 640428d7b3dSmrg box.x1 = box.y1 = 0; 641428d7b3dSmrg box.x2 = pixmap->drawable.width; 642428d7b3dSmrg box.y2 = pixmap->drawable.height; 643428d7b3dSmrg } else { 644428d7b3dSmrg box.x1 = x; 645428d7b3dSmrg box.y1 = y; 646428d7b3dSmrg box.x2 = bound(x, w); 647428d7b3dSmrg box.y2 = bound(y, h); 648428d7b3dSmrg 649428d7b3dSmrg if (channel->repeat == RepeatNone || channel->repeat == RepeatPad) { 650428d7b3dSmrg if (box.x1 < 0) 651428d7b3dSmrg box.x1 = 0; 652428d7b3dSmrg if (box.y1 < 0) 653428d7b3dSmrg box.y1 = 0; 654428d7b3dSmrg if (box.x2 > pixmap->drawable.width) 655428d7b3dSmrg box.x2 = pixmap->drawable.width; 656428d7b3dSmrg if (box.y2 > pixmap->drawable.height) 657428d7b3dSmrg box.y2 = pixmap->drawable.height; 658428d7b3dSmrg } else { 659428d7b3dSmrg if (box.x1 < 0 || box.x2 > pixmap->drawable.width) 660428d7b3dSmrg box.x1 = 0, box.x2 = pixmap->drawable.width; 661428d7b3dSmrg if (box.y1 < 0 || box.y2 > pixmap->drawable.height) 662428d7b3dSmrg box.y1 = 0, box.y2 = pixmap->drawable.height; 663428d7b3dSmrg } 664428d7b3dSmrg } 665428d7b3dSmrg 666428d7b3dSmrg w = box.x2 - box.x1; 667428d7b3dSmrg h = box.y2 - box.y1; 668428d7b3dSmrg DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d)\n", __FUNCTION__, 669428d7b3dSmrg box.x1, box.y1, box.x2, box.y2, w, h, 670428d7b3dSmrg pixmap->drawable.width, pixmap->drawable.height)); 671428d7b3dSmrg if (w <= 0 || h <= 0) { 672428d7b3dSmrg DBG(("%s: sample extents outside of texture -> clear\n", 673428d7b3dSmrg __FUNCTION__)); 674428d7b3dSmrg return 0; 675428d7b3dSmrg } 676428d7b3dSmrg 677428d7b3dSmrg DBG(("%s: offset=(%d, %d), size=(%d, %d)\n", 678428d7b3dSmrg __FUNCTION__, 679428d7b3dSmrg channel->offset[0], channel->offset[1], 680428d7b3dSmrg pixmap->drawable.width, pixmap->drawable.height)); 681428d7b3dSmrg 682428d7b3dSmrg channel->bo = __sna_render_pixmap_bo(sna, pixmap, &box, false); 683428d7b3dSmrg if (channel->bo == NULL) { 684428d7b3dSmrg DBG(("%s: uploading CPU box (%d, %d), (%d, %d)\n", 685428d7b3dSmrg __FUNCTION__, box.x1, box.y1, box.x2, box.y2)); 686428d7b3dSmrg channel->bo = upload(sna, channel, pixmap, &box); 687428d7b3dSmrg if (channel->bo == NULL) 688428d7b3dSmrg return 0; 689428d7b3dSmrg } else { 690428d7b3dSmrgdone: 691428d7b3dSmrg kgem_bo_reference(channel->bo); 692428d7b3dSmrg } 693428d7b3dSmrg 694428d7b3dSmrg channel->scale[0] = 1.f / channel->width; 695428d7b3dSmrg channel->scale[1] = 1.f / channel->height; 696428d7b3dSmrg return 1; 697428d7b3dSmrg} 698428d7b3dSmrg 699428d7b3dSmrgstatic int sna_render_picture_downsample(struct sna *sna, 700428d7b3dSmrg PicturePtr picture, 701428d7b3dSmrg struct sna_composite_channel *channel, 702428d7b3dSmrg const int16_t x, const int16_t y, 703428d7b3dSmrg const int16_t w, const int16_t h, 704428d7b3dSmrg const int16_t dst_x, const int16_t dst_y) 705428d7b3dSmrg{ 706428d7b3dSmrg PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable); 707428d7b3dSmrg ScreenPtr screen = pixmap->drawable.pScreen; 708428d7b3dSmrg PicturePtr tmp_src, tmp_dst; 709428d7b3dSmrg PictFormatPtr format; 710428d7b3dSmrg struct sna_pixmap *priv; 711428d7b3dSmrg pixman_transform_t t; 712428d7b3dSmrg PixmapPtr tmp; 713428d7b3dSmrg int width, height, size, max_size; 714428d7b3dSmrg int sx, sy, sw, sh; 715428d7b3dSmrg int error, ret = 0; 716428d7b3dSmrg BoxRec box, b; 717428d7b3dSmrg 718428d7b3dSmrg box.x1 = x; 719428d7b3dSmrg box.y1 = y; 720428d7b3dSmrg box.x2 = bound(x, w); 721428d7b3dSmrg box.y2 = bound(y, h); 722428d7b3dSmrg if (channel->transform) { 723428d7b3dSmrg pixman_vector_t v; 724428d7b3dSmrg 725428d7b3dSmrg pixman_transform_bounds(channel->transform, &box); 726428d7b3dSmrg 727428d7b3dSmrg v.vector[0] = x << 16; 728428d7b3dSmrg v.vector[1] = y << 16; 729428d7b3dSmrg v.vector[2] = 1 << 16; 730428d7b3dSmrg pixman_transform_point(channel->transform, &v); 731428d7b3dSmrg } 732428d7b3dSmrg 733428d7b3dSmrg if (channel->repeat == RepeatNone || channel->repeat == RepeatPad) { 734428d7b3dSmrg if (box.x1 < 0) 735428d7b3dSmrg box.x1 = 0; 736428d7b3dSmrg if (box.y1 < 0) 737428d7b3dSmrg box.y1 = 0; 738428d7b3dSmrg if (box.x2 > pixmap->drawable.width) 739428d7b3dSmrg box.x2 = pixmap->drawable.width; 740428d7b3dSmrg if (box.y2 > pixmap->drawable.height) 741428d7b3dSmrg box.y2 = pixmap->drawable.height; 742428d7b3dSmrg } else { 743428d7b3dSmrg /* XXX tiled repeats? */ 744428d7b3dSmrg if (box.x1 < 0 || box.x2 > pixmap->drawable.width) 745428d7b3dSmrg box.x1 = 0, box.x2 = pixmap->drawable.width; 746428d7b3dSmrg if (box.y1 < 0 || box.y2 > pixmap->drawable.height) 747428d7b3dSmrg box.y1 = 0, box.y2 = pixmap->drawable.height; 748428d7b3dSmrg 749428d7b3dSmrg } 750428d7b3dSmrg 751428d7b3dSmrg sw = box.x2 - box.x1; 752428d7b3dSmrg sh = box.y2 - box.y1; 753428d7b3dSmrg 754428d7b3dSmrg DBG(("%s: sample (%d, %d), (%d, %d)\n", 755428d7b3dSmrg __FUNCTION__, box.x1, box.y1, box.x2, box.y2)); 756428d7b3dSmrg 757428d7b3dSmrg sx = (sw + sna->render.max_3d_size - 1) / sna->render.max_3d_size; 758428d7b3dSmrg sy = (sh + sna->render.max_3d_size - 1) / sna->render.max_3d_size; 759428d7b3dSmrg 760428d7b3dSmrg DBG(("%s: scaling (%d, %d) down by %dx%d\n", 761428d7b3dSmrg __FUNCTION__, sw, sh, sx, sy)); 762428d7b3dSmrg 763428d7b3dSmrg width = sw / sx; 764428d7b3dSmrg height = sh / sy; 765428d7b3dSmrg 766428d7b3dSmrg DBG(("%s: creating temporary GPU bo %dx%d\n", 767428d7b3dSmrg __FUNCTION__, width, height)); 768428d7b3dSmrg 769428d7b3dSmrg tmp = screen->CreatePixmap(screen, 770428d7b3dSmrg width, height, 771428d7b3dSmrg pixmap->drawable.depth, 772428d7b3dSmrg SNA_CREATE_SCRATCH); 773428d7b3dSmrg if (tmp == NULL) 774428d7b3dSmrg goto fixup; 775428d7b3dSmrg 776428d7b3dSmrg priv = sna_pixmap(tmp); 777428d7b3dSmrg assert(priv && priv->gpu_bo); 778428d7b3dSmrg 779428d7b3dSmrg if (!sna_pixmap_move_to_gpu(pixmap, MOVE_ASYNC_HINT | MOVE_SOURCE_HINT | MOVE_READ)) { 780428d7b3dSmrgfixup: 781428d7b3dSmrg DBG(("%s: unable to create GPU bo for target or temporary pixmaps\n", 782428d7b3dSmrg __FUNCTION__)); 783428d7b3dSmrg return sna_render_picture_fixup(sna, picture, channel, 784428d7b3dSmrg x, y, w, h, 785428d7b3dSmrg dst_x, dst_y); 786428d7b3dSmrg } 787428d7b3dSmrg 788428d7b3dSmrg format = PictureMatchFormat(screen, 789428d7b3dSmrg pixmap->drawable.depth, 790428d7b3dSmrg picture->format); 791428d7b3dSmrg if (format == NULL) { 792428d7b3dSmrg DBG(("%s: invalid depth=%d, format=%08x\n", 793428d7b3dSmrg __FUNCTION__, pixmap->drawable.depth, picture->format)); 794428d7b3dSmrg goto fixup; 795428d7b3dSmrg } 796428d7b3dSmrg 797428d7b3dSmrg tmp_dst = CreatePicture(0, &tmp->drawable, format, 0, NULL, 798428d7b3dSmrg serverClient, &error); 799428d7b3dSmrg if (!tmp_dst) 800428d7b3dSmrg goto cleanup_tmp; 801428d7b3dSmrg 802428d7b3dSmrg tmp_src = CreatePicture(0, &pixmap->drawable, format, 0, NULL, 803428d7b3dSmrg serverClient, &error); 804428d7b3dSmrg if (!tmp_src) 805428d7b3dSmrg goto cleanup_dst; 806428d7b3dSmrg 807428d7b3dSmrg tmp_src->repeat = 1; 808428d7b3dSmrg tmp_src->repeatType = RepeatPad; 809428d7b3dSmrg /* Prefer to use nearest as it helps reduce artefacts from 810428d7b3dSmrg * interpolating and filtering twice. 811428d7b3dSmrg */ 812428d7b3dSmrg tmp_src->filter = PictFilterNearest; 813428d7b3dSmrg memset(&t, 0, sizeof(t)); 814428d7b3dSmrg t.matrix[0][0] = (sw << 16) / width; 815428d7b3dSmrg t.matrix[0][2] = box.x1 << 16; 816428d7b3dSmrg t.matrix[1][1] = (sh << 16) / height; 817428d7b3dSmrg t.matrix[1][2] = box.y1 << 16; 818428d7b3dSmrg t.matrix[2][2] = 1 << 16; 819428d7b3dSmrg tmp_src->transform = &t; 820428d7b3dSmrg 821428d7b3dSmrg ValidatePicture(tmp_dst); 822428d7b3dSmrg ValidatePicture(tmp_src); 823428d7b3dSmrg 824428d7b3dSmrg /* Use a small size to accommodate enlargement through tile alignment */ 825428d7b3dSmrg max_size = sna_max_tile_copy_size(sna, sna_pixmap(pixmap)->gpu_bo, priv->gpu_bo); 826428d7b3dSmrg if (max_size == 0) 827428d7b3dSmrg goto cleanup_dst; 828428d7b3dSmrg 829428d7b3dSmrg size = sna->render.max_3d_size - 4096 / pixmap->drawable.bitsPerPixel; 830428d7b3dSmrg while (size * size * 4 > max_size) 831428d7b3dSmrg size /= 2; 832428d7b3dSmrg DBG(("%s: size=%d (max=%d), scale %dx%d\n", 833428d7b3dSmrg __FUNCTION__, size, max_size, sx, sy)); 834428d7b3dSmrg 835428d7b3dSmrg sw = size / sx - 2 * sx; 836428d7b3dSmrg if (sw < 1) 837428d7b3dSmrg sw = 1; 838428d7b3dSmrg sh = size / sy - 2 * sy; 839428d7b3dSmrg if (sh < 1) 840428d7b3dSmrg sh = 1; 841428d7b3dSmrg DBG(("%s %d:%d downsampling using %dx%d GPU tiles\n", 842428d7b3dSmrg __FUNCTION__, (width + sw-1)/sw, (height + sh-1)/sh, sw, sh)); 843428d7b3dSmrg 844428d7b3dSmrg for (b.y1 = 0; b.y1 < height; b.y1 = b.y2) { 845428d7b3dSmrg b.y2 = b.y1 + sh; 846428d7b3dSmrg if (b.y2 > height) 847428d7b3dSmrg b.y2 = height; 848428d7b3dSmrg 849428d7b3dSmrg for (b.x1 = 0; b.x1 < width; b.x1 = b.x2) { 850428d7b3dSmrg struct sna_composite_op op; 851428d7b3dSmrg 852428d7b3dSmrg b.x2 = b.x1 + sw; 853428d7b3dSmrg if (b.x2 > width) 854428d7b3dSmrg b.x2 = width; 855428d7b3dSmrg 856428d7b3dSmrg DBG(("%s: tile (%d, %d), (%d, %d)\n", 857428d7b3dSmrg __FUNCTION__, b.x1, b.y1, b.x2, b.y2)); 858428d7b3dSmrg 859428d7b3dSmrg memset(&op, 0, sizeof(op)); 860428d7b3dSmrg if (!sna->render.composite(sna, 861428d7b3dSmrg PictOpSrc, 862428d7b3dSmrg tmp_src, NULL, tmp_dst, 863428d7b3dSmrg b.x1, b.y1, 864428d7b3dSmrg 0, 0, 865428d7b3dSmrg b.x1, b.y1, 866428d7b3dSmrg b.x2 - b.x1, b.y2 - b.y1, 867428d7b3dSmrg 0, &op)) 868428d7b3dSmrg goto cleanup_src; 869428d7b3dSmrg 870428d7b3dSmrg op.box(sna, &op, &b); 871428d7b3dSmrg op.done(sna, &op); 872428d7b3dSmrg } 873428d7b3dSmrg } 874428d7b3dSmrg 875428d7b3dSmrg pixman_transform_invert(&channel->embedded_transform, &t); 876428d7b3dSmrg if (channel->transform) 877428d7b3dSmrg pixman_transform_multiply(&channel->embedded_transform, 878428d7b3dSmrg &channel->embedded_transform, 879428d7b3dSmrg channel->transform); 880428d7b3dSmrg channel->transform = &channel->embedded_transform; 881428d7b3dSmrg 882428d7b3dSmrg channel->offset[0] = x - dst_x; 883428d7b3dSmrg channel->offset[1] = y - dst_y; 884428d7b3dSmrg channel->scale[0] = 1.f/width; 885428d7b3dSmrg channel->scale[1] = 1.f/height; 886428d7b3dSmrg channel->width = width; 887428d7b3dSmrg channel->height = height; 888428d7b3dSmrg channel->bo = kgem_bo_reference(priv->gpu_bo); 889428d7b3dSmrg 890428d7b3dSmrg ret = 1; 891428d7b3dSmrgcleanup_src: 892428d7b3dSmrg tmp_src->transform = NULL; 893428d7b3dSmrg FreePicture(tmp_src, 0); 894428d7b3dSmrgcleanup_dst: 895428d7b3dSmrg FreePicture(tmp_dst, 0); 896428d7b3dSmrgcleanup_tmp: 897428d7b3dSmrg screen->DestroyPixmap(tmp); 898428d7b3dSmrg return ret; 899428d7b3dSmrg} 900428d7b3dSmrg 901428d7b3dSmrgbool 902428d7b3dSmrgsna_render_pixmap_partial(struct sna *sna, 903428d7b3dSmrg const DrawableRec *draw, 904428d7b3dSmrg struct kgem_bo *bo, 905428d7b3dSmrg struct sna_composite_channel *channel, 906428d7b3dSmrg int16_t x, int16_t y, 907428d7b3dSmrg int16_t w, int16_t h) 908428d7b3dSmrg{ 909428d7b3dSmrg BoxRec box; 910428d7b3dSmrg int offset; 911428d7b3dSmrg 912428d7b3dSmrg DBG(("%s (%d, %d)x(%d, %d), pitch %d, max %d\n", 913428d7b3dSmrg __FUNCTION__, x, y, w, h, bo->pitch, sna->render.max_3d_pitch)); 914428d7b3dSmrg 915428d7b3dSmrg if (bo->pitch > sna->render.max_3d_pitch) { 916428d7b3dSmrg DBG(("%s: pitch too great %d > %d\n", __FUNCTION__, bo->pitch, sna->render.max_3d_pitch)); 917428d7b3dSmrg return false; 918428d7b3dSmrg } 919428d7b3dSmrg 920428d7b3dSmrg box.x1 = x; 921428d7b3dSmrg box.y1 = y; 922428d7b3dSmrg box.x2 = bound(x, w); 923428d7b3dSmrg box.y2 = bound(y, h); 924428d7b3dSmrg DBG(("%s: unaligned box (%d, %d), (%d, %d)\n", 925428d7b3dSmrg __FUNCTION__, box.x1, box.y1, box.x2, box.y2)); 926428d7b3dSmrg 927428d7b3dSmrg if (box.x1 < 0) 928428d7b3dSmrg box.x1 = 0; 929428d7b3dSmrg if (box.y1 < 0) 930428d7b3dSmrg box.y1 = 0; 931428d7b3dSmrg 932428d7b3dSmrg if (bo->tiling) { 933428d7b3dSmrg int tile_width, tile_height, tile_size; 934428d7b3dSmrg 935428d7b3dSmrg kgem_get_tile_size(&sna->kgem, bo->tiling, bo->pitch, 936428d7b3dSmrg &tile_width, &tile_height, &tile_size); 937428d7b3dSmrg DBG(("%s: tile size for tiling %d: %dx%d, size=%d\n", 938428d7b3dSmrg __FUNCTION__, bo->tiling, tile_width, tile_height, tile_size)); 939428d7b3dSmrg 940428d7b3dSmrg /* Ensure we align to an even tile row */ 941428d7b3dSmrg box.y1 = box.y1 & ~(2*tile_height - 1); 942428d7b3dSmrg box.y2 = ALIGN(box.y2, 2*tile_height); 943428d7b3dSmrg 944428d7b3dSmrg assert(tile_width * 8 >= draw->bitsPerPixel); 945428d7b3dSmrg box.x1 = box.x1 & ~(tile_width * 8 / draw->bitsPerPixel - 1); 946428d7b3dSmrg box.x2 = ALIGN(box.x2, tile_width * 8 / draw->bitsPerPixel); 947428d7b3dSmrg 948428d7b3dSmrg offset = box.x1 * draw->bitsPerPixel / 8 / tile_width * tile_size; 949428d7b3dSmrg } else { 950428d7b3dSmrg box.y1 = box.y1 & ~1; 951428d7b3dSmrg box.y2 = ALIGN(box.y2, 2); 952428d7b3dSmrg 953428d7b3dSmrg box.x1 = box.x1 & ~1; 954428d7b3dSmrg box.x2 = ALIGN(box.x2, 2); 955428d7b3dSmrg 956428d7b3dSmrg offset = box.x1 * draw->bitsPerPixel / 8; 957428d7b3dSmrg } 958428d7b3dSmrg 959428d7b3dSmrg if (box.x2 > draw->width) 960428d7b3dSmrg box.x2 = draw->width; 961428d7b3dSmrg if (box.y2 > draw->height) 962428d7b3dSmrg box.y2 = draw->height; 963428d7b3dSmrg 964428d7b3dSmrg w = box.x2 - box.x1; 965428d7b3dSmrg h = box.y2 - box.y1; 966428d7b3dSmrg DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d)\n", __FUNCTION__, 967428d7b3dSmrg box.x1, box.y1, box.x2, box.y2, w, h, 968428d7b3dSmrg draw->width, draw->height)); 969428d7b3dSmrg if (w <= 0 || h <= 0 || 970428d7b3dSmrg w > sna->render.max_3d_size || 971428d7b3dSmrg h > sna->render.max_3d_size) { 972428d7b3dSmrg DBG(("%s: box too large (%dx%d) for 3D pipeline (max %d)\n", 973428d7b3dSmrg __FUNCTION__, w, h, sna->render.max_3d_size)); 974428d7b3dSmrg return false; 975428d7b3dSmrg } 976428d7b3dSmrg 977428d7b3dSmrg /* How many tiles across are we? */ 978428d7b3dSmrg channel->bo = kgem_create_proxy(&sna->kgem, bo, 979428d7b3dSmrg box.y1 * bo->pitch + offset, 980428d7b3dSmrg h * bo->pitch); 981428d7b3dSmrg if (channel->bo == NULL) { 982428d7b3dSmrg DBG(("%s: failed to create proxy for partial (offset=%d, size=%d)\n", 983428d7b3dSmrg __FUNCTION__, box.y1 * bo->pitch + offset, h * bo->pitch)); 984428d7b3dSmrg return false; 985428d7b3dSmrg } 986428d7b3dSmrg 987428d7b3dSmrg channel->bo->pitch = bo->pitch; 988428d7b3dSmrg 989428d7b3dSmrg channel->offset[0] = -box.x1; 990428d7b3dSmrg channel->offset[1] = -box.y1; 991428d7b3dSmrg channel->scale[0] = 1.f/w; 992428d7b3dSmrg channel->scale[1] = 1.f/h; 993428d7b3dSmrg channel->width = w; 994428d7b3dSmrg channel->height = h; 995428d7b3dSmrg return true; 996428d7b3dSmrg} 997428d7b3dSmrg 998428d7b3dSmrgstatic bool 999428d7b3dSmrgsna_render_picture_partial(struct sna *sna, 1000428d7b3dSmrg PicturePtr picture, 1001428d7b3dSmrg struct sna_composite_channel *channel, 1002428d7b3dSmrg int16_t x, int16_t y, 1003428d7b3dSmrg int16_t w, int16_t h, 1004428d7b3dSmrg int16_t dst_x, int16_t dst_y) 1005428d7b3dSmrg{ 1006428d7b3dSmrg struct kgem_bo *bo = NULL; 1007428d7b3dSmrg PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable); 1008428d7b3dSmrg BoxRec box; 1009428d7b3dSmrg int offset; 1010428d7b3dSmrg 1011428d7b3dSmrg DBG(("%s (%d, %d)x(%d, %d) [dst=(%d, %d)]\n", 1012428d7b3dSmrg __FUNCTION__, x, y, w, h, dst_x, dst_y)); 1013428d7b3dSmrg 1014428d7b3dSmrg box.x1 = x; 1015428d7b3dSmrg box.y1 = y; 1016428d7b3dSmrg box.x2 = bound(x, w); 1017428d7b3dSmrg box.y2 = bound(y, h); 1018428d7b3dSmrg if (channel->transform) 1019428d7b3dSmrg pixman_transform_bounds(channel->transform, &box); 1020428d7b3dSmrg 1021428d7b3dSmrg DBG(("%s sample=(%d, %d), (%d, %d): (%d, %d)/(%d, %d), repeat=%d\n", __FUNCTION__, 1022428d7b3dSmrg box.x1, box.y1, box.x2, box.y2, w, h, 1023428d7b3dSmrg pixmap->drawable.width, pixmap->drawable.height, 1024428d7b3dSmrg channel->repeat)); 1025428d7b3dSmrg 1026428d7b3dSmrg if (channel->repeat == RepeatNone || channel->repeat == RepeatPad) { 1027428d7b3dSmrg if (box.x1 < 0) 1028428d7b3dSmrg box.x1 = 0; 1029428d7b3dSmrg if (box.y1 < 0) 1030428d7b3dSmrg box.y1 = 0; 1031428d7b3dSmrg if (box.x2 > pixmap->drawable.width) 1032428d7b3dSmrg box.x2 = pixmap->drawable.width; 1033428d7b3dSmrg if (box.y2 > pixmap->drawable.height) 1034428d7b3dSmrg box.y2 = pixmap->drawable.height; 1035428d7b3dSmrg } else { 1036428d7b3dSmrg if (box.x1 < 0 || box.x2 > pixmap->drawable.width) 1037428d7b3dSmrg box.x1 = 0, box.x2 = pixmap->drawable.width; 1038428d7b3dSmrg if (box.y1 < 0 || box.y2 > pixmap->drawable.height) 1039428d7b3dSmrg box.y1 = 0, box.y2 = pixmap->drawable.height; 1040428d7b3dSmrg } 1041428d7b3dSmrg 1042428d7b3dSmrg if (use_cpu_bo(sna, pixmap, &box, false)) { 1043428d7b3dSmrg bo = sna_pixmap(pixmap)->cpu_bo; 1044428d7b3dSmrg } else { 1045428d7b3dSmrg struct sna_pixmap *priv; 1046428d7b3dSmrg 1047428d7b3dSmrg priv = sna_pixmap_force_to_gpu(pixmap, 1048428d7b3dSmrg MOVE_READ | MOVE_ASYNC_HINT | MOVE_SOURCE_HINT); 1049428d7b3dSmrg if (priv == NULL) 1050428d7b3dSmrg return false; 1051428d7b3dSmrg 1052428d7b3dSmrg bo = priv->gpu_bo; 1053428d7b3dSmrg } 1054428d7b3dSmrg 1055428d7b3dSmrg if (bo->pitch > sna->render.max_3d_pitch) { 1056428d7b3dSmrg DBG(("%s: pitch too great %d > %d\n", __FUNCTION__, bo->pitch, sna->render.max_3d_pitch)); 1057428d7b3dSmrg return false; 1058428d7b3dSmrg } 1059428d7b3dSmrg 1060428d7b3dSmrg if (bo->tiling) { 1061428d7b3dSmrg int tile_width, tile_height, tile_size; 1062428d7b3dSmrg 1063428d7b3dSmrg kgem_get_tile_size(&sna->kgem, bo->tiling, bo->pitch, 1064428d7b3dSmrg &tile_width, &tile_height, &tile_size); 1065428d7b3dSmrg 1066428d7b3dSmrg DBG(("%s: tiling=%d, size=%dx%d, chunk=%d\n", 1067428d7b3dSmrg __FUNCTION__, bo->tiling, 1068428d7b3dSmrg tile_width, tile_height, tile_size)); 1069428d7b3dSmrg 1070428d7b3dSmrg /* Ensure we align to an even tile row */ 1071428d7b3dSmrg box.y1 = box.y1 & ~(2*tile_height - 1); 1072428d7b3dSmrg box.y2 = ALIGN(box.y2, 2*tile_height); 1073428d7b3dSmrg if (box.y2 > pixmap->drawable.height) 1074428d7b3dSmrg box.y2 = pixmap->drawable.height; 1075428d7b3dSmrg 1076428d7b3dSmrg box.x1 = box.x1 & ~(tile_width * 8 / pixmap->drawable.bitsPerPixel - 1); 1077428d7b3dSmrg box.x2 = ALIGN(box.x2, tile_width * 8 / pixmap->drawable.bitsPerPixel); 1078428d7b3dSmrg if (box.x2 > pixmap->drawable.width) 1079428d7b3dSmrg box.x2 = pixmap->drawable.width; 1080428d7b3dSmrg 1081428d7b3dSmrg offset = box.x1 * pixmap->drawable.bitsPerPixel / 8 / tile_width * tile_size; 1082428d7b3dSmrg } else 1083428d7b3dSmrg offset = box.x1 * pixmap->drawable.bitsPerPixel / 8; 1084428d7b3dSmrg 1085428d7b3dSmrg w = box.x2 - box.x1; 1086428d7b3dSmrg h = box.y2 - box.y1; 1087428d7b3dSmrg DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d)\n", __FUNCTION__, 1088428d7b3dSmrg box.x1, box.y1, box.x2, box.y2, w, h, 1089428d7b3dSmrg pixmap->drawable.width, pixmap->drawable.height)); 1090428d7b3dSmrg if (w <= 0 || h <= 0 || 1091428d7b3dSmrg w > sna->render.max_3d_size || 1092428d7b3dSmrg h > sna->render.max_3d_size) 1093428d7b3dSmrg return false; 1094428d7b3dSmrg 1095428d7b3dSmrg /* How many tiles across are we? */ 1096428d7b3dSmrg channel->bo = kgem_create_proxy(&sna->kgem, bo, 1097428d7b3dSmrg box.y1 * bo->pitch + offset, 1098428d7b3dSmrg h * bo->pitch); 1099428d7b3dSmrg if (channel->bo == NULL) 1100428d7b3dSmrg return false; 1101428d7b3dSmrg 1102428d7b3dSmrg if (channel->transform) { 1103428d7b3dSmrg memset(&channel->embedded_transform, 1104428d7b3dSmrg 0, 1105428d7b3dSmrg sizeof(channel->embedded_transform)); 1106428d7b3dSmrg channel->embedded_transform.matrix[0][0] = 1 << 16; 1107428d7b3dSmrg channel->embedded_transform.matrix[0][2] = -box.x1 << 16; 1108428d7b3dSmrg channel->embedded_transform.matrix[1][1] = 1 << 16; 1109428d7b3dSmrg channel->embedded_transform.matrix[1][2] = -box.y1 << 16; 1110428d7b3dSmrg channel->embedded_transform.matrix[2][2] = 1 << 16; 1111428d7b3dSmrg pixman_transform_multiply(&channel->embedded_transform, 1112428d7b3dSmrg &channel->embedded_transform, 1113428d7b3dSmrg channel->transform); 1114428d7b3dSmrg channel->transform = &channel->embedded_transform; 1115428d7b3dSmrg } else { 1116428d7b3dSmrg x -= box.x1; 1117428d7b3dSmrg y -= box.y1; 1118428d7b3dSmrg } 1119428d7b3dSmrg 1120428d7b3dSmrg channel->offset[0] = x - dst_x; 1121428d7b3dSmrg channel->offset[1] = y - dst_y; 1122428d7b3dSmrg channel->scale[0] = 1.f/w; 1123428d7b3dSmrg channel->scale[1] = 1.f/h; 1124428d7b3dSmrg channel->width = w; 1125428d7b3dSmrg channel->height = h; 1126428d7b3dSmrg return true; 1127428d7b3dSmrg} 1128428d7b3dSmrg 1129428d7b3dSmrgint 1130428d7b3dSmrgsna_render_picture_extract(struct sna *sna, 1131428d7b3dSmrg PicturePtr picture, 1132428d7b3dSmrg struct sna_composite_channel *channel, 1133428d7b3dSmrg int16_t x, int16_t y, 1134428d7b3dSmrg int16_t w, int16_t h, 1135428d7b3dSmrg int16_t dst_x, int16_t dst_y) 1136428d7b3dSmrg{ 1137428d7b3dSmrg struct kgem_bo *bo = NULL, *src_bo; 1138428d7b3dSmrg PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable); 1139428d7b3dSmrg int16_t ox, oy, ow, oh; 1140428d7b3dSmrg BoxRec box; 1141428d7b3dSmrg 1142428d7b3dSmrg#if NO_EXTRACT 1143428d7b3dSmrg return -1; 1144428d7b3dSmrg#endif 1145428d7b3dSmrg 1146428d7b3dSmrg DBG(("%s (%d, %d)x(%d, %d) [dst=(%d, %d)]\n", 1147428d7b3dSmrg __FUNCTION__, x, y, w, h, dst_x, dst_y)); 1148428d7b3dSmrg 1149428d7b3dSmrg if (w == 0 || h == 0) { 1150428d7b3dSmrg DBG(("%s: fallback -- unknown bounds\n", __FUNCTION__)); 1151428d7b3dSmrg return -1; 1152428d7b3dSmrg } 1153428d7b3dSmrg 1154428d7b3dSmrg if (sna_render_picture_partial(sna, picture, channel, 1155428d7b3dSmrg x, y, w, h, 1156428d7b3dSmrg dst_x, dst_y)) 1157428d7b3dSmrg return 1; 1158428d7b3dSmrg 1159428d7b3dSmrg ow = w; 1160428d7b3dSmrg oh = h; 1161428d7b3dSmrg 1162428d7b3dSmrg ox = box.x1 = x; 1163428d7b3dSmrg oy = box.y1 = y; 1164428d7b3dSmrg box.x2 = bound(x, w); 1165428d7b3dSmrg box.y2 = bound(y, h); 1166428d7b3dSmrg if (channel->transform) { 1167428d7b3dSmrg pixman_vector_t v; 1168428d7b3dSmrg 1169428d7b3dSmrg pixman_transform_bounds(channel->transform, &box); 1170428d7b3dSmrg 1171428d7b3dSmrg v.vector[0] = ox << 16; 1172428d7b3dSmrg v.vector[1] = oy << 16; 1173428d7b3dSmrg v.vector[2] = 1 << 16; 1174428d7b3dSmrg pixman_transform_point(channel->transform, &v); 1175428d7b3dSmrg ox = v.vector[0] / v.vector[2]; 1176428d7b3dSmrg oy = v.vector[1] / v.vector[2]; 1177428d7b3dSmrg } 1178428d7b3dSmrg 1179428d7b3dSmrg DBG(("%s sample=(%d, %d), (%d, %d): (%d, %d)/(%d, %d), repeat=%d\n", __FUNCTION__, 1180428d7b3dSmrg box.x1, box.y1, box.x2, box.y2, w, h, 1181428d7b3dSmrg pixmap->drawable.width, pixmap->drawable.height, 1182428d7b3dSmrg channel->repeat)); 1183428d7b3dSmrg 1184428d7b3dSmrg if (channel->repeat == RepeatNone || channel->repeat == RepeatPad) { 1185428d7b3dSmrg if (box.x1 < 0) 1186428d7b3dSmrg box.x1 = 0; 1187428d7b3dSmrg if (box.y1 < 0) 1188428d7b3dSmrg box.y1 = 0; 1189428d7b3dSmrg if (box.x2 > pixmap->drawable.width) 1190428d7b3dSmrg box.x2 = pixmap->drawable.width; 1191428d7b3dSmrg if (box.y2 > pixmap->drawable.height) 1192428d7b3dSmrg box.y2 = pixmap->drawable.height; 1193428d7b3dSmrg } else { 1194428d7b3dSmrg /* XXX tiled repeats? */ 1195428d7b3dSmrg if (box.x1 < 0 || box.x2 > pixmap->drawable.width) 1196428d7b3dSmrg box.x1 = 0, box.x2 = pixmap->drawable.width; 1197428d7b3dSmrg if (box.y1 < 0 || box.y2 > pixmap->drawable.height) 1198428d7b3dSmrg box.y1 = 0, box.y2 = pixmap->drawable.height; 1199428d7b3dSmrg } 1200428d7b3dSmrg 1201428d7b3dSmrg w = box.x2 - box.x1; 1202428d7b3dSmrg h = box.y2 - box.y1; 1203428d7b3dSmrg DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d)\n", __FUNCTION__, 1204428d7b3dSmrg box.x1, box.y1, box.x2, box.y2, w, h, 1205428d7b3dSmrg pixmap->drawable.width, pixmap->drawable.height)); 1206428d7b3dSmrg if (w <= 0 || h <= 0) { 1207428d7b3dSmrg DBG(("%s: sample extents outside of texture -> clear\n", 1208428d7b3dSmrg __FUNCTION__)); 1209428d7b3dSmrg return 0; 1210428d7b3dSmrg } 1211428d7b3dSmrg 1212428d7b3dSmrg if (w > sna->render.max_3d_size || h > sna->render.max_3d_size) { 1213428d7b3dSmrg DBG(("%s: fallback -- sample too large for texture (%d, %d)x(%d, %d)\n", 1214428d7b3dSmrg __FUNCTION__, box.x1, box.y1, w, h)); 1215428d7b3dSmrg return sna_render_picture_downsample(sna, picture, channel, 1216428d7b3dSmrg x, y, ow, oh, 1217428d7b3dSmrg dst_x, dst_y); 1218428d7b3dSmrg } 1219428d7b3dSmrg 1220428d7b3dSmrg src_bo = use_cpu_bo(sna, pixmap, &box, true); 1221428d7b3dSmrg if (src_bo == NULL) 1222428d7b3dSmrg src_bo = move_to_gpu(pixmap, &box, false); 1223428d7b3dSmrg if (src_bo) { 1224428d7b3dSmrg bo = kgem_create_2d(&sna->kgem, w, h, 1225428d7b3dSmrg pixmap->drawable.bitsPerPixel, 1226428d7b3dSmrg kgem_choose_tiling(&sna->kgem, 1227428d7b3dSmrg I915_TILING_X, w, h, 1228428d7b3dSmrg pixmap->drawable.bitsPerPixel), 1229428d7b3dSmrg CREATE_TEMPORARY); 1230428d7b3dSmrg if (bo) { 1231428d7b3dSmrg DrawableRec tmp; 1232428d7b3dSmrg 1233428d7b3dSmrg tmp.width = w; 1234428d7b3dSmrg tmp.height = h; 1235428d7b3dSmrg tmp.depth = pixmap->drawable.depth; 1236428d7b3dSmrg tmp.bitsPerPixel = pixmap->drawable.bitsPerPixel; 1237428d7b3dSmrg 1238428d7b3dSmrg assert(tmp.width); 1239428d7b3dSmrg assert(tmp.height); 1240428d7b3dSmrg 1241428d7b3dSmrg if (!sna->render.copy_boxes(sna, GXcopy, 1242428d7b3dSmrg &pixmap->drawable, src_bo, 0, 0, 1243428d7b3dSmrg &tmp, bo, -box.x1, -box.y1, 1244428d7b3dSmrg &box, 1, 0)) { 1245428d7b3dSmrg kgem_bo_destroy(&sna->kgem, bo); 1246428d7b3dSmrg bo = NULL; 1247428d7b3dSmrg } 1248428d7b3dSmrg } 1249428d7b3dSmrg } else { 1250428d7b3dSmrg struct sna_pixmap *priv = sna_pixmap(pixmap); 1251428d7b3dSmrg if (priv) { 1252428d7b3dSmrg RegionRec region; 1253428d7b3dSmrg 1254428d7b3dSmrg region.extents = box; 1255428d7b3dSmrg region.data = NULL; 1256428d7b3dSmrg if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, 1257428d7b3dSmrg ®ion, MOVE_READ)) 1258428d7b3dSmrg return 0; 1259428d7b3dSmrg 1260428d7b3dSmrg assert(!priv->mapped); 1261428d7b3dSmrg if (pixmap->devPrivate.ptr == NULL) 1262428d7b3dSmrg return 0; /* uninitialised */ 1263428d7b3dSmrg } 1264428d7b3dSmrg 1265428d7b3dSmrg bo = kgem_upload_source_image(&sna->kgem, 1266428d7b3dSmrg pixmap->devPrivate.ptr, 1267428d7b3dSmrg &box, 1268428d7b3dSmrg pixmap->devKind, 1269428d7b3dSmrg pixmap->drawable.bitsPerPixel); 1270428d7b3dSmrg if (priv != NULL && bo != NULL && 1271428d7b3dSmrg box.x2 - box.x1 == pixmap->drawable.width && 1272428d7b3dSmrg box.y2 - box.y1 == pixmap->drawable.height) { 1273428d7b3dSmrg DBG(("%s: adding upload cache to pixmap=%ld\n", 1274428d7b3dSmrg __FUNCTION__, pixmap->drawable.serialNumber)); 1275428d7b3dSmrg assert(priv->gpu_damage == NULL); 1276428d7b3dSmrg assert(priv->gpu_bo == NULL); 1277428d7b3dSmrg assert(bo->proxy != NULL); 1278428d7b3dSmrg kgem_proxy_bo_attach(bo, &priv->gpu_bo); 1279428d7b3dSmrg } 1280428d7b3dSmrg } 1281428d7b3dSmrg 1282428d7b3dSmrg if (bo == NULL) { 1283428d7b3dSmrg DBG(("%s: falback -- pixmap is not on the GPU\n", 1284428d7b3dSmrg __FUNCTION__)); 1285428d7b3dSmrg return sna_render_picture_fixup(sna, picture, channel, 1286428d7b3dSmrg x, y, ow, oh, dst_x, dst_y); 1287428d7b3dSmrg } 1288428d7b3dSmrg 1289428d7b3dSmrg if (ox == x && oy == y) { 1290428d7b3dSmrg x = y = 0; 1291428d7b3dSmrg } else if (channel->transform) { 1292428d7b3dSmrg pixman_vector_t v; 1293428d7b3dSmrg pixman_transform_t m; 1294428d7b3dSmrg 1295428d7b3dSmrg v.vector[0] = (ox - box.x1) << 16; 1296428d7b3dSmrg v.vector[1] = (oy - box.y1) << 16; 1297428d7b3dSmrg v.vector[2] = 1 << 16; 1298428d7b3dSmrg pixman_transform_invert(&m, channel->transform); 1299428d7b3dSmrg pixman_transform_point(&m, &v); 1300428d7b3dSmrg x = v.vector[0] / v.vector[2]; 1301428d7b3dSmrg y = v.vector[1] / v.vector[2]; 1302428d7b3dSmrg } else { 1303428d7b3dSmrg x = ox - box.x1; 1304428d7b3dSmrg y = oy - box.y1; 1305428d7b3dSmrg } 1306428d7b3dSmrg 1307428d7b3dSmrg channel->offset[0] = x - dst_x; 1308428d7b3dSmrg channel->offset[1] = y - dst_y; 1309428d7b3dSmrg channel->scale[0] = 1.f/w; 1310428d7b3dSmrg channel->scale[1] = 1.f/h; 1311428d7b3dSmrg channel->width = w; 1312428d7b3dSmrg channel->height = h; 1313428d7b3dSmrg channel->bo = bo; 1314428d7b3dSmrg return 1; 1315428d7b3dSmrg} 1316428d7b3dSmrg 1317428d7b3dSmrgstatic int 1318428d7b3dSmrgsna_render_picture_convolve(struct sna *sna, 1319428d7b3dSmrg PicturePtr picture, 1320428d7b3dSmrg struct sna_composite_channel *channel, 1321428d7b3dSmrg int16_t x, int16_t y, 1322428d7b3dSmrg int16_t w, int16_t h, 1323428d7b3dSmrg int16_t dst_x, int16_t dst_y) 1324428d7b3dSmrg{ 1325428d7b3dSmrg ScreenPtr screen = picture->pDrawable->pScreen; 1326428d7b3dSmrg PixmapPtr pixmap; 1327428d7b3dSmrg PicturePtr tmp; 1328428d7b3dSmrg pixman_fixed_t *params = picture->filter_params; 1329428d7b3dSmrg int x_off = -pixman_fixed_to_int((params[0] - pixman_fixed_1) >> 1); 1330428d7b3dSmrg int y_off = -pixman_fixed_to_int((params[1] - pixman_fixed_1) >> 1); 1331428d7b3dSmrg int cw = pixman_fixed_to_int(params[0]); 1332428d7b3dSmrg int ch = pixman_fixed_to_int(params[1]); 1333428d7b3dSmrg int i, j, error, depth; 1334428d7b3dSmrg struct kgem_bo *bo; 1335428d7b3dSmrg 1336428d7b3dSmrg /* Lame multi-pass accumulation implementation of a general convolution 1337428d7b3dSmrg * that works everywhere. 1338428d7b3dSmrg */ 1339428d7b3dSmrg DBG(("%s: origin=(%d,%d) kernel=%dx%d, size=%dx%d\n", 1340428d7b3dSmrg __FUNCTION__, x_off, y_off, cw, ch, w, h)); 1341428d7b3dSmrg 1342428d7b3dSmrg assert(picture->pDrawable); 1343428d7b3dSmrg assert(picture->filter == PictFilterConvolution); 1344428d7b3dSmrg assert(w <= sna->render.max_3d_size && h <= sna->render.max_3d_size); 1345428d7b3dSmrg 1346428d7b3dSmrg if (PICT_FORMAT_RGB(picture->format) == 0) { 1347428d7b3dSmrg channel->pict_format = PIXMAN_a8; 1348428d7b3dSmrg depth = 8; 1349428d7b3dSmrg } else { 1350428d7b3dSmrg channel->pict_format = PIXMAN_a8r8g8b8; 1351428d7b3dSmrg depth = 32; 1352428d7b3dSmrg } 1353428d7b3dSmrg 1354428d7b3dSmrg pixmap = screen->CreatePixmap(screen, w, h, depth, SNA_CREATE_SCRATCH); 1355428d7b3dSmrg if (pixmap == NullPixmap) { 1356428d7b3dSmrg DBG(("%s: pixmap allocation failed\n", __FUNCTION__)); 1357428d7b3dSmrg return -1; 1358428d7b3dSmrg } 1359428d7b3dSmrg 1360428d7b3dSmrg tmp = NULL; 1361428d7b3dSmrg bo = __sna_pixmap_get_bo(pixmap); 1362428d7b3dSmrg assert(bo); 1363428d7b3dSmrg if (sna->render.clear(sna, pixmap, bo)) 1364428d7b3dSmrg tmp = CreatePicture(0, &pixmap->drawable, 1365428d7b3dSmrg PictureMatchFormat(screen, depth, channel->pict_format), 1366428d7b3dSmrg 0, NULL, serverClient, &error); 1367428d7b3dSmrg screen->DestroyPixmap(pixmap); 1368428d7b3dSmrg if (tmp == NULL) 1369428d7b3dSmrg return -1; 1370428d7b3dSmrg 1371428d7b3dSmrg ValidatePicture(tmp); 1372428d7b3dSmrg 1373428d7b3dSmrg picture->filter = PictFilterBilinear; 1374428d7b3dSmrg params += 2; 1375428d7b3dSmrg for (j = 0; j < ch; j++) { 1376428d7b3dSmrg for (i = 0; i < cw; i++) { 1377428d7b3dSmrg xRenderColor color; 1378428d7b3dSmrg PicturePtr alpha; 1379428d7b3dSmrg 1380428d7b3dSmrg color.alpha = *params++; 1381428d7b3dSmrg color.red = color.green = color.blue = 0; 1382428d7b3dSmrg DBG(("%s: (%d, %d), alpha=%x\n", 1383428d7b3dSmrg __FUNCTION__, i,j, color.alpha)); 1384428d7b3dSmrg 1385428d7b3dSmrg if (color.alpha <= 0x00ff) 1386428d7b3dSmrg continue; 1387428d7b3dSmrg 1388428d7b3dSmrg alpha = CreateSolidPicture(0, &color, &error); 1389428d7b3dSmrg if (alpha) { 1390428d7b3dSmrg sna_composite(PictOpAdd, picture, alpha, tmp, 1391428d7b3dSmrg x, y, 1392428d7b3dSmrg 0, 0, 1393428d7b3dSmrg x_off+i, y_off+j, 1394428d7b3dSmrg w, h); 1395428d7b3dSmrg FreePicture(alpha, 0); 1396428d7b3dSmrg } 1397428d7b3dSmrg } 1398428d7b3dSmrg } 1399428d7b3dSmrg picture->filter = PictFilterConvolution; 1400428d7b3dSmrg 1401428d7b3dSmrg channel->height = h; 1402428d7b3dSmrg channel->width = w; 1403428d7b3dSmrg channel->filter = PictFilterNearest; 1404428d7b3dSmrg channel->repeat = RepeatNone; 1405428d7b3dSmrg channel->is_affine = true; 1406428d7b3dSmrg channel->transform = NULL; 1407428d7b3dSmrg channel->scale[0] = 1.f / w; 1408428d7b3dSmrg channel->scale[1] = 1.f / h; 1409428d7b3dSmrg channel->offset[0] = -dst_x; 1410428d7b3dSmrg channel->offset[1] = -dst_y; 1411428d7b3dSmrg channel->bo = kgem_bo_reference(bo); /* transfer ownership */ 1412428d7b3dSmrg FreePicture(tmp, 0); 1413428d7b3dSmrg 1414428d7b3dSmrg return 1; 1415428d7b3dSmrg} 1416428d7b3dSmrg 1417428d7b3dSmrgstatic bool 1418428d7b3dSmrgsna_render_picture_flatten(struct sna *sna, 1419428d7b3dSmrg PicturePtr picture, 1420428d7b3dSmrg struct sna_composite_channel *channel, 1421428d7b3dSmrg int16_t x, int16_t y, 1422428d7b3dSmrg int16_t w, int16_t h, 1423428d7b3dSmrg int16_t dst_x, int16_t dst_y) 1424428d7b3dSmrg{ 1425428d7b3dSmrg ScreenPtr screen = picture->pDrawable->pScreen; 1426428d7b3dSmrg PixmapPtr pixmap; 1427428d7b3dSmrg PicturePtr tmp, alpha; 1428428d7b3dSmrg int old_format, error; 1429428d7b3dSmrg 1430428d7b3dSmrg assert(picture->pDrawable); 1431428d7b3dSmrg assert(picture->alphaMap); 1432428d7b3dSmrg assert(w <= sna->render.max_3d_size && h <= sna->render.max_3d_size); 1433428d7b3dSmrg 1434428d7b3dSmrg /* XXX shortcut a8? */ 1435428d7b3dSmrg DBG(("%s: %dx%d\n", __FUNCTION__, w, h)); 1436428d7b3dSmrg 1437428d7b3dSmrg pixmap = screen->CreatePixmap(screen, w, h, 32, SNA_CREATE_SCRATCH); 1438428d7b3dSmrg if (pixmap == NullPixmap) { 1439428d7b3dSmrg DBG(("%s: pixmap allocation failed\n", __FUNCTION__)); 1440428d7b3dSmrg return false; 1441428d7b3dSmrg } 1442428d7b3dSmrg 1443428d7b3dSmrg assert(__sna_pixmap_get_bo(pixmap)); 1444428d7b3dSmrg 1445428d7b3dSmrg tmp = CreatePicture(0, &pixmap->drawable, 1446428d7b3dSmrg PictureMatchFormat(screen, 32, PICT_a8r8g8b8), 1447428d7b3dSmrg 0, NULL, serverClient, &error); 1448428d7b3dSmrg screen->DestroyPixmap(pixmap); 1449428d7b3dSmrg if (tmp == NULL) 1450428d7b3dSmrg return false; 1451428d7b3dSmrg 1452428d7b3dSmrg ValidatePicture(tmp); 1453428d7b3dSmrg 1454428d7b3dSmrg old_format = picture->format; 1455428d7b3dSmrg picture->format = PICT_FORMAT(PICT_FORMAT_BPP(picture->format), 1456428d7b3dSmrg PICT_FORMAT_TYPE(picture->format), 1457428d7b3dSmrg 0, 1458428d7b3dSmrg PICT_FORMAT_R(picture->format), 1459428d7b3dSmrg PICT_FORMAT_G(picture->format), 1460428d7b3dSmrg PICT_FORMAT_B(picture->format)); 1461428d7b3dSmrg 1462428d7b3dSmrg alpha = picture->alphaMap; 1463428d7b3dSmrg picture->alphaMap = NULL; 1464428d7b3dSmrg 1465428d7b3dSmrg sna_composite(PictOpSrc, picture, alpha, tmp, 1466428d7b3dSmrg x, y, 1467428d7b3dSmrg x + picture->alphaOrigin.x, y + picture->alphaOrigin.y, 1468428d7b3dSmrg 0, 0, 1469428d7b3dSmrg w, h); 1470428d7b3dSmrg 1471428d7b3dSmrg picture->format = old_format; 1472428d7b3dSmrg picture->alphaMap = alpha; 1473428d7b3dSmrg 1474428d7b3dSmrg channel->height = h; 1475428d7b3dSmrg channel->width = w; 1476428d7b3dSmrg channel->filter = PictFilterNearest; 1477428d7b3dSmrg channel->repeat = RepeatNone; 1478428d7b3dSmrg channel->pict_format = PIXMAN_a8r8g8b8; 1479428d7b3dSmrg channel->is_affine = true; 1480428d7b3dSmrg channel->transform = NULL; 1481428d7b3dSmrg channel->scale[0] = 1.f / w; 1482428d7b3dSmrg channel->scale[1] = 1.f / h; 1483428d7b3dSmrg channel->offset[0] = -dst_x; 1484428d7b3dSmrg channel->offset[1] = -dst_y; 1485428d7b3dSmrg channel->bo = kgem_bo_reference(__sna_pixmap_get_bo(pixmap)); 1486428d7b3dSmrg FreePicture(tmp, 0); 1487428d7b3dSmrg 1488428d7b3dSmrg return true; 1489428d7b3dSmrg} 1490428d7b3dSmrg 1491428d7b3dSmrgint 1492428d7b3dSmrgsna_render_picture_approximate_gradient(struct sna *sna, 1493428d7b3dSmrg PicturePtr picture, 1494428d7b3dSmrg struct sna_composite_channel *channel, 1495428d7b3dSmrg int16_t x, int16_t y, 1496428d7b3dSmrg int16_t w, int16_t h, 1497428d7b3dSmrg int16_t dst_x, int16_t dst_y) 1498428d7b3dSmrg{ 1499428d7b3dSmrg pixman_image_t *dst, *src; 1500428d7b3dSmrg pixman_transform_t t; 1501428d7b3dSmrg int w2 = w/2, h2 = h/2; 1502428d7b3dSmrg int dx, dy; 1503428d7b3dSmrg void *ptr; 1504428d7b3dSmrg 1505428d7b3dSmrg#if NO_FIXUP 1506428d7b3dSmrg return -1; 1507428d7b3dSmrg#endif 1508428d7b3dSmrg 1509428d7b3dSmrg DBG(("%s: (%d, %d)x(%d, %d), dst=(%d, %d)\n", 1510428d7b3dSmrg __FUNCTION__, x, y, w, h, dst_x, dst_y)); 1511428d7b3dSmrg 1512428d7b3dSmrg if (w2 == 0 || h2 == 0) { 1513428d7b3dSmrg DBG(("%s: fallback - unknown bounds\n", __FUNCTION__)); 1514428d7b3dSmrg return -1; 1515428d7b3dSmrg } 1516428d7b3dSmrg if (w2 > sna->render.max_3d_size || h2 > sna->render.max_3d_size) { 1517428d7b3dSmrg DBG(("%s: fallback - too large (%dx%d)\n", __FUNCTION__, w, h)); 1518428d7b3dSmrg return -1; 1519428d7b3dSmrg } 1520428d7b3dSmrg 1521428d7b3dSmrg channel->is_opaque = sna_gradient_is_opaque((PictGradient*)picture->pSourcePict); 1522428d7b3dSmrg channel->pict_format = 1523428d7b3dSmrg channel->is_opaque ? PIXMAN_x8r8g8b8 : PIXMAN_a8r8g8b8; 1524428d7b3dSmrg DBG(("%s: gradient is opaque? %d, selecting format %08x\n", 1525428d7b3dSmrg __FUNCTION__, channel->is_opaque, channel->pict_format)); 1526428d7b3dSmrg assert(channel->card_format == -1); 1527428d7b3dSmrg 1528428d7b3dSmrg channel->bo = kgem_create_buffer_2d(&sna->kgem, 1529428d7b3dSmrg w2, h2, 32, 1530428d7b3dSmrg KGEM_BUFFER_WRITE_INPLACE, 1531428d7b3dSmrg &ptr); 1532428d7b3dSmrg if (!channel->bo) { 1533428d7b3dSmrg DBG(("%s: failed to create upload buffer, using clear\n", 1534428d7b3dSmrg __FUNCTION__)); 1535428d7b3dSmrg return 0; 1536428d7b3dSmrg } 1537428d7b3dSmrg 1538428d7b3dSmrg dst = pixman_image_create_bits(channel->pict_format, 1539428d7b3dSmrg w2, h2, ptr, channel->bo->pitch); 1540428d7b3dSmrg if (!dst) { 1541428d7b3dSmrg kgem_bo_destroy(&sna->kgem, channel->bo); 1542428d7b3dSmrg channel->bo = NULL; 1543428d7b3dSmrg return 0; 1544428d7b3dSmrg } 1545428d7b3dSmrg 1546428d7b3dSmrg src = image_from_pict(picture, false, &dx, &dy); 1547428d7b3dSmrg if (src == NULL) { 1548428d7b3dSmrg pixman_image_unref(dst); 1549428d7b3dSmrg kgem_bo_destroy(&sna->kgem, channel->bo); 1550428d7b3dSmrg channel->bo = NULL; 1551428d7b3dSmrg return 0; 1552428d7b3dSmrg } 1553428d7b3dSmrg DBG(("%s: source offset (%d, %d)\n", __FUNCTION__, dx, dy)); 1554428d7b3dSmrg 1555428d7b3dSmrg memset(&t, 0, sizeof(t)); 1556428d7b3dSmrg t.matrix[0][0] = (w << 16) / w2; 1557428d7b3dSmrg t.matrix[0][2] = (x + dx) << 16; 1558428d7b3dSmrg t.matrix[1][1] = (h << 16) / h2; 1559428d7b3dSmrg t.matrix[1][2] = (y + dy) << 16; 1560428d7b3dSmrg t.matrix[2][2] = 1 << 16; 1561428d7b3dSmrg if (picture->transform) 1562428d7b3dSmrg pixman_transform_multiply(&t, picture->transform, &t); 1563428d7b3dSmrg DBG(("%s: applying transform [(%f, %f, %f), (%f, %f, %f), (%f, %f, %f)]\n", 1564428d7b3dSmrg __FUNCTION__, 1565428d7b3dSmrg pixman_fixed_to_double(t.matrix[0][0]), 1566428d7b3dSmrg pixman_fixed_to_double(t.matrix[0][1]), 1567428d7b3dSmrg pixman_fixed_to_double(t.matrix[0][2]), 1568428d7b3dSmrg pixman_fixed_to_double(t.matrix[1][0]), 1569428d7b3dSmrg pixman_fixed_to_double(t.matrix[1][1]), 1570428d7b3dSmrg pixman_fixed_to_double(t.matrix[1][2]), 1571428d7b3dSmrg pixman_fixed_to_double(t.matrix[2][0]), 1572428d7b3dSmrg pixman_fixed_to_double(t.matrix[2][1]), 1573428d7b3dSmrg pixman_fixed_to_double(t.matrix[2][2]))); 1574428d7b3dSmrg pixman_image_set_transform(src, &t); 1575428d7b3dSmrg 1576428d7b3dSmrg sna_image_composite(PictOpSrc, src, NULL, dst, 1577428d7b3dSmrg 0, 0, 1578428d7b3dSmrg 0, 0, 1579428d7b3dSmrg 0, 0, 1580428d7b3dSmrg w2, h2); 1581428d7b3dSmrg free_pixman_pict(picture, src); 1582428d7b3dSmrg pixman_image_unref(dst); 1583428d7b3dSmrg 1584428d7b3dSmrg channel->width = w2; 1585428d7b3dSmrg channel->height = h2; 1586428d7b3dSmrg 1587428d7b3dSmrg channel->filter = PictFilterNearest; 1588428d7b3dSmrg channel->repeat = RepeatNone; 1589428d7b3dSmrg channel->is_affine = true; 1590428d7b3dSmrg 1591428d7b3dSmrg channel->scale[0] = 1.f/w; 1592428d7b3dSmrg channel->scale[1] = 1.f/h; 1593428d7b3dSmrg channel->offset[0] = -dst_x; 1594428d7b3dSmrg channel->offset[1] = -dst_y; 1595428d7b3dSmrg channel->transform = NULL; 1596428d7b3dSmrg 1597428d7b3dSmrg return 1; 1598428d7b3dSmrg} 1599428d7b3dSmrg 1600428d7b3dSmrgint 1601428d7b3dSmrgsna_render_picture_fixup(struct sna *sna, 1602428d7b3dSmrg PicturePtr picture, 1603428d7b3dSmrg struct sna_composite_channel *channel, 1604428d7b3dSmrg int16_t x, int16_t y, 1605428d7b3dSmrg int16_t w, int16_t h, 1606428d7b3dSmrg int16_t dst_x, int16_t dst_y) 1607428d7b3dSmrg{ 1608428d7b3dSmrg pixman_image_t *dst, *src; 1609428d7b3dSmrg int dx, dy; 1610428d7b3dSmrg void *ptr; 1611428d7b3dSmrg 1612428d7b3dSmrg#if NO_FIXUP 1613428d7b3dSmrg return -1; 1614428d7b3dSmrg#endif 1615428d7b3dSmrg 1616428d7b3dSmrg DBG(("%s: (%d, %d)x(%d, %d)\n", __FUNCTION__, x, y, w, h)); 1617428d7b3dSmrg 1618428d7b3dSmrg if (w == 0 || h == 0) { 1619428d7b3dSmrg DBG(("%s: fallback - unknown bounds\n", __FUNCTION__)); 1620428d7b3dSmrg return -1; 1621428d7b3dSmrg } 1622428d7b3dSmrg if (w > sna->render.max_3d_size || h > sna->render.max_3d_size) { 1623428d7b3dSmrg DBG(("%s: fallback - too large (%dx%d)\n", __FUNCTION__, w, h)); 1624428d7b3dSmrg return -1; 1625428d7b3dSmrg } 1626428d7b3dSmrg 1627428d7b3dSmrg if (picture->alphaMap) { 1628428d7b3dSmrg DBG(("%s: alphamap\n", __FUNCTION__)); 1629428d7b3dSmrg if (is_gpu(sna, picture->pDrawable, PREFER_GPU_RENDER) || 1630428d7b3dSmrg is_gpu(sna, picture->alphaMap->pDrawable, PREFER_GPU_RENDER)) { 1631428d7b3dSmrg if (sna_render_picture_flatten(sna, picture, channel, 1632428d7b3dSmrg x, y, w, h, dst_x, dst_y)) 1633428d7b3dSmrg return 1; 1634428d7b3dSmrg } 1635428d7b3dSmrg 1636428d7b3dSmrg goto do_fixup; 1637428d7b3dSmrg } 1638428d7b3dSmrg 1639428d7b3dSmrg if (picture->filter == PictFilterConvolution) { 1640428d7b3dSmrg DBG(("%s: convolution\n", __FUNCTION__)); 1641428d7b3dSmrg if (is_gpu(sna, picture->pDrawable, PREFER_GPU_RENDER)) { 1642428d7b3dSmrg return sna_render_picture_convolve(sna, picture, channel, 1643428d7b3dSmrg x, y, w, h, dst_x, dst_y); 1644428d7b3dSmrg } 1645428d7b3dSmrg 1646428d7b3dSmrg goto do_fixup; 1647428d7b3dSmrg } 1648428d7b3dSmrg 1649428d7b3dSmrgdo_fixup: 1650428d7b3dSmrg if (PICT_FORMAT_RGB(picture->format) == 0) 1651428d7b3dSmrg channel->pict_format = PIXMAN_a8; 1652428d7b3dSmrg else 1653428d7b3dSmrg channel->pict_format = PIXMAN_a8r8g8b8; 1654428d7b3dSmrg 1655428d7b3dSmrg if (picture->pDrawable && 1656428d7b3dSmrg !sna_drawable_move_to_cpu(picture->pDrawable, MOVE_READ)) 1657428d7b3dSmrg return 0; 1658428d7b3dSmrg 1659428d7b3dSmrg channel->bo = kgem_create_buffer_2d(&sna->kgem, 1660428d7b3dSmrg w, h, PIXMAN_FORMAT_BPP(channel->pict_format), 1661428d7b3dSmrg KGEM_BUFFER_WRITE_INPLACE, 1662428d7b3dSmrg &ptr); 1663428d7b3dSmrg if (!channel->bo) { 1664428d7b3dSmrg DBG(("%s: failed to create upload buffer, using clear\n", 1665428d7b3dSmrg __FUNCTION__)); 1666428d7b3dSmrg return 0; 1667428d7b3dSmrg } 1668428d7b3dSmrg 1669428d7b3dSmrg /* Composite in the original format to preserve idiosyncracies */ 1670428d7b3dSmrg if (!kgem_buffer_is_inplace(channel->bo) && 1671428d7b3dSmrg (picture->pDrawable == NULL || 1672428d7b3dSmrg alphaless(picture->format) == alphaless(channel->pict_format))) 1673428d7b3dSmrg dst = pixman_image_create_bits(channel->pict_format, 1674428d7b3dSmrg w, h, ptr, channel->bo->pitch); 1675428d7b3dSmrg else 1676428d7b3dSmrg dst = pixman_image_create_bits((pixman_format_code_t)picture->format, 1677428d7b3dSmrg w, h, NULL, 0); 1678428d7b3dSmrg if (!dst) { 1679428d7b3dSmrg kgem_bo_destroy(&sna->kgem, channel->bo); 1680428d7b3dSmrg return 0; 1681428d7b3dSmrg } 1682428d7b3dSmrg 1683428d7b3dSmrg src = image_from_pict(picture, false, &dx, &dy); 1684428d7b3dSmrg if (src == NULL) { 1685428d7b3dSmrg pixman_image_unref(dst); 1686428d7b3dSmrg kgem_bo_destroy(&sna->kgem, channel->bo); 1687428d7b3dSmrg return 0; 1688428d7b3dSmrg } 1689428d7b3dSmrg 1690428d7b3dSmrg DBG(("%s: compositing tmp=(%d+%d, %d+%d)x(%d, %d)\n", 1691428d7b3dSmrg __FUNCTION__, x, dx, y, dy, w, h)); 1692428d7b3dSmrg sna_image_composite(PictOpSrc, src, NULL, dst, 1693428d7b3dSmrg x + dx, y + dy, 1694428d7b3dSmrg 0, 0, 1695428d7b3dSmrg 0, 0, 1696428d7b3dSmrg w, h); 1697428d7b3dSmrg free_pixman_pict(picture, src); 1698428d7b3dSmrg 1699428d7b3dSmrg /* Then convert to card format */ 1700428d7b3dSmrg if (pixman_image_get_data(dst) != ptr) { 1701428d7b3dSmrg DBG(("%s: performing post-conversion %08x->%08x (%d, %d)\n", 1702428d7b3dSmrg __FUNCTION__, 1703428d7b3dSmrg picture->format, channel->pict_format, 1704428d7b3dSmrg w, h)); 1705428d7b3dSmrg 1706428d7b3dSmrg src = dst; 1707428d7b3dSmrg dst = pixman_image_create_bits(channel->pict_format, 1708428d7b3dSmrg w, h, ptr, channel->bo->pitch); 1709428d7b3dSmrg if (dst) { 1710428d7b3dSmrg sna_image_composite(PictOpSrc, src, NULL, dst, 1711428d7b3dSmrg 0, 0, 1712428d7b3dSmrg 0, 0, 1713428d7b3dSmrg 0, 0, 1714428d7b3dSmrg w, h); 1715428d7b3dSmrg pixman_image_unref(src); 1716428d7b3dSmrg } else { 1717428d7b3dSmrg memset(ptr, 0, __kgem_buffer_size(channel->bo)); 1718428d7b3dSmrg dst = src; 1719428d7b3dSmrg } 1720428d7b3dSmrg } 1721428d7b3dSmrg pixman_image_unref(dst); 1722428d7b3dSmrg 1723428d7b3dSmrg channel->width = w; 1724428d7b3dSmrg channel->height = h; 1725428d7b3dSmrg 1726428d7b3dSmrg channel->filter = PictFilterNearest; 1727428d7b3dSmrg channel->repeat = RepeatNone; 1728428d7b3dSmrg channel->is_affine = true; 1729428d7b3dSmrg 1730428d7b3dSmrg channel->scale[0] = 1.f/w; 1731428d7b3dSmrg channel->scale[1] = 1.f/h; 1732428d7b3dSmrg channel->offset[0] = -dst_x; 1733428d7b3dSmrg channel->offset[1] = -dst_y; 1734428d7b3dSmrg channel->transform = NULL; 1735428d7b3dSmrg 1736428d7b3dSmrg return 1; 1737428d7b3dSmrg} 1738428d7b3dSmrg 1739428d7b3dSmrgint 1740428d7b3dSmrgsna_render_picture_convert(struct sna *sna, 1741428d7b3dSmrg PicturePtr picture, 1742428d7b3dSmrg struct sna_composite_channel *channel, 1743428d7b3dSmrg PixmapPtr pixmap, 1744428d7b3dSmrg int16_t x, int16_t y, 1745428d7b3dSmrg int16_t w, int16_t h, 1746428d7b3dSmrg int16_t dst_x, int16_t dst_y, 1747428d7b3dSmrg bool fixup_alpha) 1748428d7b3dSmrg{ 1749428d7b3dSmrg BoxRec box; 1750428d7b3dSmrg 1751428d7b3dSmrg#if NO_CONVERT 1752428d7b3dSmrg return -1; 1753428d7b3dSmrg#endif 1754428d7b3dSmrg 1755428d7b3dSmrg if (w != 0 && h != 0) { 1756428d7b3dSmrg box.x1 = x; 1757428d7b3dSmrg box.y1 = y; 1758428d7b3dSmrg box.x2 = bound(x, w); 1759428d7b3dSmrg box.y2 = bound(y, h); 1760428d7b3dSmrg 1761428d7b3dSmrg if (channel->transform) { 1762428d7b3dSmrg DBG(("%s: has transform, converting whole surface\n", 1763428d7b3dSmrg __FUNCTION__)); 1764428d7b3dSmrg box.x1 = box.y1 = 0; 1765428d7b3dSmrg box.x2 = pixmap->drawable.width; 1766428d7b3dSmrg box.y2 = pixmap->drawable.height; 1767428d7b3dSmrg } 1768428d7b3dSmrg 1769428d7b3dSmrg if (box.x1 < 0) 1770428d7b3dSmrg box.x1 = 0; 1771428d7b3dSmrg if (box.y1 < 0) 1772428d7b3dSmrg box.y1 = 0; 1773428d7b3dSmrg if (box.x2 > pixmap->drawable.width) 1774428d7b3dSmrg box.x2 = pixmap->drawable.width; 1775428d7b3dSmrg if (box.y2 > pixmap->drawable.height) 1776428d7b3dSmrg box.y2 = pixmap->drawable.height; 1777428d7b3dSmrg } else { 1778428d7b3dSmrg DBG(("%s: op no bounds, converting whole surface\n", 1779428d7b3dSmrg __FUNCTION__)); 1780428d7b3dSmrg box.x1 = box.y1 = 0; 1781428d7b3dSmrg box.x2 = pixmap->drawable.width; 1782428d7b3dSmrg box.y2 = pixmap->drawable.height; 1783428d7b3dSmrg } 1784428d7b3dSmrg 1785428d7b3dSmrg w = box.x2 - box.x1; 1786428d7b3dSmrg h = box.y2 - box.y1; 1787428d7b3dSmrg 1788428d7b3dSmrg DBG(("%s: convert (%d, %d)x(%d, %d), source size %dx%d\n", 1789428d7b3dSmrg __FUNCTION__, box.x1, box.y1, w, h, 1790428d7b3dSmrg pixmap->drawable.width, 1791428d7b3dSmrg pixmap->drawable.height)); 1792428d7b3dSmrg 1793428d7b3dSmrg if (w <= 0 || h <= 0) { 1794428d7b3dSmrg DBG(("%s: sample extents lie outside of source, using clear\n", 1795428d7b3dSmrg __FUNCTION__)); 1796428d7b3dSmrg return 0; 1797428d7b3dSmrg } 1798428d7b3dSmrg 1799428d7b3dSmrg if (fixup_alpha && is_gpu(sna, &pixmap->drawable, PREFER_GPU_RENDER)) { 1800428d7b3dSmrg ScreenPtr screen = pixmap->drawable.pScreen; 1801428d7b3dSmrg PixmapPtr tmp; 1802428d7b3dSmrg PicturePtr src, dst; 1803428d7b3dSmrg int error; 1804428d7b3dSmrg 1805428d7b3dSmrg assert(PICT_FORMAT_BPP(picture->format) == pixmap->drawable.bitsPerPixel); 1806428d7b3dSmrg channel->pict_format = PICT_FORMAT(PICT_FORMAT_BPP(picture->format), 1807428d7b3dSmrg PICT_FORMAT_TYPE(picture->format), 1808428d7b3dSmrg PICT_FORMAT_BPP(picture->format) - PIXMAN_FORMAT_DEPTH(picture->format), 1809428d7b3dSmrg PICT_FORMAT_R(picture->format), 1810428d7b3dSmrg PICT_FORMAT_G(picture->format), 1811428d7b3dSmrg PICT_FORMAT_B(picture->format)); 1812428d7b3dSmrg 1813428d7b3dSmrg DBG(("%s: converting to %08x from %08x using composite alpha-fixup\n", 1814428d7b3dSmrg __FUNCTION__, 1815428d7b3dSmrg (unsigned)channel->pict_format, 1816428d7b3dSmrg (unsigned)picture->format)); 1817428d7b3dSmrg 1818428d7b3dSmrg tmp = screen->CreatePixmap(screen, w, h, pixmap->drawable.bitsPerPixel, SNA_CREATE_SCRATCH); 1819428d7b3dSmrg if (tmp == NULL) 1820428d7b3dSmrg return -1; 1821428d7b3dSmrg 1822428d7b3dSmrg assert(__sna_pixmap_get_bo(tmp)); 1823428d7b3dSmrg 1824428d7b3dSmrg dst = CreatePicture(0, &tmp->drawable, 1825428d7b3dSmrg PictureMatchFormat(screen, 1826428d7b3dSmrg pixmap->drawable.bitsPerPixel, 1827428d7b3dSmrg channel->pict_format), 1828428d7b3dSmrg 0, NULL, serverClient, &error); 1829428d7b3dSmrg if (dst == NULL) { 1830428d7b3dSmrg screen->DestroyPixmap(tmp); 1831428d7b3dSmrg return 0; 1832428d7b3dSmrg } 1833428d7b3dSmrg 1834428d7b3dSmrg src = CreatePicture(0, &pixmap->drawable, 1835428d7b3dSmrg PictureMatchFormat(screen, 1836428d7b3dSmrg pixmap->drawable.depth, 1837428d7b3dSmrg picture->format), 1838428d7b3dSmrg 0, NULL, serverClient, &error); 1839428d7b3dSmrg if (src == NULL) { 1840428d7b3dSmrg FreePicture(dst, 0); 1841428d7b3dSmrg screen->DestroyPixmap(tmp); 1842428d7b3dSmrg return 0; 1843428d7b3dSmrg } 1844428d7b3dSmrg 1845428d7b3dSmrg ValidatePicture(src); 1846428d7b3dSmrg ValidatePicture(dst); 1847428d7b3dSmrg 1848428d7b3dSmrg sna_composite(PictOpSrc, src, NULL, dst, 1849428d7b3dSmrg box.x1, box.y1, 1850428d7b3dSmrg 0, 0, 1851428d7b3dSmrg 0, 0, 1852428d7b3dSmrg w, h); 1853428d7b3dSmrg FreePicture(dst, 0); 1854428d7b3dSmrg FreePicture(src, 0); 1855428d7b3dSmrg 1856428d7b3dSmrg channel->bo = __sna_pixmap_get_bo(tmp); 1857428d7b3dSmrg kgem_bo_reference(channel->bo); 1858428d7b3dSmrg screen->DestroyPixmap(tmp); 1859428d7b3dSmrg } else { 1860428d7b3dSmrg pixman_image_t *src, *dst; 1861428d7b3dSmrg void *ptr; 1862428d7b3dSmrg 1863428d7b3dSmrg if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ)) 1864428d7b3dSmrg return 0; 1865428d7b3dSmrg 1866428d7b3dSmrg src = pixman_image_create_bits((pixman_format_code_t)picture->format, 1867428d7b3dSmrg pixmap->drawable.width, 1868428d7b3dSmrg pixmap->drawable.height, 1869428d7b3dSmrg pixmap->devPrivate.ptr, 1870428d7b3dSmrg pixmap->devKind); 1871428d7b3dSmrg if (!src) 1872428d7b3dSmrg return 0; 1873428d7b3dSmrg 1874428d7b3dSmrg if (PICT_FORMAT_RGB(picture->format) == 0) { 1875428d7b3dSmrg channel->pict_format = PIXMAN_a8; 1876428d7b3dSmrg DBG(("%s: converting to a8 from %08x\n", 1877428d7b3dSmrg __FUNCTION__, picture->format)); 1878428d7b3dSmrg } else { 1879428d7b3dSmrg channel->pict_format = PIXMAN_a8r8g8b8; 1880428d7b3dSmrg DBG(("%s: converting to a8r8g8b8 from %08x\n", 1881428d7b3dSmrg __FUNCTION__, picture->format)); 1882428d7b3dSmrg } 1883428d7b3dSmrg 1884428d7b3dSmrg channel->bo = kgem_create_buffer_2d(&sna->kgem, 1885428d7b3dSmrg w, h, PIXMAN_FORMAT_BPP(channel->pict_format), 1886428d7b3dSmrg KGEM_BUFFER_WRITE_INPLACE, 1887428d7b3dSmrg &ptr); 1888428d7b3dSmrg if (!channel->bo) { 1889428d7b3dSmrg pixman_image_unref(src); 1890428d7b3dSmrg return 0; 1891428d7b3dSmrg } 1892428d7b3dSmrg 1893428d7b3dSmrg dst = pixman_image_create_bits(channel->pict_format, 1894428d7b3dSmrg w, h, ptr, channel->bo->pitch); 1895428d7b3dSmrg if (!dst) { 1896428d7b3dSmrg kgem_bo_destroy(&sna->kgem, channel->bo); 1897428d7b3dSmrg pixman_image_unref(src); 1898428d7b3dSmrg return 0; 1899428d7b3dSmrg } 1900428d7b3dSmrg 1901428d7b3dSmrg if (sigtrap_get() == 0) { 1902428d7b3dSmrg sna_image_composite(PictOpSrc, src, NULL, dst, 1903428d7b3dSmrg box.x1, box.y1, 1904428d7b3dSmrg 0, 0, 1905428d7b3dSmrg 0, 0, 1906428d7b3dSmrg w, h); 1907428d7b3dSmrg sigtrap_put(); 1908428d7b3dSmrg } 1909428d7b3dSmrg pixman_image_unref(dst); 1910428d7b3dSmrg pixman_image_unref(src); 1911428d7b3dSmrg } 1912428d7b3dSmrg 1913428d7b3dSmrg channel->width = w; 1914428d7b3dSmrg channel->height = h; 1915428d7b3dSmrg 1916428d7b3dSmrg channel->scale[0] = 1.f/w; 1917428d7b3dSmrg channel->scale[1] = 1.f/h; 1918428d7b3dSmrg channel->offset[0] = x - dst_x - box.x1; 1919428d7b3dSmrg channel->offset[1] = y - dst_y - box.y1; 1920428d7b3dSmrg 1921428d7b3dSmrg DBG(("%s: offset=(%d, %d), size=(%d, %d)\n", 1922428d7b3dSmrg __FUNCTION__, 1923428d7b3dSmrg channel->offset[0], channel->offset[1], 1924428d7b3dSmrg channel->width, channel->height)); 1925428d7b3dSmrg return 1; 1926428d7b3dSmrg} 1927428d7b3dSmrg 1928428d7b3dSmrgbool 1929428d7b3dSmrgsna_render_composite_redirect(struct sna *sna, 1930428d7b3dSmrg struct sna_composite_op *op, 1931428d7b3dSmrg int x, int y, int width, int height, 1932428d7b3dSmrg bool partial) 1933428d7b3dSmrg{ 1934428d7b3dSmrg struct sna_composite_redirect *t = &op->redirect; 1935428d7b3dSmrg int bpp = op->dst.pixmap->drawable.bitsPerPixel; 1936428d7b3dSmrg struct kgem_bo *bo; 1937428d7b3dSmrg 1938428d7b3dSmrg assert(t->real_bo == NULL); 1939428d7b3dSmrg 1940428d7b3dSmrg#if NO_REDIRECT 1941428d7b3dSmrg return false; 1942428d7b3dSmrg#endif 1943428d7b3dSmrg 1944428d7b3dSmrg DBG(("%s: target too large (%dx%d), copying to temporary %dx%d, max %d / %d\n", 1945428d7b3dSmrg __FUNCTION__, 1946428d7b3dSmrg op->dst.width, op->dst.height, 1947428d7b3dSmrg width, height, 1948428d7b3dSmrg sna->render.max_3d_size, 1949428d7b3dSmrg sna->render.max_3d_pitch)); 1950428d7b3dSmrg 1951428d7b3dSmrg if (!width || !height) 1952428d7b3dSmrg return false; 1953428d7b3dSmrg 1954428d7b3dSmrg if (width > sna->render.max_3d_size || 1955428d7b3dSmrg height > sna->render.max_3d_size) 1956428d7b3dSmrg return false; 1957428d7b3dSmrg 1958428d7b3dSmrg if (op->dst.bo->pitch <= sna->render.max_3d_pitch) { 1959428d7b3dSmrg BoxRec box; 1960428d7b3dSmrg int w, h, offset; 1961428d7b3dSmrg 1962428d7b3dSmrg DBG(("%s: dst pitch (%d) fits within render pipeline (%d)\n", 1963428d7b3dSmrg __FUNCTION__, op->dst.bo->pitch, sna->render.max_3d_pitch)); 1964428d7b3dSmrg 1965428d7b3dSmrg box.x1 = x + op->dst.x; 1966428d7b3dSmrg box.x2 = bound(box.x1, width); 1967428d7b3dSmrg box.y1 = y + op->dst.y; 1968428d7b3dSmrg box.y2 = bound(box.y1, height); 1969428d7b3dSmrg 1970428d7b3dSmrg if (box.x1 < 0) 1971428d7b3dSmrg box.x1 = 0; 1972428d7b3dSmrg if (box.y1 < 0) 1973428d7b3dSmrg box.y1 = 0; 1974428d7b3dSmrg 1975428d7b3dSmrg /* Ensure we align to an even tile row */ 1976428d7b3dSmrg if (op->dst.bo->tiling) { 1977428d7b3dSmrg int tile_width, tile_height, tile_size; 1978428d7b3dSmrg 1979428d7b3dSmrg kgem_get_tile_size(&sna->kgem, op->dst.bo->tiling, op->dst.bo->pitch, 1980428d7b3dSmrg &tile_width, &tile_height, &tile_size); 1981428d7b3dSmrg 1982428d7b3dSmrg box.y1 = box.y1 & ~(2*tile_height - 1); 1983428d7b3dSmrg box.y2 = ALIGN(box.y2, 2*tile_height); 1984428d7b3dSmrg 1985428d7b3dSmrg box.x1 = box.x1 & ~(tile_width * 8 / op->dst.pixmap->drawable.bitsPerPixel - 1); 1986428d7b3dSmrg box.x2 = ALIGN(box.x2, tile_width * 8 / op->dst.pixmap->drawable.bitsPerPixel); 1987428d7b3dSmrg 1988428d7b3dSmrg if (box.x1 > sna->render.max_3d_size && 1989428d7b3dSmrg box.x2 <= 2*sna->render.max_3d_size) 1990428d7b3dSmrg box.x1 = sna->render.max_3d_size; 1991428d7b3dSmrg 1992428d7b3dSmrg if (box.y1 > sna->render.max_3d_size && 1993428d7b3dSmrg box.y2 <= 2*sna->render.max_3d_size) 1994428d7b3dSmrg box.y1 = sna->render.max_3d_size; 1995428d7b3dSmrg 1996428d7b3dSmrg offset = box.x1 * op->dst.pixmap->drawable.bitsPerPixel / 8 / tile_width * tile_size; 1997428d7b3dSmrg } else { 1998428d7b3dSmrg if (sna->kgem.gen < 040) { 1999428d7b3dSmrg box.y1 = box.y1 & ~3; 2000428d7b3dSmrg box.y2 = ALIGN(box.y2, 4); 2001428d7b3dSmrg 2002428d7b3dSmrg box.x1 = box.x1 & ~3; 2003428d7b3dSmrg box.x2 = ALIGN(box.x2, 4); 2004428d7b3dSmrg } else { 2005428d7b3dSmrg box.y1 = box.y1 & ~1; 2006428d7b3dSmrg box.y2 = ALIGN(box.y2, 2); 2007428d7b3dSmrg 2008428d7b3dSmrg box.x1 = box.x1 & ~1; 2009428d7b3dSmrg box.x2 = ALIGN(box.x2, 2); 2010428d7b3dSmrg } 2011428d7b3dSmrg 2012428d7b3dSmrg if (box.x1 > sna->render.max_3d_size && 2013428d7b3dSmrg box.x2 <= 2*sna->render.max_3d_size) 2014428d7b3dSmrg box.x1 = sna->render.max_3d_size; 2015428d7b3dSmrg 2016428d7b3dSmrg if (box.y1 > sna->render.max_3d_size && 2017428d7b3dSmrg box.y2 <= 2*sna->render.max_3d_size) 2018428d7b3dSmrg box.y1 = sna->render.max_3d_size; 2019428d7b3dSmrg 2020428d7b3dSmrg offset = box.x1 * op->dst.pixmap->drawable.bitsPerPixel / 8; 2021428d7b3dSmrg } 2022428d7b3dSmrg 2023428d7b3dSmrg if (box.y2 > op->dst.pixmap->drawable.height) 2024428d7b3dSmrg box.y2 = op->dst.pixmap->drawable.height; 2025428d7b3dSmrg 2026428d7b3dSmrg if (box.x2 > op->dst.pixmap->drawable.width) 2027428d7b3dSmrg box.x2 = op->dst.pixmap->drawable.width; 2028428d7b3dSmrg 2029428d7b3dSmrg w = box.x2 - box.x1; 2030428d7b3dSmrg h = box.y2 - box.y1; 2031428d7b3dSmrg DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d), max %d\n", __FUNCTION__, 2032428d7b3dSmrg box.x1, box.y1, box.x2, box.y2, w, h, 2033428d7b3dSmrg op->dst.pixmap->drawable.width, 2034428d7b3dSmrg op->dst.pixmap->drawable.height, 2035428d7b3dSmrg sna->render.max_3d_size)); 2036428d7b3dSmrg if (w <= sna->render.max_3d_size && 2037428d7b3dSmrg h <= sna->render.max_3d_size) { 2038428d7b3dSmrg t->box.x2 = t->box.x1 = op->dst.x; 2039428d7b3dSmrg t->box.y2 = t->box.y1 = op->dst.y; 2040428d7b3dSmrg t->real_bo = op->dst.bo; 2041428d7b3dSmrg t->real_damage = op->damage; 2042428d7b3dSmrg if (op->damage) { 2043428d7b3dSmrg assert(!DAMAGE_IS_ALL(op->damage)); 2044428d7b3dSmrg t->damage = sna_damage_create(); 2045428d7b3dSmrg op->damage = &t->damage; 2046428d7b3dSmrg } 2047428d7b3dSmrg 2048428d7b3dSmrg /* How many tiles across are we? */ 2049428d7b3dSmrg op->dst.bo = kgem_create_proxy(&sna->kgem, op->dst.bo, 2050428d7b3dSmrg box.y1 * op->dst.bo->pitch + offset, 2051428d7b3dSmrg h * op->dst.bo->pitch); 2052428d7b3dSmrg if (!op->dst.bo) { 2053428d7b3dSmrg t->real_bo = NULL; 2054428d7b3dSmrg if (t->damage) 2055428d7b3dSmrg __sna_damage_destroy(t->damage); 2056428d7b3dSmrg return false; 2057428d7b3dSmrg } 2058428d7b3dSmrg 2059428d7b3dSmrg assert(op->dst.bo != t->real_bo); 2060428d7b3dSmrg op->dst.bo->pitch = t->real_bo->pitch; 2061428d7b3dSmrg 2062428d7b3dSmrg op->dst.x -= box.x1; 2063428d7b3dSmrg op->dst.y -= box.y1; 2064428d7b3dSmrg op->dst.width = w; 2065428d7b3dSmrg op->dst.height = h; 2066428d7b3dSmrg return true; 2067428d7b3dSmrg } 2068428d7b3dSmrg } 2069428d7b3dSmrg 2070428d7b3dSmrg /* We can process the operation in a single pass, 2071428d7b3dSmrg * but the target is too large for the 3D pipeline. 2072428d7b3dSmrg * Copy into a smaller surface and replace afterwards. 2073428d7b3dSmrg */ 2074428d7b3dSmrg bo = kgem_create_2d(&sna->kgem, 2075428d7b3dSmrg width, height, bpp, 2076428d7b3dSmrg kgem_choose_tiling(&sna->kgem, I915_TILING_X, 2077428d7b3dSmrg width, height, bpp), 2078428d7b3dSmrg CREATE_TEMPORARY); 2079428d7b3dSmrg if (!bo) 2080428d7b3dSmrg return false; 2081428d7b3dSmrg 2082428d7b3dSmrg t->box.x1 = x + op->dst.x; 2083428d7b3dSmrg t->box.y1 = y + op->dst.y; 2084428d7b3dSmrg t->box.x2 = bound(t->box.x1, width); 2085428d7b3dSmrg t->box.y2 = bound(t->box.y1, height); 2086428d7b3dSmrg 2087428d7b3dSmrg DBG(("%s: original box (%d, %d), (%d, %d)\n", 2088428d7b3dSmrg __FUNCTION__, t->box.x1, t->box.y1, t->box.x2, t->box.y2)); 2089428d7b3dSmrg 2090428d7b3dSmrg if (partial && 2091428d7b3dSmrg !sna_blt_copy_boxes(sna, GXcopy, 2092428d7b3dSmrg op->dst.bo, 0, 0, 2093428d7b3dSmrg bo, -t->box.x1, -t->box.y1, 2094428d7b3dSmrg bpp, &t->box, 1)) { 2095428d7b3dSmrg kgem_bo_destroy(&sna->kgem, bo); 2096428d7b3dSmrg return false; 2097428d7b3dSmrg } 2098428d7b3dSmrg 2099428d7b3dSmrg t->real_bo = op->dst.bo; 2100428d7b3dSmrg t->real_damage = op->damage; 2101428d7b3dSmrg if (op->damage) { 2102428d7b3dSmrg assert(!DAMAGE_IS_ALL(op->damage)); 2103428d7b3dSmrg t->damage = sna_damage_create(); 2104428d7b3dSmrg op->damage = &t->damage; 2105428d7b3dSmrg } 2106428d7b3dSmrg 2107428d7b3dSmrg op->dst.bo = bo; 2108428d7b3dSmrg op->dst.x = -x; 2109428d7b3dSmrg op->dst.y = -y; 2110428d7b3dSmrg op->dst.width = width; 2111428d7b3dSmrg op->dst.height = height; 2112428d7b3dSmrg return true; 2113428d7b3dSmrg} 2114428d7b3dSmrg 2115428d7b3dSmrgvoid 2116428d7b3dSmrgsna_render_composite_redirect_done(struct sna *sna, 2117428d7b3dSmrg const struct sna_composite_op *op) 2118428d7b3dSmrg{ 2119428d7b3dSmrg const struct sna_composite_redirect *t = &op->redirect; 2120428d7b3dSmrg 2121428d7b3dSmrg if (t->real_bo) { 2122428d7b3dSmrg assert(op->dst.bo != t->real_bo); 2123428d7b3dSmrg 2124428d7b3dSmrg if (t->box.x2 > t->box.x1) { 2125428d7b3dSmrg bool ok; 2126428d7b3dSmrg 2127428d7b3dSmrg DBG(("%s: copying temporary to dst\n", __FUNCTION__)); 2128428d7b3dSmrg ok = sna_blt_copy_boxes(sna, GXcopy, 2129428d7b3dSmrg op->dst.bo, -t->box.x1, -t->box.y1, 2130428d7b3dSmrg t->real_bo, 0, 0, 2131428d7b3dSmrg op->dst.pixmap->drawable.bitsPerPixel, 2132428d7b3dSmrg &t->box, 1); 2133428d7b3dSmrg assert(ok); 2134428d7b3dSmrg (void)ok; 2135428d7b3dSmrg } 2136428d7b3dSmrg if (t->damage) { 2137428d7b3dSmrg DBG(("%s: combining damage (all? %d), offset=(%d, %d)\n", 2138428d7b3dSmrg __FUNCTION__, (int)DAMAGE_IS_ALL(t->damage), 2139428d7b3dSmrg t->box.x1, t->box.y1)); 2140428d7b3dSmrg sna_damage_combine(t->real_damage, 2141428d7b3dSmrg DAMAGE_PTR(t->damage), 2142428d7b3dSmrg t->box.x1, t->box.y1); 2143428d7b3dSmrg __sna_damage_destroy(DAMAGE_PTR(t->damage)); 2144428d7b3dSmrg } 2145428d7b3dSmrg 2146428d7b3dSmrg kgem_bo_destroy(&sna->kgem, op->dst.bo); 2147428d7b3dSmrg } 2148428d7b3dSmrg} 2149428d7b3dSmrg 2150428d7b3dSmrgstatic bool 2151428d7b3dSmrgcopy_overlap(struct sna *sna, uint8_t alu, 2152428d7b3dSmrg const DrawableRec *draw, struct kgem_bo *bo, 2153428d7b3dSmrg int16_t src_dx, int16_t src_dy, 2154428d7b3dSmrg int16_t dst_dx, int16_t dst_dy, 2155428d7b3dSmrg const BoxRec *box, int n, const BoxRec *extents) 2156428d7b3dSmrg{ 2157428d7b3dSmrg ScreenPtr screen = draw->pScreen; 2158428d7b3dSmrg struct kgem_bo *tmp_bo; 2159428d7b3dSmrg PixmapPtr tmp; 2160428d7b3dSmrg bool ret = false; 2161428d7b3dSmrg 2162428d7b3dSmrg if (n == 0) 2163428d7b3dSmrg return true; 2164428d7b3dSmrg 2165428d7b3dSmrg DBG(("%s: %d x %dx%d src=(%d, %d), dst=(%d, %d)\n", 2166428d7b3dSmrg __FUNCTION__, n, 2167428d7b3dSmrg extents->x2 - extents->x1, 2168428d7b3dSmrg extents->y2 - extents->y1, 2169428d7b3dSmrg src_dx, src_dy, 2170428d7b3dSmrg dst_dx, dst_dy)); 2171428d7b3dSmrg 2172428d7b3dSmrg tmp = screen->CreatePixmap(screen, 2173428d7b3dSmrg extents->x2 - extents->x1, 2174428d7b3dSmrg extents->y2 - extents->y1, 2175428d7b3dSmrg draw->depth, 2176428d7b3dSmrg SNA_CREATE_SCRATCH); 2177428d7b3dSmrg if (tmp == NULL) 2178428d7b3dSmrg return false; 2179428d7b3dSmrg 2180428d7b3dSmrg tmp_bo = __sna_pixmap_get_bo(tmp); 2181428d7b3dSmrg assert(tmp_bo); 2182428d7b3dSmrg 2183428d7b3dSmrg ret = (sna->render.copy_boxes(sna, GXcopy, 2184428d7b3dSmrg draw, bo, src_dx, src_dy, 2185428d7b3dSmrg &tmp->drawable, tmp_bo, -extents->x1, -extents->y1, 2186428d7b3dSmrg box, n , 0) && 2187428d7b3dSmrg sna->render.copy_boxes(sna, alu, 2188428d7b3dSmrg &tmp->drawable, tmp_bo, -extents->x1, -extents->y1, 2189428d7b3dSmrg draw, bo, dst_dx, dst_dy, 2190428d7b3dSmrg box, n , 0)); 2191428d7b3dSmrg 2192428d7b3dSmrg screen->DestroyPixmap(tmp); 2193428d7b3dSmrg return ret; 2194428d7b3dSmrg} 2195428d7b3dSmrgbool 2196428d7b3dSmrgsna_render_copy_boxes__overlap(struct sna *sna, uint8_t alu, 2197428d7b3dSmrg const DrawableRec *draw, struct kgem_bo *bo, 2198428d7b3dSmrg int16_t src_dx, int16_t src_dy, 2199428d7b3dSmrg int16_t dst_dx, int16_t dst_dy, 2200428d7b3dSmrg const BoxRec *box, int n, const BoxRec *extents) 2201428d7b3dSmrg{ 2202428d7b3dSmrg bool ret = false; 2203428d7b3dSmrg RegionRec overlap, non_overlap; 2204428d7b3dSmrg pixman_region16_t region; 2205428d7b3dSmrg pixman_box16_t stack_boxes[64], *boxes = stack_boxes; 2206428d7b3dSmrg int num_boxes, i; 2207428d7b3dSmrg 2208428d7b3dSmrg DBG(("%s: pixmap=%ld, handle=%d, %d x [(%d, %d), (%d, %d)], dst=(%d, %d), src=(%d, %d)\n", 2209428d7b3dSmrg __FUNCTION__, draw->serialNumber, bo->handle, 2210428d7b3dSmrg n, extents->x1, extents->y1, extents->x2, extents->y2, 2211428d7b3dSmrg src_dx, src_dy, dst_dx, dst_dy)); 2212428d7b3dSmrg 2213428d7b3dSmrg if ((dst_dx - src_dx < 4 && src_dx - dst_dx < 4) && 2214428d7b3dSmrg (dst_dy - src_dy < 4 && src_dy - dst_dy < 4)) 2215428d7b3dSmrg return copy_overlap(sna, alu, draw, bo, 2216428d7b3dSmrg src_dx, src_dy, 2217428d7b3dSmrg dst_dx, dst_dy, 2218428d7b3dSmrg box, n, extents); 2219428d7b3dSmrg 2220428d7b3dSmrg if (n > ARRAY_SIZE(stack_boxes)) { 2221428d7b3dSmrg boxes = malloc(sizeof(pixman_box16_t) * n); 2222428d7b3dSmrg if (boxes == NULL) 2223428d7b3dSmrg return copy_overlap(sna, alu, draw, bo, 2224428d7b3dSmrg src_dx, src_dy, 2225428d7b3dSmrg dst_dx, dst_dy, 2226428d7b3dSmrg box, n, extents); 2227428d7b3dSmrg } 2228428d7b3dSmrg 2229428d7b3dSmrg region.extents.x1 = extents->x1 + dst_dx; 2230428d7b3dSmrg region.extents.x2 = extents->x2 + dst_dx; 2231428d7b3dSmrg region.extents.y1 = extents->y1 + dst_dy; 2232428d7b3dSmrg region.extents.y2 = extents->y2 + dst_dy; 2233428d7b3dSmrg 2234428d7b3dSmrg for (i = num_boxes = 0; i < n; i++) { 2235428d7b3dSmrg boxes[num_boxes].x1 = box[i].x1 + dst_dx; 2236428d7b3dSmrg if (boxes[num_boxes].x1 < region.extents.x1) 2237428d7b3dSmrg boxes[num_boxes].x1 = region.extents.x1; 2238428d7b3dSmrg 2239428d7b3dSmrg boxes[num_boxes].y1 = box[i].y1 + dst_dy; 2240428d7b3dSmrg if (boxes[num_boxes].y1 < region.extents.y1) 2241428d7b3dSmrg boxes[num_boxes].y1 = region.extents.y1; 2242428d7b3dSmrg 2243428d7b3dSmrg boxes[num_boxes].x2 = box[i].x2 + dst_dx; 2244428d7b3dSmrg if (boxes[num_boxes].x2 > region.extents.x2) 2245428d7b3dSmrg boxes[num_boxes].x2 = region.extents.x2; 2246428d7b3dSmrg 2247428d7b3dSmrg boxes[num_boxes].y2 = box[i].y2 + dst_dy; 2248428d7b3dSmrg if (boxes[num_boxes].y2 > region.extents.y2) 2249428d7b3dSmrg boxes[num_boxes].y2 = region.extents.y2; 2250428d7b3dSmrg 2251428d7b3dSmrg if (boxes[num_boxes].x2 > boxes[num_boxes].x1 && 2252428d7b3dSmrg boxes[num_boxes].y2 > boxes[num_boxes].y1) 2253428d7b3dSmrg num_boxes++; 2254428d7b3dSmrg } 2255428d7b3dSmrg 2256428d7b3dSmrg if (num_boxes == 0) { 2257428d7b3dSmrg ret = true; 2258428d7b3dSmrg goto cleanup_boxes; 2259428d7b3dSmrg } 2260428d7b3dSmrg 2261428d7b3dSmrg if (!pixman_region_init_rects(®ion, boxes, num_boxes)) 2262428d7b3dSmrg goto cleanup_boxes; 2263428d7b3dSmrg 2264428d7b3dSmrg overlap.extents.x1 = extents->x1 + src_dx; 2265428d7b3dSmrg overlap.extents.x2 = extents->x2 + src_dx; 2266428d7b3dSmrg overlap.extents.y1 = extents->y1 + src_dy; 2267428d7b3dSmrg overlap.extents.y2 = extents->y2 + src_dy; 2268428d7b3dSmrg overlap.data = NULL; 2269428d7b3dSmrg 2270428d7b3dSmrg RegionIntersect(&overlap, &overlap, ®ion); 2271428d7b3dSmrg DBG(("%s: overlapping extents: (%d, %d), (%d, %d) x %d\n", 2272428d7b3dSmrg __FUNCTION__, 2273428d7b3dSmrg overlap.extents.x1, overlap.extents.y1, 2274428d7b3dSmrg overlap.extents.x2, overlap.extents.y2, 2275428d7b3dSmrg region_num_rects(&overlap))); 2276428d7b3dSmrg 2277428d7b3dSmrg RegionNull(&non_overlap); 2278428d7b3dSmrg RegionSubtract(&non_overlap, ®ion, &overlap); 2279428d7b3dSmrg DBG(("%s: non-overlapping extents: (%d, %d), (%d, %d) x %d\n", 2280428d7b3dSmrg __FUNCTION__, 2281428d7b3dSmrg non_overlap.extents.x1, non_overlap.extents.y1, 2282428d7b3dSmrg non_overlap.extents.x2, non_overlap.extents.y2, 2283428d7b3dSmrg region_num_rects(&non_overlap))); 2284428d7b3dSmrg 2285428d7b3dSmrg n = region_num_rects(&non_overlap); 2286428d7b3dSmrg box = region_rects(&non_overlap); 2287428d7b3dSmrg if (n && !sna->render.copy_boxes(sna, alu, 2288428d7b3dSmrg draw, bo, -dst_dx + src_dx, -dst_dy + src_dy, 2289428d7b3dSmrg draw, bo, 0, 0, 2290428d7b3dSmrg box, n , COPY_NO_OVERLAP)) 2291428d7b3dSmrg goto cleanup_boxes; 2292428d7b3dSmrg 2293428d7b3dSmrg n = region_num_rects(&overlap); 2294428d7b3dSmrg box = region_rects(&overlap); 2295428d7b3dSmrg ret = copy_overlap(sna, alu, draw, bo, 2296428d7b3dSmrg -dst_dx + src_dx, -dst_dy + src_dy, 2297428d7b3dSmrg 0, 0, 2298428d7b3dSmrg box, n, &overlap.extents); 2299428d7b3dSmrg 2300428d7b3dSmrgcleanup_boxes: 2301428d7b3dSmrg if (boxes != stack_boxes) 2302428d7b3dSmrg free(boxes); 2303428d7b3dSmrg 2304428d7b3dSmrg return ret; 2305428d7b3dSmrg} 2306428d7b3dSmrg 2307428d7b3dSmrgstatic bool can_copy_cpu(struct sna *sna, 2308428d7b3dSmrg struct kgem_bo *src, 2309428d7b3dSmrg struct kgem_bo *dst) 2310428d7b3dSmrg{ 2311428d7b3dSmrg if (src->tiling != dst->tiling) 2312428d7b3dSmrg return false; 2313428d7b3dSmrg 2314428d7b3dSmrg if (src->pitch != dst->pitch) 2315428d7b3dSmrg return false; 2316428d7b3dSmrg 2317428d7b3dSmrg if (!kgem_bo_can_map__cpu(&sna->kgem, src, false)) 2318428d7b3dSmrg return false; 2319428d7b3dSmrg 2320428d7b3dSmrg if (!kgem_bo_can_map__cpu(&sna->kgem, dst, true)) 2321428d7b3dSmrg return false; 2322428d7b3dSmrg 2323428d7b3dSmrg DBG(("%s -- yes, src handle=%d, dst handle=%d\n", __FUNCTION__, src->handle, dst->handle)); 2324428d7b3dSmrg return true; 2325428d7b3dSmrg} 2326428d7b3dSmrg 2327428d7b3dSmrgbool 2328428d7b3dSmrgmemcpy_copy_boxes(struct sna *sna, uint8_t op, 2329428d7b3dSmrg const DrawableRec *src_draw, struct kgem_bo *src_bo, int16_t sx, int16_t sy, 2330428d7b3dSmrg const DrawableRec *dst_draw, struct kgem_bo *dst_bo, int16_t dx, int16_t dy, 2331428d7b3dSmrg const BoxRec *box, int n, unsigned flags) 2332428d7b3dSmrg{ 2333428d7b3dSmrg void *dst, *src; 2334428d7b3dSmrg bool clipped; 2335428d7b3dSmrg 2336428d7b3dSmrg if (op != GXcopy) 2337428d7b3dSmrg return false; 2338428d7b3dSmrg 2339428d7b3dSmrg clipped = (n > 1 || 2340428d7b3dSmrg box->x1 + dx > 0 || 2341428d7b3dSmrg box->y1 + dy > 0 || 2342428d7b3dSmrg box->x2 + dx < dst_draw->width || 2343428d7b3dSmrg box->y2 + dy < dst_draw->height); 2344428d7b3dSmrg 2345428d7b3dSmrg dst = src = NULL; 2346428d7b3dSmrg if (!clipped && can_copy_cpu(sna, src_bo, dst_bo)) { 2347428d7b3dSmrg dst = kgem_bo_map__cpu(&sna->kgem, dst_bo); 2348428d7b3dSmrg src = kgem_bo_map__cpu(&sna->kgem, src_bo); 2349428d7b3dSmrg } 2350428d7b3dSmrg 2351428d7b3dSmrg if (dst == NULL || src == NULL) { 2352428d7b3dSmrg dst = kgem_bo_map__gtt(&sna->kgem, dst_bo); 2353428d7b3dSmrg src = kgem_bo_map__gtt(&sna->kgem, src_bo); 2354428d7b3dSmrg if (dst == NULL || src == NULL) 2355428d7b3dSmrg return false; 2356428d7b3dSmrg } else { 2357428d7b3dSmrg kgem_bo_sync__cpu_full(&sna->kgem, dst_bo, true); 2358428d7b3dSmrg kgem_bo_sync__cpu_full(&sna->kgem, src_bo, false); 2359428d7b3dSmrg } 2360428d7b3dSmrg 2361428d7b3dSmrg DBG(("%s: src(%d, %d), dst(%d, %d) x %d\n", 2362428d7b3dSmrg __FUNCTION__, sx, sy, dx, dy, n)); 2363428d7b3dSmrg 2364428d7b3dSmrg if (sigtrap_get() == 0) { 2365428d7b3dSmrg do { 2366428d7b3dSmrg memcpy_blt(src, dst, dst_draw->bitsPerPixel, 2367428d7b3dSmrg src_bo->pitch, dst_bo->pitch, 2368428d7b3dSmrg box->x1 + sx, box->y1 + sy, 2369428d7b3dSmrg box->x1 + dx, box->y1 + dy, 2370428d7b3dSmrg box->x2 - box->x1, box->y2 - box->y1); 2371428d7b3dSmrg box++; 2372428d7b3dSmrg } while (--n); 2373428d7b3dSmrg sigtrap_put(); 2374428d7b3dSmrg } 2375428d7b3dSmrg 2376428d7b3dSmrg return true; 2377428d7b3dSmrg} 2378428d7b3dSmrg 2379428d7b3dSmrgvoid 2380428d7b3dSmrgsna_render_mark_wedged(struct sna *sna) 2381428d7b3dSmrg{ 2382428d7b3dSmrg sna->render.copy_boxes = memcpy_copy_boxes; 2383428d7b3dSmrg} 2384