sna_render.c revision 03b705cf
103b705cfSriastradh/* 203b705cfSriastradh * Copyright © 2011 Intel Corporation 303b705cfSriastradh * 403b705cfSriastradh * Permission is hereby granted, free of charge, to any person obtaining a 503b705cfSriastradh * copy of this software and associated documentation files (the "Software"), 603b705cfSriastradh * to deal in the Software without restriction, including without limitation 703b705cfSriastradh * the rights to use, copy, modify, merge, publish, distribute, sublicense, 803b705cfSriastradh * and/or sell copies of the Software, and to permit persons to whom the 903b705cfSriastradh * Software is furnished to do so, subject to the following conditions: 1003b705cfSriastradh * 1103b705cfSriastradh * The above copyright notice and this permission notice (including the next 1203b705cfSriastradh * paragraph) shall be included in all copies or substantial portions of the 1303b705cfSriastradh * Software. 1403b705cfSriastradh * 1503b705cfSriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1603b705cfSriastradh * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1703b705cfSriastradh * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1803b705cfSriastradh * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1903b705cfSriastradh * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2003b705cfSriastradh * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 2103b705cfSriastradh * SOFTWARE. 2203b705cfSriastradh * 2303b705cfSriastradh * Authors: 2403b705cfSriastradh * Chris Wilson <chris@chris-wilson.co.uk> 2503b705cfSriastradh * 2603b705cfSriastradh */ 2703b705cfSriastradh 2803b705cfSriastradh#include "sna.h" 2903b705cfSriastradh#include "sna_render.h" 3003b705cfSriastradh#include "sna_render_inline.h" 3103b705cfSriastradh#include "fb/fbpict.h" 3203b705cfSriastradh 3303b705cfSriastradh#define NO_REDIRECT 0 3403b705cfSriastradh#define NO_CONVERT 0 3503b705cfSriastradh#define NO_FIXUP 0 3603b705cfSriastradh#define NO_EXTRACT 0 3703b705cfSriastradh 3803b705cfSriastradh#define DBG_FORCE_UPLOAD 0 3903b705cfSriastradh#define DBG_NO_CPU_BO 0 4003b705cfSriastradh 4103b705cfSriastradh#define alphaless(format) PICT_FORMAT(PICT_FORMAT_BPP(format), \ 4203b705cfSriastradh PICT_FORMAT_TYPE(format), \ 4303b705cfSriastradh 0, \ 4403b705cfSriastradh PICT_FORMAT_R(format), \ 4503b705cfSriastradh PICT_FORMAT_G(format), \ 4603b705cfSriastradh PICT_FORMAT_B(format)) 4703b705cfSriastradh 4803b705cfSriastradhCARD32 4903b705cfSriastradhsna_format_for_depth(int depth) 5003b705cfSriastradh{ 5103b705cfSriastradh switch (depth) { 5203b705cfSriastradh case 1: return PICT_a1; 5303b705cfSriastradh case 4: return PICT_a4; 5403b705cfSriastradh case 8: return PICT_a8; 5503b705cfSriastradh case 15: return PICT_x1r5g5b5; 5603b705cfSriastradh case 16: return PICT_r5g6b5; 5703b705cfSriastradh default: assert(0); 5803b705cfSriastradh case 24: return PICT_x8r8g8b8; 5903b705cfSriastradh case 30: return PICT_x2r10g10b10; 6003b705cfSriastradh case 32: return PICT_a8r8g8b8; 6103b705cfSriastradh } 6203b705cfSriastradh} 6303b705cfSriastradh 6403b705cfSriastradhCARD32 6503b705cfSriastradhsna_render_format_for_depth(int depth) 6603b705cfSriastradh{ 6703b705cfSriastradh switch (depth) { 6803b705cfSriastradh case 1: return PIXMAN_a1; 6903b705cfSriastradh case 4: return PIXMAN_a4; 7003b705cfSriastradh case 8: return PIXMAN_a8; 7103b705cfSriastradh case 15: return PIXMAN_a1r5g5b5; 7203b705cfSriastradh case 16: return PIXMAN_r5g6b5; 7303b705cfSriastradh case 30: return PIXMAN_a2r10g10b10; 7403b705cfSriastradh default: assert(0); 7503b705cfSriastradh case 24: 7603b705cfSriastradh case 32: return PIXMAN_a8r8g8b8; 7703b705cfSriastradh } 7803b705cfSriastradh} 7903b705cfSriastradh 8003b705cfSriastradhstatic bool 8103b705cfSriastradhno_render_composite(struct sna *sna, 8203b705cfSriastradh uint8_t op, 8303b705cfSriastradh PicturePtr src, 8403b705cfSriastradh PicturePtr mask, 8503b705cfSriastradh PicturePtr dst, 8603b705cfSriastradh int16_t src_x, int16_t src_y, 8703b705cfSriastradh int16_t mask_x, int16_t mask_y, 8803b705cfSriastradh int16_t dst_x, int16_t dst_y, 8903b705cfSriastradh int16_t width, int16_t height, 9003b705cfSriastradh struct sna_composite_op *tmp) 9103b705cfSriastradh{ 9203b705cfSriastradh DBG(("%s (op=%d, mask? %d)\n", __FUNCTION__, op, mask != NULL)); 9303b705cfSriastradh 9403b705cfSriastradh if (mask) 9503b705cfSriastradh return false; 9603b705cfSriastradh 9703b705cfSriastradh if (!is_gpu(sna, dst->pDrawable, PREFER_GPU_BLT) && 9803b705cfSriastradh (src->pDrawable == NULL || !is_gpu(sna, src->pDrawable, PREFER_GPU_BLT))) 9903b705cfSriastradh return false; 10003b705cfSriastradh 10103b705cfSriastradh return sna_blt_composite(sna, 10203b705cfSriastradh op, src, dst, 10303b705cfSriastradh src_x, src_y, 10403b705cfSriastradh dst_x, dst_y, 10503b705cfSriastradh width, height, 10603b705cfSriastradh tmp, true); 10703b705cfSriastradh (void)mask_x; 10803b705cfSriastradh (void)mask_y; 10903b705cfSriastradh} 11003b705cfSriastradh 11103b705cfSriastradhstatic bool 11203b705cfSriastradhno_render_check_composite_spans(struct sna *sna, 11303b705cfSriastradh uint8_t op, PicturePtr src, PicturePtr dst, 11403b705cfSriastradh int16_t width, int16_t height, unsigned flags) 11503b705cfSriastradh{ 11603b705cfSriastradh return false; 11703b705cfSriastradh} 11803b705cfSriastradh 11903b705cfSriastradhstatic bool 12003b705cfSriastradhno_render_copy_boxes(struct sna *sna, uint8_t alu, 12103b705cfSriastradh PixmapPtr src, struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy, 12203b705cfSriastradh PixmapPtr dst, struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy, 12303b705cfSriastradh const BoxRec *box, int n, unsigned flags) 12403b705cfSriastradh{ 12503b705cfSriastradh DBG(("%s (n=%d)\n", __FUNCTION__, n)); 12603b705cfSriastradh 12703b705cfSriastradh if (!sna_blt_compare_depth(&src->drawable, &dst->drawable)) 12803b705cfSriastradh return false; 12903b705cfSriastradh 13003b705cfSriastradh return sna_blt_copy_boxes(sna, alu, 13103b705cfSriastradh src_bo, src_dx, src_dy, 13203b705cfSriastradh dst_bo, dst_dx, dst_dy, 13303b705cfSriastradh dst->drawable.bitsPerPixel, 13403b705cfSriastradh box, n); 13503b705cfSriastradh} 13603b705cfSriastradh 13703b705cfSriastradhstatic bool 13803b705cfSriastradhno_render_copy(struct sna *sna, uint8_t alu, 13903b705cfSriastradh PixmapPtr src, struct kgem_bo *src_bo, 14003b705cfSriastradh PixmapPtr dst, struct kgem_bo *dst_bo, 14103b705cfSriastradh struct sna_copy_op *tmp) 14203b705cfSriastradh{ 14303b705cfSriastradh DBG(("%s ()\n", __FUNCTION__)); 14403b705cfSriastradh 14503b705cfSriastradh if (sna_blt_compare_depth(&src->drawable, &dst->drawable) && 14603b705cfSriastradh sna_blt_copy(sna, alu, 14703b705cfSriastradh src_bo, dst_bo, dst->drawable.bitsPerPixel, 14803b705cfSriastradh tmp)) 14903b705cfSriastradh return true; 15003b705cfSriastradh 15103b705cfSriastradh return false; 15203b705cfSriastradh} 15303b705cfSriastradh 15403b705cfSriastradhstatic bool 15503b705cfSriastradhno_render_fill_boxes(struct sna *sna, 15603b705cfSriastradh CARD8 op, 15703b705cfSriastradh PictFormat format, 15803b705cfSriastradh const xRenderColor *color, 15903b705cfSriastradh PixmapPtr dst, struct kgem_bo *dst_bo, 16003b705cfSriastradh const BoxRec *box, int n) 16103b705cfSriastradh{ 16203b705cfSriastradh uint8_t alu = GXcopy; 16303b705cfSriastradh uint32_t pixel; 16403b705cfSriastradh 16503b705cfSriastradh DBG(("%s (op=%d, color=(%04x,%04x,%04x, %04x))\n", 16603b705cfSriastradh __FUNCTION__, op, 16703b705cfSriastradh color->red, color->green, color->blue, color->alpha)); 16803b705cfSriastradh 16903b705cfSriastradh if (op == PictOpClear) { 17003b705cfSriastradh pixel = 0; 17103b705cfSriastradh alu = GXclear; 17203b705cfSriastradh op = PictOpSrc; 17303b705cfSriastradh } 17403b705cfSriastradh 17503b705cfSriastradh if (op == PictOpOver) { 17603b705cfSriastradh if ((color->alpha >= 0xff00)) 17703b705cfSriastradh op = PictOpSrc; 17803b705cfSriastradh } 17903b705cfSriastradh 18003b705cfSriastradh if (op != PictOpSrc) 18103b705cfSriastradh return false; 18203b705cfSriastradh 18303b705cfSriastradh if (alu == GXcopy && 18403b705cfSriastradh !sna_get_pixel_from_rgba(&pixel, 18503b705cfSriastradh color->red, 18603b705cfSriastradh color->green, 18703b705cfSriastradh color->blue, 18803b705cfSriastradh color->alpha, 18903b705cfSriastradh format)) 19003b705cfSriastradh return false; 19103b705cfSriastradh 19203b705cfSriastradh return sna_blt_fill_boxes(sna, alu, 19303b705cfSriastradh dst_bo, dst->drawable.bitsPerPixel, 19403b705cfSriastradh pixel, box, n); 19503b705cfSriastradh} 19603b705cfSriastradh 19703b705cfSriastradhstatic bool 19803b705cfSriastradhno_render_fill(struct sna *sna, uint8_t alu, 19903b705cfSriastradh PixmapPtr dst, struct kgem_bo *dst_bo, 20003b705cfSriastradh uint32_t color, 20103b705cfSriastradh struct sna_fill_op *tmp) 20203b705cfSriastradh{ 20303b705cfSriastradh DBG(("%s (alu=%d, color=%08x)\n", __FUNCTION__, alu, color)); 20403b705cfSriastradh return sna_blt_fill(sna, alu, 20503b705cfSriastradh dst_bo, dst->drawable.bitsPerPixel, 20603b705cfSriastradh color, 20703b705cfSriastradh tmp); 20803b705cfSriastradh} 20903b705cfSriastradh 21003b705cfSriastradhstatic bool 21103b705cfSriastradhno_render_fill_one(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo, 21203b705cfSriastradh uint32_t color, 21303b705cfSriastradh int16_t x1, int16_t y1, int16_t x2, int16_t y2, 21403b705cfSriastradh uint8_t alu) 21503b705cfSriastradh{ 21603b705cfSriastradh BoxRec box; 21703b705cfSriastradh 21803b705cfSriastradh box.x1 = x1; 21903b705cfSriastradh box.y1 = y1; 22003b705cfSriastradh box.x2 = x2; 22103b705cfSriastradh box.y2 = y2; 22203b705cfSriastradh 22303b705cfSriastradh DBG(("%s (alu=%d, color=%08x) (%d,%d), (%d, %d)\n", 22403b705cfSriastradh __FUNCTION__, alu, color, x1, y1, x2, y2)); 22503b705cfSriastradh return sna_blt_fill_boxes(sna, alu, 22603b705cfSriastradh bo, dst->drawable.bitsPerPixel, 22703b705cfSriastradh color, &box, 1); 22803b705cfSriastradh} 22903b705cfSriastradh 23003b705cfSriastradhstatic bool 23103b705cfSriastradhno_render_clear(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo) 23203b705cfSriastradh{ 23303b705cfSriastradh DBG(("%s: pixmap=%ld %dx%d\n", __FUNCTION__, 23403b705cfSriastradh dst->drawable.serialNumber, 23503b705cfSriastradh dst->drawable.width, 23603b705cfSriastradh dst->drawable.height)); 23703b705cfSriastradh return sna->render.fill_one(sna, dst, bo, 0, 23803b705cfSriastradh 0, 0, dst->drawable.width, dst->drawable.height, 23903b705cfSriastradh GXclear); 24003b705cfSriastradh} 24103b705cfSriastradh 24203b705cfSriastradhstatic void no_render_reset(struct sna *sna) 24303b705cfSriastradh{ 24403b705cfSriastradh (void)sna; 24503b705cfSriastradh} 24603b705cfSriastradh 24703b705cfSriastradhstatic void no_render_flush(struct sna *sna) 24803b705cfSriastradh{ 24903b705cfSriastradh (void)sna; 25003b705cfSriastradh} 25103b705cfSriastradh 25203b705cfSriastradhstatic void 25303b705cfSriastradhno_render_context_switch(struct kgem *kgem, 25403b705cfSriastradh int new_mode) 25503b705cfSriastradh{ 25603b705cfSriastradh if (!kgem->nbatch) 25703b705cfSriastradh return; 25803b705cfSriastradh 25903b705cfSriastradh if (kgem_ring_is_idle(kgem, kgem->ring)) { 26003b705cfSriastradh DBG(("%s: GPU idle, flushing\n", __FUNCTION__)); 26103b705cfSriastradh _kgem_submit(kgem); 26203b705cfSriastradh } 26303b705cfSriastradh 26403b705cfSriastradh (void)new_mode; 26503b705cfSriastradh} 26603b705cfSriastradh 26703b705cfSriastradhstatic void 26803b705cfSriastradhno_render_retire(struct kgem *kgem) 26903b705cfSriastradh{ 27003b705cfSriastradh (void)kgem; 27103b705cfSriastradh} 27203b705cfSriastradh 27303b705cfSriastradhstatic void 27403b705cfSriastradhno_render_expire(struct kgem *kgem) 27503b705cfSriastradh{ 27603b705cfSriastradh (void)kgem; 27703b705cfSriastradh} 27803b705cfSriastradh 27903b705cfSriastradhstatic void 28003b705cfSriastradhno_render_fini(struct sna *sna) 28103b705cfSriastradh{ 28203b705cfSriastradh (void)sna; 28303b705cfSriastradh} 28403b705cfSriastradh 28503b705cfSriastradhconst char *no_render_init(struct sna *sna) 28603b705cfSriastradh{ 28703b705cfSriastradh struct sna_render *render = &sna->render; 28803b705cfSriastradh 28903b705cfSriastradh memset (render, 0, sizeof (*render)); 29003b705cfSriastradh 29103b705cfSriastradh render->prefer_gpu = PREFER_GPU_BLT; 29203b705cfSriastradh 29303b705cfSriastradh render->vertices = render->vertex_data; 29403b705cfSriastradh render->vertex_size = ARRAY_SIZE(render->vertex_data); 29503b705cfSriastradh 29603b705cfSriastradh render->composite = no_render_composite; 29703b705cfSriastradh render->check_composite_spans = no_render_check_composite_spans; 29803b705cfSriastradh 29903b705cfSriastradh render->copy_boxes = no_render_copy_boxes; 30003b705cfSriastradh render->copy = no_render_copy; 30103b705cfSriastradh 30203b705cfSriastradh render->fill_boxes = no_render_fill_boxes; 30303b705cfSriastradh render->fill = no_render_fill; 30403b705cfSriastradh render->fill_one = no_render_fill_one; 30503b705cfSriastradh render->clear = no_render_clear; 30603b705cfSriastradh 30703b705cfSriastradh render->reset = no_render_reset; 30803b705cfSriastradh render->flush = no_render_flush; 30903b705cfSriastradh render->fini = no_render_fini; 31003b705cfSriastradh 31103b705cfSriastradh sna->kgem.context_switch = no_render_context_switch; 31203b705cfSriastradh sna->kgem.retire = no_render_retire; 31303b705cfSriastradh sna->kgem.expire = no_render_expire; 31403b705cfSriastradh if (sna->kgem.has_blt) 31503b705cfSriastradh sna->kgem.ring = KGEM_BLT; 31603b705cfSriastradh 31703b705cfSriastradh sna_vertex_init(sna); 31803b705cfSriastradh return "generic"; 31903b705cfSriastradh} 32003b705cfSriastradh 32103b705cfSriastradhstatic struct kgem_bo * 32203b705cfSriastradhuse_cpu_bo(struct sna *sna, PixmapPtr pixmap, const BoxRec *box, bool blt) 32303b705cfSriastradh{ 32403b705cfSriastradh struct sna_pixmap *priv; 32503b705cfSriastradh 32603b705cfSriastradh if (DBG_NO_CPU_BO) 32703b705cfSriastradh return NULL; 32803b705cfSriastradh 32903b705cfSriastradh priv = sna_pixmap(pixmap); 33003b705cfSriastradh if (priv == NULL || priv->cpu_bo == NULL) { 33103b705cfSriastradh DBG(("%s: no cpu bo\n", __FUNCTION__)); 33203b705cfSriastradh return NULL; 33303b705cfSriastradh } 33403b705cfSriastradh 33503b705cfSriastradh if (!blt && priv->cpu_bo->snoop && priv->source_count > SOURCE_BIAS) { 33603b705cfSriastradh DBG(("%s: promoting snooped CPU bo due to reuse\n", 33703b705cfSriastradh __FUNCTION__)); 33803b705cfSriastradh return NULL; 33903b705cfSriastradh } 34003b705cfSriastradh 34103b705cfSriastradh if (priv->gpu_bo) { 34203b705cfSriastradh switch (sna_damage_contains_box(priv->cpu_damage, box)) { 34303b705cfSriastradh case PIXMAN_REGION_OUT: 34403b705cfSriastradh DBG(("%s: has GPU bo and no damage to upload\n", 34503b705cfSriastradh __FUNCTION__)); 34603b705cfSriastradh return NULL; 34703b705cfSriastradh 34803b705cfSriastradh case PIXMAN_REGION_IN: 34903b705cfSriastradh DBG(("%s: has GPU bo but box is completely on CPU\n", 35003b705cfSriastradh __FUNCTION__)); 35103b705cfSriastradh break; 35203b705cfSriastradh default: 35303b705cfSriastradh if (kgem_bo_is_busy(priv->gpu_bo)){ 35403b705cfSriastradh DBG(("%s: box is partially damaged on the CPU, and the GPU is busy\n", 35503b705cfSriastradh __FUNCTION__)); 35603b705cfSriastradh return NULL; 35703b705cfSriastradh } 35803b705cfSriastradh if (sna_damage_contains_box(priv->gpu_damage, 35903b705cfSriastradh box) != PIXMAN_REGION_OUT) { 36003b705cfSriastradh DBG(("%s: box is damaged on the GPU\n", 36103b705cfSriastradh __FUNCTION__)); 36203b705cfSriastradh return NULL; 36303b705cfSriastradh } 36403b705cfSriastradh break; 36503b705cfSriastradh } 36603b705cfSriastradh } 36703b705cfSriastradh 36803b705cfSriastradh if (!blt) { 36903b705cfSriastradh int w = box->x2 - box->x1; 37003b705cfSriastradh int h = box->y2 - box->y1; 37103b705cfSriastradh 37203b705cfSriastradh if (w < pixmap->drawable.width || 37303b705cfSriastradh h < pixmap->drawable.height || 37403b705cfSriastradh priv->source_count != SOURCE_BIAS) { 37503b705cfSriastradh bool want_tiling; 37603b705cfSriastradh 37703b705cfSriastradh if (priv->cpu_bo->pitch >= 4096) { 37803b705cfSriastradh DBG(("%s: size=%dx%d, promoting reused (%d) CPU bo due to TLB miss (%dx%d, pitch=%d)\n", 37903b705cfSriastradh __FUNCTION__, w, h, priv->source_count, 38003b705cfSriastradh pixmap->drawable.width, 38103b705cfSriastradh pixmap->drawable.height, 38203b705cfSriastradh priv->cpu_bo->pitch)); 38303b705cfSriastradh return NULL; 38403b705cfSriastradh } 38503b705cfSriastradh 38603b705cfSriastradh if (priv->gpu_bo) 38703b705cfSriastradh want_tiling = priv->gpu_bo->tiling != I915_TILING_NONE; 38803b705cfSriastradh else 38903b705cfSriastradh want_tiling = kgem_choose_tiling(&sna->kgem, 39003b705cfSriastradh I915_TILING_Y, 39103b705cfSriastradh pixmap->drawable.width, 39203b705cfSriastradh pixmap->drawable.height, 39303b705cfSriastradh pixmap->drawable.bitsPerPixel) != I915_TILING_NONE; 39403b705cfSriastradh if (want_tiling && 39503b705cfSriastradh priv->source_count*w*h >= (int)pixmap->drawable.width * pixmap->drawable.height) { 39603b705cfSriastradh DBG(("%s: pitch (%d) requires tiling\n", 39703b705cfSriastradh __FUNCTION__, priv->cpu_bo->pitch)); 39803b705cfSriastradh return NULL; 39903b705cfSriastradh } 40003b705cfSriastradh } 40103b705cfSriastradh } 40203b705cfSriastradh 40303b705cfSriastradh if (priv->shm) { 40403b705cfSriastradh assert(!priv->flush); 40503b705cfSriastradh sna_add_flush_pixmap(sna, priv, priv->cpu_bo); 40603b705cfSriastradh } 40703b705cfSriastradh 40803b705cfSriastradh DBG(("%s for box=(%d, %d), (%d, %d)\n", 40903b705cfSriastradh __FUNCTION__, box->x1, box->y1, box->x2, box->y2)); 41003b705cfSriastradh ++priv->source_count; 41103b705cfSriastradh return priv->cpu_bo; 41203b705cfSriastradh} 41303b705cfSriastradh 41403b705cfSriastradhstatic struct kgem_bo * 41503b705cfSriastradhmove_to_gpu(PixmapPtr pixmap, const BoxRec *box, bool blt) 41603b705cfSriastradh{ 41703b705cfSriastradh struct sna_pixmap *priv; 41803b705cfSriastradh int count, w, h; 41903b705cfSriastradh bool migrate = false; 42003b705cfSriastradh 42103b705cfSriastradh if (DBG_FORCE_UPLOAD > 0) 42203b705cfSriastradh return NULL; 42303b705cfSriastradh 42403b705cfSriastradh priv = sna_pixmap(pixmap); 42503b705cfSriastradh if (priv == NULL) { 42603b705cfSriastradh DBG(("%s: not migrating unattached pixmap\n", 42703b705cfSriastradh __FUNCTION__)); 42803b705cfSriastradh return NULL; 42903b705cfSriastradh } 43003b705cfSriastradh 43103b705cfSriastradh if (priv->shm) 43203b705cfSriastradh blt = true; 43303b705cfSriastradh 43403b705cfSriastradh if (priv->gpu_bo) { 43503b705cfSriastradh if (priv->cpu_damage && 43603b705cfSriastradh sna_damage_contains_box(priv->cpu_damage, 43703b705cfSriastradh box) != PIXMAN_REGION_OUT) 43803b705cfSriastradh goto upload; 43903b705cfSriastradh 44003b705cfSriastradh return priv->gpu_bo; 44103b705cfSriastradh } 44203b705cfSriastradh 44303b705cfSriastradh if (priv->cpu_damage == NULL) { 44403b705cfSriastradh DBG(("%s: not migrating uninitialised pixmap\n", 44503b705cfSriastradh __FUNCTION__)); 44603b705cfSriastradh return NULL; 44703b705cfSriastradh } 44803b705cfSriastradh 44903b705cfSriastradh if (pixmap->usage_hint) { 45003b705cfSriastradh DBG(("%s: not migrating pixmap due to usage_hint=%d\n", 45103b705cfSriastradh __FUNCTION__, pixmap->usage_hint)); 45203b705cfSriastradh return NULL; 45303b705cfSriastradh } 45403b705cfSriastradh 45503b705cfSriastradh if (DBG_FORCE_UPLOAD < 0) { 45603b705cfSriastradh if (!sna_pixmap_force_to_gpu(pixmap, 45703b705cfSriastradh blt ? MOVE_READ : MOVE_SOURCE_HINT | MOVE_READ)) 45803b705cfSriastradh return NULL; 45903b705cfSriastradh 46003b705cfSriastradh return priv->gpu_bo; 46103b705cfSriastradh } 46203b705cfSriastradh 46303b705cfSriastradh w = box->x2 - box->x1; 46403b705cfSriastradh h = box->y2 - box->y1; 46503b705cfSriastradh if (priv->cpu_bo && !priv->cpu_bo->flush) { 46603b705cfSriastradh migrate = true; 46703b705cfSriastradh } else if (w == pixmap->drawable.width && h == pixmap->drawable.height) { 46803b705cfSriastradh migrate = priv->source_count++ > SOURCE_BIAS; 46903b705cfSriastradh 47003b705cfSriastradh DBG(("%s: migrating whole pixmap (%dx%d) for source (%d,%d),(%d,%d), count %d? %d\n", 47103b705cfSriastradh __FUNCTION__, 47203b705cfSriastradh pixmap->drawable.width, pixmap->drawable.height, 47303b705cfSriastradh box->x1, box->y1, box->x2, box->y2, priv->source_count, 47403b705cfSriastradh migrate)); 47503b705cfSriastradh } else if (kgem_choose_tiling(&to_sna_from_pixmap(pixmap)->kgem, 47603b705cfSriastradh blt ? I915_TILING_X : I915_TILING_Y, w, h, 47703b705cfSriastradh pixmap->drawable.bitsPerPixel) != I915_TILING_NONE) { 47803b705cfSriastradh count = priv->source_count++; 47903b705cfSriastradh if ((priv->create & KGEM_CAN_CREATE_GPU) == 0) 48003b705cfSriastradh count -= SOURCE_BIAS; 48103b705cfSriastradh 48203b705cfSriastradh DBG(("%s: migrate box (%d, %d), (%d, %d)? source count=%d, fraction=%d/%d [%d]\n", 48303b705cfSriastradh __FUNCTION__, 48403b705cfSriastradh box->x1, box->y1, box->x2, box->y2, 48503b705cfSriastradh count, w*h, 48603b705cfSriastradh pixmap->drawable.width * pixmap->drawable.height, 48703b705cfSriastradh pixmap->drawable.width * pixmap->drawable.height / (w*h))); 48803b705cfSriastradh 48903b705cfSriastradh migrate = count*w*h > pixmap->drawable.width * pixmap->drawable.height; 49003b705cfSriastradh } 49103b705cfSriastradh 49203b705cfSriastradh if (!migrate) 49303b705cfSriastradh return NULL; 49403b705cfSriastradh 49503b705cfSriastradhupload: 49603b705cfSriastradh if (blt) { 49703b705cfSriastradh if (!sna_pixmap_move_area_to_gpu(pixmap, box, 49803b705cfSriastradh __MOVE_FORCE | MOVE_READ)) 49903b705cfSriastradh return NULL; 50003b705cfSriastradh } else { 50103b705cfSriastradh if (!sna_pixmap_move_to_gpu(pixmap, 50203b705cfSriastradh __MOVE_FORCE | MOVE_SOURCE_HINT | MOVE_READ)) 50303b705cfSriastradh return NULL; 50403b705cfSriastradh } 50503b705cfSriastradh 50603b705cfSriastradh return priv->gpu_bo; 50703b705cfSriastradh} 50803b705cfSriastradh 50903b705cfSriastradhstatic struct kgem_bo *upload(struct sna *sna, 51003b705cfSriastradh struct sna_composite_channel *channel, 51103b705cfSriastradh PixmapPtr pixmap, 51203b705cfSriastradh const BoxRec *box) 51303b705cfSriastradh{ 51403b705cfSriastradh struct sna_pixmap *priv; 51503b705cfSriastradh struct kgem_bo *bo; 51603b705cfSriastradh 51703b705cfSriastradh DBG(("%s: box=(%d, %d), (%d, %d), pixmap=%dx%d\n", 51803b705cfSriastradh __FUNCTION__, box->x1, box->y1, box->x2, box->y2, pixmap->drawable.width, pixmap->drawable.height)); 51903b705cfSriastradh assert(box->x1 >= 0); 52003b705cfSriastradh assert(box->y1 >= 0); 52103b705cfSriastradh assert(box->x2 <= pixmap->drawable.width); 52203b705cfSriastradh assert(box->y2 <= pixmap->drawable.height); 52303b705cfSriastradh 52403b705cfSriastradh priv = sna_pixmap(pixmap); 52503b705cfSriastradh if (priv) { 52603b705cfSriastradh RegionRec region; 52703b705cfSriastradh 52803b705cfSriastradh if (priv->cpu_damage == NULL) 52903b705cfSriastradh return NULL; /* uninitialised */ 53003b705cfSriastradh 53103b705cfSriastradh region.extents = *box; 53203b705cfSriastradh region.data = NULL; 53303b705cfSriastradh if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, 53403b705cfSriastradh ®ion, MOVE_READ)) 53503b705cfSriastradh return NULL; 53603b705cfSriastradh 53703b705cfSriastradh assert(!priv->mapped); 53803b705cfSriastradh if (pixmap->devPrivate.ptr == NULL) 53903b705cfSriastradh return NULL; /* uninitialised */ 54003b705cfSriastradh } 54103b705cfSriastradh 54203b705cfSriastradh bo = kgem_upload_source_image(&sna->kgem, 54303b705cfSriastradh pixmap->devPrivate.ptr, box, 54403b705cfSriastradh pixmap->devKind, 54503b705cfSriastradh pixmap->drawable.bitsPerPixel); 54603b705cfSriastradh if (channel && bo) { 54703b705cfSriastradh channel->width = box->x2 - box->x1; 54803b705cfSriastradh channel->height = box->y2 - box->y1; 54903b705cfSriastradh channel->offset[0] -= box->x1; 55003b705cfSriastradh channel->offset[1] -= box->y1; 55103b705cfSriastradh 55203b705cfSriastradh if (priv && 55303b705cfSriastradh pixmap->usage_hint == 0 && 55403b705cfSriastradh channel->width == pixmap->drawable.width && 55503b705cfSriastradh channel->height == pixmap->drawable.height) { 55603b705cfSriastradh DBG(("%s: adding upload cache to pixmap=%ld\n", 55703b705cfSriastradh __FUNCTION__, pixmap->drawable.serialNumber)); 55803b705cfSriastradh assert(priv->gpu_damage == NULL); 55903b705cfSriastradh assert(priv->gpu_bo == NULL); 56003b705cfSriastradh assert(bo->proxy != NULL); 56103b705cfSriastradh kgem_proxy_bo_attach(bo, &priv->gpu_bo); 56203b705cfSriastradh } 56303b705cfSriastradh } 56403b705cfSriastradh 56503b705cfSriastradh return bo; 56603b705cfSriastradh} 56703b705cfSriastradh 56803b705cfSriastradhstruct kgem_bo * 56903b705cfSriastradh__sna_render_pixmap_bo(struct sna *sna, 57003b705cfSriastradh PixmapPtr pixmap, 57103b705cfSriastradh const BoxRec *box, 57203b705cfSriastradh bool blt) 57303b705cfSriastradh{ 57403b705cfSriastradh struct kgem_bo *bo; 57503b705cfSriastradh 57603b705cfSriastradh bo = use_cpu_bo(sna, pixmap, box, blt); 57703b705cfSriastradh if (bo == NULL) { 57803b705cfSriastradh bo = move_to_gpu(pixmap, box, blt); 57903b705cfSriastradh if (bo == NULL) 58003b705cfSriastradh return NULL; 58103b705cfSriastradh } 58203b705cfSriastradh 58303b705cfSriastradh return bo; 58403b705cfSriastradh} 58503b705cfSriastradh 58603b705cfSriastradhint 58703b705cfSriastradhsna_render_pixmap_bo(struct sna *sna, 58803b705cfSriastradh struct sna_composite_channel *channel, 58903b705cfSriastradh PixmapPtr pixmap, 59003b705cfSriastradh int16_t x, int16_t y, 59103b705cfSriastradh int16_t w, int16_t h, 59203b705cfSriastradh int16_t dst_x, int16_t dst_y) 59303b705cfSriastradh{ 59403b705cfSriastradh struct sna_pixmap *priv; 59503b705cfSriastradh BoxRec box; 59603b705cfSriastradh 59703b705cfSriastradh DBG(("%s pixmap=%ld, (%d, %d)x(%d, %d)/(%d, %d)\n", 59803b705cfSriastradh __FUNCTION__, pixmap->drawable.serialNumber, 59903b705cfSriastradh x, y, w,h, pixmap->drawable.width, pixmap->drawable.height)); 60003b705cfSriastradh 60103b705cfSriastradh channel->width = pixmap->drawable.width; 60203b705cfSriastradh channel->height = pixmap->drawable.height; 60303b705cfSriastradh channel->offset[0] = x - dst_x; 60403b705cfSriastradh channel->offset[1] = y - dst_y; 60503b705cfSriastradh 60603b705cfSriastradh priv = sna_pixmap(pixmap); 60703b705cfSriastradh if (priv) { 60803b705cfSriastradh if (priv->gpu_bo && 60903b705cfSriastradh (DAMAGE_IS_ALL(priv->gpu_damage) || !priv->cpu_damage || 61003b705cfSriastradh priv->gpu_bo->proxy)) { 61103b705cfSriastradh DBG(("%s: GPU all damaged\n", __FUNCTION__)); 61203b705cfSriastradh channel->bo = priv->gpu_bo; 61303b705cfSriastradh goto done; 61403b705cfSriastradh } 61503b705cfSriastradh 61603b705cfSriastradh if (priv->cpu_bo && 61703b705cfSriastradh (DAMAGE_IS_ALL(priv->cpu_damage) || !priv->gpu_damage) && 61803b705cfSriastradh !priv->cpu_bo->snoop && priv->cpu_bo->pitch < 4096) { 61903b705cfSriastradh DBG(("%s: CPU all damaged\n", __FUNCTION__)); 62003b705cfSriastradh channel->bo = priv->cpu_bo; 62103b705cfSriastradh if (priv->shm) { 62203b705cfSriastradh assert(!priv->flush); 62303b705cfSriastradh sna_add_flush_pixmap(sna, priv, priv->cpu_bo); 62403b705cfSriastradh } 62503b705cfSriastradh goto done; 62603b705cfSriastradh } 62703b705cfSriastradh } 62803b705cfSriastradh 62903b705cfSriastradh /* XXX handle transformed repeat */ 63003b705cfSriastradh if (w == 0 || h == 0 || channel->transform) { 63103b705cfSriastradh box.x1 = box.y1 = 0; 63203b705cfSriastradh box.x2 = pixmap->drawable.width; 63303b705cfSriastradh box.y2 = pixmap->drawable.height; 63403b705cfSriastradh } else { 63503b705cfSriastradh box.x1 = x; 63603b705cfSriastradh box.y1 = y; 63703b705cfSriastradh box.x2 = bound(x, w); 63803b705cfSriastradh box.y2 = bound(y, h); 63903b705cfSriastradh 64003b705cfSriastradh if (channel->repeat == RepeatNone || channel->repeat == RepeatPad) { 64103b705cfSriastradh if (box.x1 < 0) 64203b705cfSriastradh box.x1 = 0; 64303b705cfSriastradh if (box.y1 < 0) 64403b705cfSriastradh box.y1 = 0; 64503b705cfSriastradh if (box.x2 > pixmap->drawable.width) 64603b705cfSriastradh box.x2 = pixmap->drawable.width; 64703b705cfSriastradh if (box.y2 > pixmap->drawable.height) 64803b705cfSriastradh box.y2 = pixmap->drawable.height; 64903b705cfSriastradh } else { 65003b705cfSriastradh if (box.x1 < 0 || box.x2 > pixmap->drawable.width) 65103b705cfSriastradh box.x1 = 0, box.x2 = pixmap->drawable.width; 65203b705cfSriastradh if (box.y1 < 0 || box.y2 > pixmap->drawable.height) 65303b705cfSriastradh box.y1 = 0, box.y2 = pixmap->drawable.height; 65403b705cfSriastradh } 65503b705cfSriastradh } 65603b705cfSriastradh 65703b705cfSriastradh w = box.x2 - box.x1; 65803b705cfSriastradh h = box.y2 - box.y1; 65903b705cfSriastradh DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d)\n", __FUNCTION__, 66003b705cfSriastradh box.x1, box.y1, box.x2, box.y2, w, h, 66103b705cfSriastradh pixmap->drawable.width, pixmap->drawable.height)); 66203b705cfSriastradh if (w <= 0 || h <= 0) { 66303b705cfSriastradh DBG(("%s: sample extents outside of texture -> clear\n", 66403b705cfSriastradh __FUNCTION__)); 66503b705cfSriastradh return 0; 66603b705cfSriastradh } 66703b705cfSriastradh 66803b705cfSriastradh DBG(("%s: offset=(%d, %d), size=(%d, %d)\n", 66903b705cfSriastradh __FUNCTION__, 67003b705cfSriastradh channel->offset[0], channel->offset[1], 67103b705cfSriastradh pixmap->drawable.width, pixmap->drawable.height)); 67203b705cfSriastradh 67303b705cfSriastradh channel->bo = __sna_render_pixmap_bo(sna, pixmap, &box, false); 67403b705cfSriastradh if (channel->bo == NULL) { 67503b705cfSriastradh DBG(("%s: uploading CPU box (%d, %d), (%d, %d)\n", 67603b705cfSriastradh __FUNCTION__, box.x1, box.y1, box.x2, box.y2)); 67703b705cfSriastradh channel->bo = upload(sna, channel, pixmap, &box); 67803b705cfSriastradh if (channel->bo == NULL) 67903b705cfSriastradh return 0; 68003b705cfSriastradh } else { 68103b705cfSriastradhdone: 68203b705cfSriastradh kgem_bo_reference(channel->bo); 68303b705cfSriastradh } 68403b705cfSriastradh 68503b705cfSriastradh channel->scale[0] = 1.f / channel->width; 68603b705cfSriastradh channel->scale[1] = 1.f / channel->height; 68703b705cfSriastradh return 1; 68803b705cfSriastradh} 68903b705cfSriastradh 69003b705cfSriastradhstatic int sna_render_picture_downsample(struct sna *sna, 69103b705cfSriastradh PicturePtr picture, 69203b705cfSriastradh struct sna_composite_channel *channel, 69303b705cfSriastradh const int16_t x, const int16_t y, 69403b705cfSriastradh const int16_t w, const int16_t h, 69503b705cfSriastradh const int16_t dst_x, const int16_t dst_y) 69603b705cfSriastradh{ 69703b705cfSriastradh PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable); 69803b705cfSriastradh ScreenPtr screen = pixmap->drawable.pScreen; 69903b705cfSriastradh PicturePtr tmp_src, tmp_dst; 70003b705cfSriastradh PictFormatPtr format; 70103b705cfSriastradh struct sna_pixmap *priv; 70203b705cfSriastradh pixman_transform_t t; 70303b705cfSriastradh PixmapPtr tmp; 70403b705cfSriastradh int width, height, size; 70503b705cfSriastradh int sx, sy, sw, sh; 70603b705cfSriastradh int error, ret = 0; 70703b705cfSriastradh BoxRec box, b; 70803b705cfSriastradh 70903b705cfSriastradh box.x1 = x; 71003b705cfSriastradh box.y1 = y; 71103b705cfSriastradh box.x2 = bound(x, w); 71203b705cfSriastradh box.y2 = bound(y, h); 71303b705cfSriastradh if (channel->transform) { 71403b705cfSriastradh pixman_vector_t v; 71503b705cfSriastradh 71603b705cfSriastradh pixman_transform_bounds(channel->transform, &box); 71703b705cfSriastradh 71803b705cfSriastradh v.vector[0] = x << 16; 71903b705cfSriastradh v.vector[1] = y << 16; 72003b705cfSriastradh v.vector[2] = 1 << 16; 72103b705cfSriastradh pixman_transform_point(channel->transform, &v); 72203b705cfSriastradh } 72303b705cfSriastradh 72403b705cfSriastradh if (channel->repeat == RepeatNone || channel->repeat == RepeatPad) { 72503b705cfSriastradh if (box.x1 < 0) 72603b705cfSriastradh box.x1 = 0; 72703b705cfSriastradh if (box.y1 < 0) 72803b705cfSriastradh box.y1 = 0; 72903b705cfSriastradh if (box.x2 > pixmap->drawable.width) 73003b705cfSriastradh box.x2 = pixmap->drawable.width; 73103b705cfSriastradh if (box.y2 > pixmap->drawable.height) 73203b705cfSriastradh box.y2 = pixmap->drawable.height; 73303b705cfSriastradh } else { 73403b705cfSriastradh /* XXX tiled repeats? */ 73503b705cfSriastradh if (box.x1 < 0 || box.x2 > pixmap->drawable.width) 73603b705cfSriastradh box.x1 = 0, box.x2 = pixmap->drawable.width; 73703b705cfSriastradh if (box.y1 < 0 || box.y2 > pixmap->drawable.height) 73803b705cfSriastradh box.y1 = 0, box.y2 = pixmap->drawable.height; 73903b705cfSriastradh 74003b705cfSriastradh } 74103b705cfSriastradh 74203b705cfSriastradh sw = box.x2 - box.x1; 74303b705cfSriastradh sh = box.y2 - box.y1; 74403b705cfSriastradh 74503b705cfSriastradh DBG(("%s: sample (%d, %d), (%d, %d)\n", 74603b705cfSriastradh __FUNCTION__, box.x1, box.y1, box.x2, box.y2)); 74703b705cfSriastradh 74803b705cfSriastradh sx = (sw + sna->render.max_3d_size - 1) / sna->render.max_3d_size; 74903b705cfSriastradh sy = (sh + sna->render.max_3d_size - 1) / sna->render.max_3d_size; 75003b705cfSriastradh 75103b705cfSriastradh DBG(("%s: scaling (%d, %d) down by %dx%d\n", 75203b705cfSriastradh __FUNCTION__, sw, sh, sx, sy)); 75303b705cfSriastradh 75403b705cfSriastradh width = sw / sx; 75503b705cfSriastradh height = sh / sy; 75603b705cfSriastradh 75703b705cfSriastradh DBG(("%s: creating temporary GPU bo %dx%d\n", 75803b705cfSriastradh __FUNCTION__, width, height)); 75903b705cfSriastradh 76003b705cfSriastradh if (!sna_pixmap_force_to_gpu(pixmap, MOVE_SOURCE_HINT | MOVE_READ)) 76103b705cfSriastradh return sna_render_picture_fixup(sna, picture, channel, 76203b705cfSriastradh x, y, w, h, 76303b705cfSriastradh dst_x, dst_y); 76403b705cfSriastradh 76503b705cfSriastradh tmp = screen->CreatePixmap(screen, 76603b705cfSriastradh width, height, 76703b705cfSriastradh pixmap->drawable.depth, 76803b705cfSriastradh SNA_CREATE_SCRATCH); 76903b705cfSriastradh if (!tmp) 77003b705cfSriastradh return 0; 77103b705cfSriastradh 77203b705cfSriastradh priv = sna_pixmap(tmp); 77303b705cfSriastradh if (!priv) 77403b705cfSriastradh goto cleanup_tmp; 77503b705cfSriastradh 77603b705cfSriastradh format = PictureMatchFormat(screen, 77703b705cfSriastradh pixmap->drawable.depth, 77803b705cfSriastradh picture->format); 77903b705cfSriastradh 78003b705cfSriastradh tmp_dst = CreatePicture(0, &tmp->drawable, format, 0, NULL, 78103b705cfSriastradh serverClient, &error); 78203b705cfSriastradh if (!tmp_dst) 78303b705cfSriastradh goto cleanup_tmp; 78403b705cfSriastradh 78503b705cfSriastradh tmp_src = CreatePicture(0, &pixmap->drawable, format, 0, NULL, 78603b705cfSriastradh serverClient, &error); 78703b705cfSriastradh if (!tmp_src) 78803b705cfSriastradh goto cleanup_dst; 78903b705cfSriastradh 79003b705cfSriastradh tmp_src->repeat = 1; 79103b705cfSriastradh tmp_src->repeatType = RepeatPad; 79203b705cfSriastradh /* Prefer to use nearest as it helps reduce artefacts from 79303b705cfSriastradh * interpolating and filtering twice. 79403b705cfSriastradh */ 79503b705cfSriastradh tmp_src->filter = PictFilterNearest; 79603b705cfSriastradh memset(&t, 0, sizeof(t)); 79703b705cfSriastradh t.matrix[0][0] = (sw << 16) / width; 79803b705cfSriastradh t.matrix[0][2] = box.x1 << 16; 79903b705cfSriastradh t.matrix[1][1] = (sh << 16) / height; 80003b705cfSriastradh t.matrix[1][2] = box.y1 << 16; 80103b705cfSriastradh t.matrix[2][2] = 1 << 16; 80203b705cfSriastradh tmp_src->transform = &t; 80303b705cfSriastradh 80403b705cfSriastradh ValidatePicture(tmp_dst); 80503b705cfSriastradh ValidatePicture(tmp_src); 80603b705cfSriastradh 80703b705cfSriastradh /* Use a small size to accommodate enlargement through tile alignment */ 80803b705cfSriastradh size = sna->render.max_3d_size - 4096 / pixmap->drawable.bitsPerPixel; 80903b705cfSriastradh while (size * size * 4 > sna->kgem.max_copy_tile_size) 81003b705cfSriastradh size /= 2; 81103b705cfSriastradh 81203b705cfSriastradh sw = size / sx - 2 * sx; 81303b705cfSriastradh sh = size / sy - 2 * sy; 81403b705cfSriastradh DBG(("%s %d:%d downsampling using %dx%d GPU tiles\n", 81503b705cfSriastradh __FUNCTION__, (width + sw-1)/sw, (height + sh-1)/sh, sw, sh)); 81603b705cfSriastradh 81703b705cfSriastradh for (b.y1 = 0; b.y1 < height; b.y1 = b.y2) { 81803b705cfSriastradh b.y2 = b.y1 + sh; 81903b705cfSriastradh if (b.y2 > height) 82003b705cfSriastradh b.y2 = height; 82103b705cfSriastradh 82203b705cfSriastradh for (b.x1 = 0; b.x1 < width; b.x1 = b.x2) { 82303b705cfSriastradh struct sna_composite_op op; 82403b705cfSriastradh 82503b705cfSriastradh b.x2 = b.x1 + sw; 82603b705cfSriastradh if (b.x2 > width) 82703b705cfSriastradh b.x2 = width; 82803b705cfSriastradh 82903b705cfSriastradh DBG(("%s: tile (%d, %d), (%d, %d)\n", 83003b705cfSriastradh __FUNCTION__, b.x1, b.y1, b.x2, b.y2)); 83103b705cfSriastradh 83203b705cfSriastradh memset(&op, 0, sizeof(op)); 83303b705cfSriastradh if (!sna->render.composite(sna, 83403b705cfSriastradh PictOpSrc, 83503b705cfSriastradh tmp_src, NULL, tmp_dst, 83603b705cfSriastradh b.x1, b.y1, 83703b705cfSriastradh 0, 0, 83803b705cfSriastradh b.x1, b.y1, 83903b705cfSriastradh b.x2 - b.x1, b.y2 - b.y1, 84003b705cfSriastradh &op)) 84103b705cfSriastradh goto cleanup_src; 84203b705cfSriastradh 84303b705cfSriastradh op.box(sna, &op, &b); 84403b705cfSriastradh op.done(sna, &op); 84503b705cfSriastradh } 84603b705cfSriastradh } 84703b705cfSriastradh 84803b705cfSriastradh pixman_transform_invert(&channel->embedded_transform, &t); 84903b705cfSriastradh if (channel->transform) 85003b705cfSriastradh pixman_transform_multiply(&channel->embedded_transform, 85103b705cfSriastradh &channel->embedded_transform, 85203b705cfSriastradh channel->transform); 85303b705cfSriastradh channel->transform = &channel->embedded_transform; 85403b705cfSriastradh 85503b705cfSriastradh channel->offset[0] = x - dst_x; 85603b705cfSriastradh channel->offset[1] = y - dst_y; 85703b705cfSriastradh channel->scale[0] = 1.f/width; 85803b705cfSriastradh channel->scale[1] = 1.f/height; 85903b705cfSriastradh channel->width = width; 86003b705cfSriastradh channel->height = height; 86103b705cfSriastradh channel->bo = kgem_bo_reference(priv->gpu_bo); 86203b705cfSriastradh 86303b705cfSriastradh ret = 1; 86403b705cfSriastradhcleanup_src: 86503b705cfSriastradh tmp_src->transform = NULL; 86603b705cfSriastradh FreePicture(tmp_src, 0); 86703b705cfSriastradhcleanup_dst: 86803b705cfSriastradh FreePicture(tmp_dst, 0); 86903b705cfSriastradhcleanup_tmp: 87003b705cfSriastradh screen->DestroyPixmap(tmp); 87103b705cfSriastradh return ret; 87203b705cfSriastradh} 87303b705cfSriastradh 87403b705cfSriastradhbool 87503b705cfSriastradhsna_render_pixmap_partial(struct sna *sna, 87603b705cfSriastradh PixmapPtr pixmap, 87703b705cfSriastradh struct kgem_bo *bo, 87803b705cfSriastradh struct sna_composite_channel *channel, 87903b705cfSriastradh int16_t x, int16_t y, 88003b705cfSriastradh int16_t w, int16_t h) 88103b705cfSriastradh{ 88203b705cfSriastradh BoxRec box; 88303b705cfSriastradh int offset; 88403b705cfSriastradh 88503b705cfSriastradh DBG(("%s (%d, %d)x(%d, %d), pitch %d, max %d\n", 88603b705cfSriastradh __FUNCTION__, x, y, w, h, bo->pitch, sna->render.max_3d_pitch)); 88703b705cfSriastradh 88803b705cfSriastradh if (bo->pitch > sna->render.max_3d_pitch) 88903b705cfSriastradh return false; 89003b705cfSriastradh 89103b705cfSriastradh box.x1 = x; 89203b705cfSriastradh box.y1 = y; 89303b705cfSriastradh box.x2 = bound(x, w); 89403b705cfSriastradh box.y2 = bound(y, h); 89503b705cfSriastradh DBG(("%s: unaligned box (%d, %d), (%d, %d)\n", 89603b705cfSriastradh __FUNCTION__, box.x1, box.y1, box.x2, box.y2)); 89703b705cfSriastradh 89803b705cfSriastradh if (box.x1 < 0) 89903b705cfSriastradh box.x1 = 0; 90003b705cfSriastradh if (box.y1 < 0) 90103b705cfSriastradh box.y1 = 0; 90203b705cfSriastradh 90303b705cfSriastradh if (bo->tiling) { 90403b705cfSriastradh int tile_width, tile_height, tile_size; 90503b705cfSriastradh 90603b705cfSriastradh kgem_get_tile_size(&sna->kgem, bo->tiling, 90703b705cfSriastradh &tile_width, &tile_height, &tile_size); 90803b705cfSriastradh DBG(("%s: tile size for tiling %d: %dx%d, size=%d\n", 90903b705cfSriastradh __FUNCTION__, bo->tiling, tile_width, tile_height, tile_size)); 91003b705cfSriastradh 91103b705cfSriastradh if (sna->kgem.gen < 033) 91203b705cfSriastradh tile_width = bo->pitch; 91303b705cfSriastradh 91403b705cfSriastradh /* Ensure we align to an even tile row */ 91503b705cfSriastradh box.y1 = box.y1 & ~(2*tile_height - 1); 91603b705cfSriastradh box.y2 = ALIGN(box.y2, 2*tile_height); 91703b705cfSriastradh 91803b705cfSriastradh assert(tile_width * 8 >= pixmap->drawable.bitsPerPixel); 91903b705cfSriastradh box.x1 = box.x1 & ~(tile_width * 8 / pixmap->drawable.bitsPerPixel - 1); 92003b705cfSriastradh box.x2 = ALIGN(box.x2, tile_width * 8 / pixmap->drawable.bitsPerPixel); 92103b705cfSriastradh 92203b705cfSriastradh offset = box.x1 * pixmap->drawable.bitsPerPixel / 8 / tile_width * tile_size; 92303b705cfSriastradh } else { 92403b705cfSriastradh box.y1 = box.y1 & ~1; 92503b705cfSriastradh box.y2 = ALIGN(box.y2, 2); 92603b705cfSriastradh 92703b705cfSriastradh box.x1 = box.x1 & ~1; 92803b705cfSriastradh box.x2 = ALIGN(box.x2, 2); 92903b705cfSriastradh 93003b705cfSriastradh offset = box.x1 * pixmap->drawable.bitsPerPixel / 8; 93103b705cfSriastradh } 93203b705cfSriastradh 93303b705cfSriastradh if (box.x2 > pixmap->drawable.width) 93403b705cfSriastradh box.x2 = pixmap->drawable.width; 93503b705cfSriastradh if (box.y2 > pixmap->drawable.height) 93603b705cfSriastradh box.y2 = pixmap->drawable.height; 93703b705cfSriastradh 93803b705cfSriastradh w = box.x2 - box.x1; 93903b705cfSriastradh h = box.y2 - box.y1; 94003b705cfSriastradh DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d)\n", __FUNCTION__, 94103b705cfSriastradh box.x1, box.y1, box.x2, box.y2, w, h, 94203b705cfSriastradh pixmap->drawable.width, pixmap->drawable.height)); 94303b705cfSriastradh if (w <= 0 || h <= 0 || 94403b705cfSriastradh w > sna->render.max_3d_size || 94503b705cfSriastradh h > sna->render.max_3d_size) { 94603b705cfSriastradh DBG(("%s: box too large (%dx%d) for 3D pipeline (max %d)\n", 94703b705cfSriastradh __FUNCTION__, w, h, sna->render.max_3d_size)); 94803b705cfSriastradh return false; 94903b705cfSriastradh } 95003b705cfSriastradh 95103b705cfSriastradh /* How many tiles across are we? */ 95203b705cfSriastradh channel->bo = kgem_create_proxy(&sna->kgem, bo, 95303b705cfSriastradh box.y1 * bo->pitch + offset, 95403b705cfSriastradh h * bo->pitch); 95503b705cfSriastradh if (channel->bo == NULL) 95603b705cfSriastradh return false; 95703b705cfSriastradh 95803b705cfSriastradh channel->bo->pitch = bo->pitch; 95903b705cfSriastradh 96003b705cfSriastradh channel->offset[0] = -box.x1; 96103b705cfSriastradh channel->offset[1] = -box.y1; 96203b705cfSriastradh channel->scale[0] = 1.f/w; 96303b705cfSriastradh channel->scale[1] = 1.f/h; 96403b705cfSriastradh channel->width = w; 96503b705cfSriastradh channel->height = h; 96603b705cfSriastradh return true; 96703b705cfSriastradh} 96803b705cfSriastradh 96903b705cfSriastradhstatic int 97003b705cfSriastradhsna_render_picture_partial(struct sna *sna, 97103b705cfSriastradh PicturePtr picture, 97203b705cfSriastradh struct sna_composite_channel *channel, 97303b705cfSriastradh int16_t x, int16_t y, 97403b705cfSriastradh int16_t w, int16_t h, 97503b705cfSriastradh int16_t dst_x, int16_t dst_y) 97603b705cfSriastradh{ 97703b705cfSriastradh struct kgem_bo *bo = NULL; 97803b705cfSriastradh PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable); 97903b705cfSriastradh BoxRec box; 98003b705cfSriastradh int offset; 98103b705cfSriastradh 98203b705cfSriastradh DBG(("%s (%d, %d)x(%d, %d) [dst=(%d, %d)]\n", 98303b705cfSriastradh __FUNCTION__, x, y, w, h, dst_x, dst_y)); 98403b705cfSriastradh 98503b705cfSriastradh box.x1 = x; 98603b705cfSriastradh box.y1 = y; 98703b705cfSriastradh box.x2 = bound(x, w); 98803b705cfSriastradh box.y2 = bound(y, h); 98903b705cfSriastradh if (channel->transform) 99003b705cfSriastradh pixman_transform_bounds(channel->transform, &box); 99103b705cfSriastradh 99203b705cfSriastradh DBG(("%s sample=(%d, %d), (%d, %d): (%d, %d)/(%d, %d), repeat=%d\n", __FUNCTION__, 99303b705cfSriastradh box.x1, box.y1, box.x2, box.y2, w, h, 99403b705cfSriastradh pixmap->drawable.width, pixmap->drawable.height, 99503b705cfSriastradh channel->repeat)); 99603b705cfSriastradh 99703b705cfSriastradh if (channel->repeat == RepeatNone || channel->repeat == RepeatPad) { 99803b705cfSriastradh if (box.x1 < 0) 99903b705cfSriastradh box.x1 = 0; 100003b705cfSriastradh if (box.y1 < 0) 100103b705cfSriastradh box.y1 = 0; 100203b705cfSriastradh if (box.x2 > pixmap->drawable.width) 100303b705cfSriastradh box.x2 = pixmap->drawable.width; 100403b705cfSriastradh if (box.y2 > pixmap->drawable.height) 100503b705cfSriastradh box.y2 = pixmap->drawable.height; 100603b705cfSriastradh } else { 100703b705cfSriastradh if (box.x1 < 0 || box.x2 > pixmap->drawable.width) 100803b705cfSriastradh box.x1 = 0, box.x2 = pixmap->drawable.width; 100903b705cfSriastradh if (box.y1 < 0 || box.y2 > pixmap->drawable.height) 101003b705cfSriastradh box.y1 = 0, box.y2 = pixmap->drawable.height; 101103b705cfSriastradh } 101203b705cfSriastradh 101303b705cfSriastradh if (use_cpu_bo(sna, pixmap, &box, false)) { 101403b705cfSriastradh bo = sna_pixmap(pixmap)->cpu_bo; 101503b705cfSriastradh } else { 101603b705cfSriastradh struct sna_pixmap *priv; 101703b705cfSriastradh 101803b705cfSriastradh priv = sna_pixmap_force_to_gpu(pixmap, 101903b705cfSriastradh MOVE_READ | MOVE_SOURCE_HINT); 102003b705cfSriastradh if (priv == NULL) 102103b705cfSriastradh return 0; 102203b705cfSriastradh 102303b705cfSriastradh bo = priv->gpu_bo; 102403b705cfSriastradh } 102503b705cfSriastradh 102603b705cfSriastradh if (bo->pitch > sna->render.max_3d_pitch) 102703b705cfSriastradh return 0; 102803b705cfSriastradh 102903b705cfSriastradh if (bo->tiling) { 103003b705cfSriastradh int tile_width, tile_height, tile_size; 103103b705cfSriastradh 103203b705cfSriastradh kgem_get_tile_size(&sna->kgem, bo->tiling, 103303b705cfSriastradh &tile_width, &tile_height, &tile_size); 103403b705cfSriastradh 103503b705cfSriastradh DBG(("%s: tiling=%d, size=%dx%d, chunk=%d\n", 103603b705cfSriastradh __FUNCTION__, bo->tiling, 103703b705cfSriastradh tile_width, tile_height, tile_size)); 103803b705cfSriastradh 103903b705cfSriastradh /* Ensure we align to an even tile row */ 104003b705cfSriastradh box.y1 = box.y1 & ~(2*tile_height - 1); 104103b705cfSriastradh box.y2 = ALIGN(box.y2, 2*tile_height); 104203b705cfSriastradh if (box.y2 > pixmap->drawable.height) 104303b705cfSriastradh box.y2 = pixmap->drawable.height; 104403b705cfSriastradh 104503b705cfSriastradh box.x1 = box.x1 & ~(tile_width * 8 / pixmap->drawable.bitsPerPixel - 1); 104603b705cfSriastradh box.x2 = ALIGN(box.x2, tile_width * 8 / pixmap->drawable.bitsPerPixel); 104703b705cfSriastradh if (box.x2 > pixmap->drawable.width) 104803b705cfSriastradh box.x2 = pixmap->drawable.width; 104903b705cfSriastradh 105003b705cfSriastradh offset = box.x1 * pixmap->drawable.bitsPerPixel / 8 / tile_width * tile_size; 105103b705cfSriastradh } else 105203b705cfSriastradh offset = box.x1 * pixmap->drawable.bitsPerPixel / 8; 105303b705cfSriastradh 105403b705cfSriastradh w = box.x2 - box.x1; 105503b705cfSriastradh h = box.y2 - box.y1; 105603b705cfSriastradh DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d)\n", __FUNCTION__, 105703b705cfSriastradh box.x1, box.y1, box.x2, box.y2, w, h, 105803b705cfSriastradh pixmap->drawable.width, pixmap->drawable.height)); 105903b705cfSriastradh if (w <= 0 || h <= 0 || 106003b705cfSriastradh w > sna->render.max_3d_size || 106103b705cfSriastradh h > sna->render.max_3d_size) 106203b705cfSriastradh return 0; 106303b705cfSriastradh 106403b705cfSriastradh /* How many tiles across are we? */ 106503b705cfSriastradh channel->bo = kgem_create_proxy(&sna->kgem, bo, 106603b705cfSriastradh box.y1 * bo->pitch + offset, 106703b705cfSriastradh h * bo->pitch); 106803b705cfSriastradh if (channel->bo == NULL) 106903b705cfSriastradh return 0; 107003b705cfSriastradh 107103b705cfSriastradh if (channel->transform) { 107203b705cfSriastradh memset(&channel->embedded_transform, 107303b705cfSriastradh 0, 107403b705cfSriastradh sizeof(channel->embedded_transform)); 107503b705cfSriastradh channel->embedded_transform.matrix[0][0] = 1 << 16; 107603b705cfSriastradh channel->embedded_transform.matrix[0][2] = -box.x1 << 16; 107703b705cfSriastradh channel->embedded_transform.matrix[1][1] = 1 << 16; 107803b705cfSriastradh channel->embedded_transform.matrix[1][2] = -box.y1 << 16; 107903b705cfSriastradh channel->embedded_transform.matrix[2][2] = 1 << 16; 108003b705cfSriastradh pixman_transform_multiply(&channel->embedded_transform, 108103b705cfSriastradh &channel->embedded_transform, 108203b705cfSriastradh channel->transform); 108303b705cfSriastradh channel->transform = &channel->embedded_transform; 108403b705cfSriastradh } else { 108503b705cfSriastradh x -= box.x1; 108603b705cfSriastradh y -= box.y1; 108703b705cfSriastradh } 108803b705cfSriastradh 108903b705cfSriastradh channel->offset[0] = x - dst_x; 109003b705cfSriastradh channel->offset[1] = y - dst_y; 109103b705cfSriastradh channel->scale[0] = 1.f/w; 109203b705cfSriastradh channel->scale[1] = 1.f/h; 109303b705cfSriastradh channel->width = w; 109403b705cfSriastradh channel->height = h; 109503b705cfSriastradh return 1; 109603b705cfSriastradh} 109703b705cfSriastradh 109803b705cfSriastradhint 109903b705cfSriastradhsna_render_picture_extract(struct sna *sna, 110003b705cfSriastradh PicturePtr picture, 110103b705cfSriastradh struct sna_composite_channel *channel, 110203b705cfSriastradh int16_t x, int16_t y, 110303b705cfSriastradh int16_t w, int16_t h, 110403b705cfSriastradh int16_t dst_x, int16_t dst_y) 110503b705cfSriastradh{ 110603b705cfSriastradh struct kgem_bo *bo = NULL, *src_bo; 110703b705cfSriastradh PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable); 110803b705cfSriastradh int16_t ox, oy, ow, oh; 110903b705cfSriastradh BoxRec box; 111003b705cfSriastradh 111103b705cfSriastradh#if NO_EXTRACT 111203b705cfSriastradh return -1; 111303b705cfSriastradh#endif 111403b705cfSriastradh 111503b705cfSriastradh DBG(("%s (%d, %d)x(%d, %d) [dst=(%d, %d)]\n", 111603b705cfSriastradh __FUNCTION__, x, y, w, h, dst_x, dst_y)); 111703b705cfSriastradh 111803b705cfSriastradh if (w == 0 || h == 0) { 111903b705cfSriastradh DBG(("%s: fallback -- unknown bounds\n", __FUNCTION__)); 112003b705cfSriastradh return -1; 112103b705cfSriastradh } 112203b705cfSriastradh 112303b705cfSriastradh if (sna_render_picture_partial(sna, picture, channel, 112403b705cfSriastradh x, y, w, h, 112503b705cfSriastradh dst_x, dst_y)) 112603b705cfSriastradh return 1; 112703b705cfSriastradh 112803b705cfSriastradh ow = w; 112903b705cfSriastradh oh = h; 113003b705cfSriastradh 113103b705cfSriastradh ox = box.x1 = x; 113203b705cfSriastradh oy = box.y1 = y; 113303b705cfSriastradh box.x2 = bound(x, w); 113403b705cfSriastradh box.y2 = bound(y, h); 113503b705cfSriastradh if (channel->transform) { 113603b705cfSriastradh pixman_vector_t v; 113703b705cfSriastradh 113803b705cfSriastradh pixman_transform_bounds(channel->transform, &box); 113903b705cfSriastradh 114003b705cfSriastradh v.vector[0] = ox << 16; 114103b705cfSriastradh v.vector[1] = oy << 16; 114203b705cfSriastradh v.vector[2] = 1 << 16; 114303b705cfSriastradh pixman_transform_point(channel->transform, &v); 114403b705cfSriastradh ox = v.vector[0] / v.vector[2]; 114503b705cfSriastradh oy = v.vector[1] / v.vector[2]; 114603b705cfSriastradh } 114703b705cfSriastradh 114803b705cfSriastradh DBG(("%s sample=(%d, %d), (%d, %d): (%d, %d)/(%d, %d), repeat=%d\n", __FUNCTION__, 114903b705cfSriastradh box.x1, box.y1, box.x2, box.y2, w, h, 115003b705cfSriastradh pixmap->drawable.width, pixmap->drawable.height, 115103b705cfSriastradh channel->repeat)); 115203b705cfSriastradh 115303b705cfSriastradh if (channel->repeat == RepeatNone || channel->repeat == RepeatPad) { 115403b705cfSriastradh if (box.x1 < 0) 115503b705cfSriastradh box.x1 = 0; 115603b705cfSriastradh if (box.y1 < 0) 115703b705cfSriastradh box.y1 = 0; 115803b705cfSriastradh if (box.x2 > pixmap->drawable.width) 115903b705cfSriastradh box.x2 = pixmap->drawable.width; 116003b705cfSriastradh if (box.y2 > pixmap->drawable.height) 116103b705cfSriastradh box.y2 = pixmap->drawable.height; 116203b705cfSriastradh } else { 116303b705cfSriastradh /* XXX tiled repeats? */ 116403b705cfSriastradh if (box.x1 < 0 || box.x2 > pixmap->drawable.width) 116503b705cfSriastradh box.x1 = 0, box.x2 = pixmap->drawable.width; 116603b705cfSriastradh if (box.y1 < 0 || box.y2 > pixmap->drawable.height) 116703b705cfSriastradh box.y1 = 0, box.y2 = pixmap->drawable.height; 116803b705cfSriastradh } 116903b705cfSriastradh 117003b705cfSriastradh w = box.x2 - box.x1; 117103b705cfSriastradh h = box.y2 - box.y1; 117203b705cfSriastradh DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d)\n", __FUNCTION__, 117303b705cfSriastradh box.x1, box.y1, box.x2, box.y2, w, h, 117403b705cfSriastradh pixmap->drawable.width, pixmap->drawable.height)); 117503b705cfSriastradh if (w <= 0 || h <= 0) { 117603b705cfSriastradh DBG(("%s: sample extents outside of texture -> clear\n", 117703b705cfSriastradh __FUNCTION__)); 117803b705cfSriastradh return 0; 117903b705cfSriastradh } 118003b705cfSriastradh 118103b705cfSriastradh if (w > sna->render.max_3d_size || h > sna->render.max_3d_size) { 118203b705cfSriastradh DBG(("%s: fallback -- sample too large for texture (%d, %d)x(%d, %d)\n", 118303b705cfSriastradh __FUNCTION__, box.x1, box.y1, w, h)); 118403b705cfSriastradh return sna_render_picture_downsample(sna, picture, channel, 118503b705cfSriastradh x, y, ow, oh, 118603b705cfSriastradh dst_x, dst_y); 118703b705cfSriastradh } 118803b705cfSriastradh 118903b705cfSriastradh src_bo = use_cpu_bo(sna, pixmap, &box, true); 119003b705cfSriastradh if (src_bo == NULL) { 119103b705cfSriastradh src_bo = move_to_gpu(pixmap, &box, false); 119203b705cfSriastradh if (src_bo == NULL) { 119303b705cfSriastradh struct sna_pixmap *priv = sna_pixmap(pixmap); 119403b705cfSriastradh if (priv) { 119503b705cfSriastradh RegionRec region; 119603b705cfSriastradh 119703b705cfSriastradh region.extents = box; 119803b705cfSriastradh region.data = NULL; 119903b705cfSriastradh if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, 120003b705cfSriastradh ®ion, MOVE_READ)) 120103b705cfSriastradh return 0; 120203b705cfSriastradh 120303b705cfSriastradh assert(!priv->mapped); 120403b705cfSriastradh if (pixmap->devPrivate.ptr == NULL) 120503b705cfSriastradh return 0; /* uninitialised */ 120603b705cfSriastradh } 120703b705cfSriastradh 120803b705cfSriastradh bo = kgem_upload_source_image(&sna->kgem, 120903b705cfSriastradh pixmap->devPrivate.ptr, 121003b705cfSriastradh &box, 121103b705cfSriastradh pixmap->devKind, 121203b705cfSriastradh pixmap->drawable.bitsPerPixel); 121303b705cfSriastradh if (priv != NULL && bo != NULL && 121403b705cfSriastradh box.x2 - box.x1 == pixmap->drawable.width && 121503b705cfSriastradh box.y2 - box.y1 == pixmap->drawable.height) { 121603b705cfSriastradh DBG(("%s: adding upload cache to pixmap=%ld\n", 121703b705cfSriastradh __FUNCTION__, pixmap->drawable.serialNumber)); 121803b705cfSriastradh assert(priv->gpu_damage == NULL); 121903b705cfSriastradh assert(priv->gpu_bo == NULL); 122003b705cfSriastradh assert(bo->proxy != NULL); 122103b705cfSriastradh kgem_proxy_bo_attach(bo, &priv->gpu_bo); 122203b705cfSriastradh } 122303b705cfSriastradh } 122403b705cfSriastradh } 122503b705cfSriastradh if (src_bo) { 122603b705cfSriastradh bo = kgem_create_2d(&sna->kgem, w, h, 122703b705cfSriastradh pixmap->drawable.bitsPerPixel, 122803b705cfSriastradh kgem_choose_tiling(&sna->kgem, 122903b705cfSriastradh I915_TILING_X, w, h, 123003b705cfSriastradh pixmap->drawable.bitsPerPixel), 123103b705cfSriastradh CREATE_TEMPORARY); 123203b705cfSriastradh if (bo) { 123303b705cfSriastradh PixmapRec tmp; 123403b705cfSriastradh 123503b705cfSriastradh tmp.drawable.width = w; 123603b705cfSriastradh tmp.drawable.height = h; 123703b705cfSriastradh tmp.drawable.depth = pixmap->drawable.depth; 123803b705cfSriastradh tmp.drawable.bitsPerPixel = pixmap->drawable.bitsPerPixel; 123903b705cfSriastradh tmp.devPrivate.ptr = NULL; 124003b705cfSriastradh 124103b705cfSriastradh assert(tmp.drawable.width); 124203b705cfSriastradh assert(tmp.drawable.height); 124303b705cfSriastradh 124403b705cfSriastradh if (!sna->render.copy_boxes(sna, GXcopy, 124503b705cfSriastradh pixmap, src_bo, 0, 0, 124603b705cfSriastradh &tmp, bo, -box.x1, -box.y1, 124703b705cfSriastradh &box, 1, 0)) { 124803b705cfSriastradh kgem_bo_destroy(&sna->kgem, bo); 124903b705cfSriastradh bo = NULL; 125003b705cfSriastradh } 125103b705cfSriastradh } 125203b705cfSriastradh } 125303b705cfSriastradh 125403b705cfSriastradh if (bo == NULL) { 125503b705cfSriastradh DBG(("%s: falback -- pixmap is not on the GPU\n", 125603b705cfSriastradh __FUNCTION__)); 125703b705cfSriastradh return sna_render_picture_fixup(sna, picture, channel, 125803b705cfSriastradh x, y, ow, oh, dst_x, dst_y); 125903b705cfSriastradh } 126003b705cfSriastradh 126103b705cfSriastradh if (ox == x && oy == y) { 126203b705cfSriastradh x = y = 0; 126303b705cfSriastradh } else if (channel->transform) { 126403b705cfSriastradh pixman_vector_t v; 126503b705cfSriastradh pixman_transform_t m; 126603b705cfSriastradh 126703b705cfSriastradh v.vector[0] = (ox - box.x1) << 16; 126803b705cfSriastradh v.vector[1] = (oy - box.y1) << 16; 126903b705cfSriastradh v.vector[2] = 1 << 16; 127003b705cfSriastradh pixman_transform_invert(&m, channel->transform); 127103b705cfSriastradh pixman_transform_point(&m, &v); 127203b705cfSriastradh x = v.vector[0] / v.vector[2]; 127303b705cfSriastradh y = v.vector[1] / v.vector[2]; 127403b705cfSriastradh } else { 127503b705cfSriastradh x = ox - box.x1; 127603b705cfSriastradh y = oy - box.y1; 127703b705cfSriastradh } 127803b705cfSriastradh 127903b705cfSriastradh channel->offset[0] = x - dst_x; 128003b705cfSriastradh channel->offset[1] = y - dst_y; 128103b705cfSriastradh channel->scale[0] = 1.f/w; 128203b705cfSriastradh channel->scale[1] = 1.f/h; 128303b705cfSriastradh channel->width = w; 128403b705cfSriastradh channel->height = h; 128503b705cfSriastradh channel->bo = bo; 128603b705cfSriastradh return 1; 128703b705cfSriastradh} 128803b705cfSriastradh 128903b705cfSriastradhstatic int 129003b705cfSriastradhsna_render_picture_convolve(struct sna *sna, 129103b705cfSriastradh PicturePtr picture, 129203b705cfSriastradh struct sna_composite_channel *channel, 129303b705cfSriastradh int16_t x, int16_t y, 129403b705cfSriastradh int16_t w, int16_t h, 129503b705cfSriastradh int16_t dst_x, int16_t dst_y) 129603b705cfSriastradh{ 129703b705cfSriastradh ScreenPtr screen = picture->pDrawable->pScreen; 129803b705cfSriastradh PixmapPtr pixmap; 129903b705cfSriastradh PicturePtr tmp; 130003b705cfSriastradh pixman_fixed_t *params = picture->filter_params; 130103b705cfSriastradh int x_off = -pixman_fixed_to_int((params[0] - pixman_fixed_1) >> 1); 130203b705cfSriastradh int y_off = -pixman_fixed_to_int((params[1] - pixman_fixed_1) >> 1); 130303b705cfSriastradh int cw = pixman_fixed_to_int(params[0]); 130403b705cfSriastradh int ch = pixman_fixed_to_int(params[1]); 130503b705cfSriastradh int i, j, error, depth; 130603b705cfSriastradh struct kgem_bo *bo; 130703b705cfSriastradh 130803b705cfSriastradh /* Lame multi-pass accumulation implementation of a general convolution 130903b705cfSriastradh * that works everywhere. 131003b705cfSriastradh */ 131103b705cfSriastradh DBG(("%s: origin=(%d,%d) kernel=%dx%d, size=%dx%d\n", 131203b705cfSriastradh __FUNCTION__, x_off, y_off, cw, ch, w, h)); 131303b705cfSriastradh 131403b705cfSriastradh assert(picture->pDrawable); 131503b705cfSriastradh assert(picture->filter == PictFilterConvolution); 131603b705cfSriastradh assert(w <= sna->render.max_3d_size && h <= sna->render.max_3d_size); 131703b705cfSriastradh 131803b705cfSriastradh if (PICT_FORMAT_RGB(picture->format) == 0) { 131903b705cfSriastradh channel->pict_format = PIXMAN_a8; 132003b705cfSriastradh depth = 8; 132103b705cfSriastradh } else { 132203b705cfSriastradh channel->pict_format = PIXMAN_a8r8g8b8; 132303b705cfSriastradh depth = 32; 132403b705cfSriastradh } 132503b705cfSriastradh 132603b705cfSriastradh pixmap = screen->CreatePixmap(screen, w, h, depth, SNA_CREATE_SCRATCH); 132703b705cfSriastradh if (pixmap == NullPixmap) 132803b705cfSriastradh return 0; 132903b705cfSriastradh 133003b705cfSriastradh tmp = CreatePicture(0, &pixmap->drawable, 133103b705cfSriastradh PictureMatchFormat(screen, depth, channel->pict_format), 133203b705cfSriastradh 0, NULL, serverClient, &error); 133303b705cfSriastradh screen->DestroyPixmap(pixmap); 133403b705cfSriastradh if (tmp == NULL) 133503b705cfSriastradh return 0; 133603b705cfSriastradh 133703b705cfSriastradh ValidatePicture(tmp); 133803b705cfSriastradh 133903b705cfSriastradh bo = __sna_pixmap_get_bo(pixmap); 134003b705cfSriastradh if (!sna->render.clear(sna, pixmap, bo)) { 134103b705cfSriastradh FreePicture(tmp, 0); 134203b705cfSriastradh return 0; 134303b705cfSriastradh } 134403b705cfSriastradh 134503b705cfSriastradh picture->filter = PictFilterBilinear; 134603b705cfSriastradh params += 2; 134703b705cfSriastradh for (j = 0; j < ch; j++) { 134803b705cfSriastradh for (i = 0; i < cw; i++) { 134903b705cfSriastradh xRenderColor color; 135003b705cfSriastradh PicturePtr alpha; 135103b705cfSriastradh 135203b705cfSriastradh color.alpha = *params++; 135303b705cfSriastradh color.red = color.green = color.blue = 0; 135403b705cfSriastradh DBG(("%s: (%d, %d), alpha=%x\n", 135503b705cfSriastradh __FUNCTION__, i,j, color.alpha)); 135603b705cfSriastradh 135703b705cfSriastradh if (color.alpha <= 0x00ff) 135803b705cfSriastradh continue; 135903b705cfSriastradh 136003b705cfSriastradh alpha = CreateSolidPicture(0, &color, &error); 136103b705cfSriastradh if (alpha) { 136203b705cfSriastradh sna_composite(PictOpAdd, picture, alpha, tmp, 136303b705cfSriastradh x, y, 136403b705cfSriastradh 0, 0, 136503b705cfSriastradh x_off+i, y_off+j, 136603b705cfSriastradh w, h); 136703b705cfSriastradh FreePicture(alpha, 0); 136803b705cfSriastradh } 136903b705cfSriastradh } 137003b705cfSriastradh } 137103b705cfSriastradh picture->filter = PictFilterConvolution; 137203b705cfSriastradh 137303b705cfSriastradh channel->height = h; 137403b705cfSriastradh channel->width = w; 137503b705cfSriastradh channel->filter = PictFilterNearest; 137603b705cfSriastradh channel->repeat = RepeatNone; 137703b705cfSriastradh channel->is_affine = true; 137803b705cfSriastradh channel->transform = NULL; 137903b705cfSriastradh channel->scale[0] = 1.f / w; 138003b705cfSriastradh channel->scale[1] = 1.f / h; 138103b705cfSriastradh channel->offset[0] = -dst_x; 138203b705cfSriastradh channel->offset[1] = -dst_y; 138303b705cfSriastradh channel->bo = kgem_bo_reference(bo); /* transfer ownership */ 138403b705cfSriastradh FreePicture(tmp, 0); 138503b705cfSriastradh 138603b705cfSriastradh return 1; 138703b705cfSriastradh} 138803b705cfSriastradh 138903b705cfSriastradhstatic int 139003b705cfSriastradhsna_render_picture_flatten(struct sna *sna, 139103b705cfSriastradh PicturePtr picture, 139203b705cfSriastradh struct sna_composite_channel *channel, 139303b705cfSriastradh int16_t x, int16_t y, 139403b705cfSriastradh int16_t w, int16_t h, 139503b705cfSriastradh int16_t dst_x, int16_t dst_y) 139603b705cfSriastradh{ 139703b705cfSriastradh ScreenPtr screen = picture->pDrawable->pScreen; 139803b705cfSriastradh PixmapPtr pixmap; 139903b705cfSriastradh PicturePtr tmp, alpha; 140003b705cfSriastradh int old_format, error; 140103b705cfSriastradh 140203b705cfSriastradh assert(picture->pDrawable); 140303b705cfSriastradh assert(picture->alphaMap); 140403b705cfSriastradh assert(w <= sna->render.max_3d_size && h <= sna->render.max_3d_size); 140503b705cfSriastradh 140603b705cfSriastradh /* XXX shortcut a8? */ 140703b705cfSriastradh DBG(("%s: %dx%d\n", __FUNCTION__, w, h)); 140803b705cfSriastradh 140903b705cfSriastradh pixmap = screen->CreatePixmap(screen, w, h, 32, SNA_CREATE_SCRATCH); 141003b705cfSriastradh if (pixmap == NullPixmap) 141103b705cfSriastradh return 0; 141203b705cfSriastradh 141303b705cfSriastradh tmp = CreatePicture(0, &pixmap->drawable, 141403b705cfSriastradh PictureMatchFormat(screen, 32, PICT_a8r8g8b8), 141503b705cfSriastradh 0, NULL, serverClient, &error); 141603b705cfSriastradh screen->DestroyPixmap(pixmap); 141703b705cfSriastradh if (tmp == NULL) 141803b705cfSriastradh return 0; 141903b705cfSriastradh 142003b705cfSriastradh ValidatePicture(tmp); 142103b705cfSriastradh 142203b705cfSriastradh old_format = picture->format; 142303b705cfSriastradh picture->format = PICT_FORMAT(PICT_FORMAT_BPP(picture->format), 142403b705cfSriastradh PICT_FORMAT_TYPE(picture->format), 142503b705cfSriastradh 0, 142603b705cfSriastradh PICT_FORMAT_R(picture->format), 142703b705cfSriastradh PICT_FORMAT_G(picture->format), 142803b705cfSriastradh PICT_FORMAT_B(picture->format)); 142903b705cfSriastradh 143003b705cfSriastradh alpha = picture->alphaMap; 143103b705cfSriastradh picture->alphaMap = NULL; 143203b705cfSriastradh 143303b705cfSriastradh sna_composite(PictOpSrc, picture, alpha, tmp, 143403b705cfSriastradh x, y, 143503b705cfSriastradh x + picture->alphaOrigin.x, y + picture->alphaOrigin.y, 143603b705cfSriastradh 0, 0, 143703b705cfSriastradh w, h); 143803b705cfSriastradh 143903b705cfSriastradh picture->format = old_format; 144003b705cfSriastradh picture->alphaMap = alpha; 144103b705cfSriastradh 144203b705cfSriastradh channel->height = h; 144303b705cfSriastradh channel->width = w; 144403b705cfSriastradh channel->filter = PictFilterNearest; 144503b705cfSriastradh channel->repeat = RepeatNone; 144603b705cfSriastradh channel->pict_format = PIXMAN_a8r8g8b8; 144703b705cfSriastradh channel->is_affine = true; 144803b705cfSriastradh channel->transform = NULL; 144903b705cfSriastradh channel->scale[0] = 1.f / w; 145003b705cfSriastradh channel->scale[1] = 1.f / h; 145103b705cfSriastradh channel->offset[0] = -dst_x; 145203b705cfSriastradh channel->offset[1] = -dst_y; 145303b705cfSriastradh channel->bo = kgem_bo_reference(__sna_pixmap_get_bo(pixmap)); 145403b705cfSriastradh FreePicture(tmp, 0); 145503b705cfSriastradh 145603b705cfSriastradh return 1; 145703b705cfSriastradh} 145803b705cfSriastradh 145903b705cfSriastradhint 146003b705cfSriastradhsna_render_picture_approximate_gradient(struct sna *sna, 146103b705cfSriastradh PicturePtr picture, 146203b705cfSriastradh struct sna_composite_channel *channel, 146303b705cfSriastradh int16_t x, int16_t y, 146403b705cfSriastradh int16_t w, int16_t h, 146503b705cfSriastradh int16_t dst_x, int16_t dst_y) 146603b705cfSriastradh{ 146703b705cfSriastradh pixman_image_t *dst, *src; 146803b705cfSriastradh pixman_transform_t t; 146903b705cfSriastradh int w2 = w/2, h2 = h/2; 147003b705cfSriastradh int dx, dy; 147103b705cfSriastradh void *ptr; 147203b705cfSriastradh 147303b705cfSriastradh#if NO_FIXUP 147403b705cfSriastradh return -1; 147503b705cfSriastradh#endif 147603b705cfSriastradh 147703b705cfSriastradh DBG(("%s: (%d, %d)x(%d, %d), dst=(%d, %d)\n", 147803b705cfSriastradh __FUNCTION__, x, y, w, h, dst_x, dst_y)); 147903b705cfSriastradh 148003b705cfSriastradh if (w2 == 0 || h2 == 0) { 148103b705cfSriastradh DBG(("%s: fallback - unknown bounds\n", __FUNCTION__)); 148203b705cfSriastradh return -1; 148303b705cfSriastradh } 148403b705cfSriastradh if (w2 > sna->render.max_3d_size || h2 > sna->render.max_3d_size) { 148503b705cfSriastradh DBG(("%s: fallback - too large (%dx%d)\n", __FUNCTION__, w, h)); 148603b705cfSriastradh return -1; 148703b705cfSriastradh } 148803b705cfSriastradh 148903b705cfSriastradh channel->is_opaque = sna_gradient_is_opaque((PictGradient*)picture->pSourcePict); 149003b705cfSriastradh channel->pict_format = 149103b705cfSriastradh channel->is_opaque ? PIXMAN_x8r8g8b8 : PIXMAN_a8r8g8b8; 149203b705cfSriastradh DBG(("%s: gradient is opaque? %d, selecting format %08x\n", 149303b705cfSriastradh __FUNCTION__, channel->is_opaque, channel->pict_format)); 149403b705cfSriastradh assert(channel->card_format == -1); 149503b705cfSriastradh 149603b705cfSriastradh channel->bo = kgem_create_buffer_2d(&sna->kgem, 149703b705cfSriastradh w2, h2, 32, 149803b705cfSriastradh KGEM_BUFFER_WRITE_INPLACE, 149903b705cfSriastradh &ptr); 150003b705cfSriastradh if (!channel->bo) { 150103b705cfSriastradh DBG(("%s: failed to create upload buffer, using clear\n", 150203b705cfSriastradh __FUNCTION__)); 150303b705cfSriastradh return 0; 150403b705cfSriastradh } 150503b705cfSriastradh 150603b705cfSriastradh dst = pixman_image_create_bits(channel->pict_format, 150703b705cfSriastradh w2, h2, ptr, channel->bo->pitch); 150803b705cfSriastradh if (!dst) { 150903b705cfSriastradh kgem_bo_destroy(&sna->kgem, channel->bo); 151003b705cfSriastradh channel->bo = NULL; 151103b705cfSriastradh return 0; 151203b705cfSriastradh } 151303b705cfSriastradh 151403b705cfSriastradh src = image_from_pict(picture, false, &dx, &dy); 151503b705cfSriastradh if (src == NULL) { 151603b705cfSriastradh pixman_image_unref(dst); 151703b705cfSriastradh kgem_bo_destroy(&sna->kgem, channel->bo); 151803b705cfSriastradh channel->bo = NULL; 151903b705cfSriastradh return 0; 152003b705cfSriastradh } 152103b705cfSriastradh DBG(("%s: source offset (%d, %d)\n", __FUNCTION__, dx, dy)); 152203b705cfSriastradh 152303b705cfSriastradh memset(&t, 0, sizeof(t)); 152403b705cfSriastradh t.matrix[0][0] = (w << 16) / w2; 152503b705cfSriastradh t.matrix[0][2] = (x + dx) << 16; 152603b705cfSriastradh t.matrix[1][1] = (h << 16) / h2; 152703b705cfSriastradh t.matrix[1][2] = (y + dy) << 16; 152803b705cfSriastradh t.matrix[2][2] = 1 << 16; 152903b705cfSriastradh if (picture->transform) 153003b705cfSriastradh pixman_transform_multiply(&t, picture->transform, &t); 153103b705cfSriastradh DBG(("%s: applying transform [(%f, %f, %f), (%f, %f, %f), (%f, %f, %f)]\n", 153203b705cfSriastradh __FUNCTION__, 153303b705cfSriastradh pixman_fixed_to_double(t.matrix[0][0]), 153403b705cfSriastradh pixman_fixed_to_double(t.matrix[0][1]), 153503b705cfSriastradh pixman_fixed_to_double(t.matrix[0][2]), 153603b705cfSriastradh pixman_fixed_to_double(t.matrix[1][0]), 153703b705cfSriastradh pixman_fixed_to_double(t.matrix[1][1]), 153803b705cfSriastradh pixman_fixed_to_double(t.matrix[1][2]), 153903b705cfSriastradh pixman_fixed_to_double(t.matrix[2][0]), 154003b705cfSriastradh pixman_fixed_to_double(t.matrix[2][1]), 154103b705cfSriastradh pixman_fixed_to_double(t.matrix[2][2]))); 154203b705cfSriastradh pixman_image_set_transform(src, &t); 154303b705cfSriastradh 154403b705cfSriastradh sna_image_composite(PictOpSrc, src, NULL, dst, 154503b705cfSriastradh 0, 0, 154603b705cfSriastradh 0, 0, 154703b705cfSriastradh 0, 0, 154803b705cfSriastradh w2, h2); 154903b705cfSriastradh free_pixman_pict(picture, src); 155003b705cfSriastradh pixman_image_unref(dst); 155103b705cfSriastradh 155203b705cfSriastradh channel->width = w2; 155303b705cfSriastradh channel->height = h2; 155403b705cfSriastradh 155503b705cfSriastradh channel->filter = PictFilterNearest; 155603b705cfSriastradh channel->repeat = RepeatNone; 155703b705cfSriastradh channel->is_affine = true; 155803b705cfSriastradh 155903b705cfSriastradh channel->scale[0] = 1.f/w; 156003b705cfSriastradh channel->scale[1] = 1.f/h; 156103b705cfSriastradh channel->offset[0] = -dst_x; 156203b705cfSriastradh channel->offset[1] = -dst_y; 156303b705cfSriastradh channel->transform = NULL; 156403b705cfSriastradh 156503b705cfSriastradh return 1; 156603b705cfSriastradh} 156703b705cfSriastradh 156803b705cfSriastradhint 156903b705cfSriastradhsna_render_picture_fixup(struct sna *sna, 157003b705cfSriastradh PicturePtr picture, 157103b705cfSriastradh struct sna_composite_channel *channel, 157203b705cfSriastradh int16_t x, int16_t y, 157303b705cfSriastradh int16_t w, int16_t h, 157403b705cfSriastradh int16_t dst_x, int16_t dst_y) 157503b705cfSriastradh{ 157603b705cfSriastradh pixman_image_t *dst, *src; 157703b705cfSriastradh int dx, dy; 157803b705cfSriastradh void *ptr; 157903b705cfSriastradh 158003b705cfSriastradh#if NO_FIXUP 158103b705cfSriastradh return -1; 158203b705cfSriastradh#endif 158303b705cfSriastradh 158403b705cfSriastradh DBG(("%s: (%d, %d)x(%d, %d)\n", __FUNCTION__, x, y, w, h)); 158503b705cfSriastradh 158603b705cfSriastradh if (w == 0 || h == 0) { 158703b705cfSriastradh DBG(("%s: fallback - unknown bounds\n", __FUNCTION__)); 158803b705cfSriastradh return -1; 158903b705cfSriastradh } 159003b705cfSriastradh if (w > sna->render.max_3d_size || h > sna->render.max_3d_size) { 159103b705cfSriastradh DBG(("%s: fallback - too large (%dx%d)\n", __FUNCTION__, w, h)); 159203b705cfSriastradh return -1; 159303b705cfSriastradh } 159403b705cfSriastradh 159503b705cfSriastradh if (picture->alphaMap) { 159603b705cfSriastradh DBG(("%s: alphamap\n", __FUNCTION__)); 159703b705cfSriastradh if (is_gpu(sna, picture->pDrawable, PREFER_GPU_RENDER) || 159803b705cfSriastradh is_gpu(sna, picture->alphaMap->pDrawable, PREFER_GPU_RENDER)) { 159903b705cfSriastradh return sna_render_picture_flatten(sna, picture, channel, 160003b705cfSriastradh x, y, w, h, dst_x, dst_y); 160103b705cfSriastradh } 160203b705cfSriastradh 160303b705cfSriastradh goto do_fixup; 160403b705cfSriastradh } 160503b705cfSriastradh 160603b705cfSriastradh if (picture->filter == PictFilterConvolution) { 160703b705cfSriastradh DBG(("%s: convolution\n", __FUNCTION__)); 160803b705cfSriastradh if (is_gpu(sna, picture->pDrawable, PREFER_GPU_RENDER)) { 160903b705cfSriastradh return sna_render_picture_convolve(sna, picture, channel, 161003b705cfSriastradh x, y, w, h, dst_x, dst_y); 161103b705cfSriastradh } 161203b705cfSriastradh 161303b705cfSriastradh goto do_fixup; 161403b705cfSriastradh } 161503b705cfSriastradh 161603b705cfSriastradhdo_fixup: 161703b705cfSriastradh if (PICT_FORMAT_RGB(picture->format) == 0) 161803b705cfSriastradh channel->pict_format = PIXMAN_a8; 161903b705cfSriastradh else 162003b705cfSriastradh channel->pict_format = PIXMAN_a8r8g8b8; 162103b705cfSriastradh 162203b705cfSriastradh if (picture->pDrawable && 162303b705cfSriastradh !sna_drawable_move_to_cpu(picture->pDrawable, MOVE_READ)) 162403b705cfSriastradh return 0; 162503b705cfSriastradh 162603b705cfSriastradh channel->bo = kgem_create_buffer_2d(&sna->kgem, 162703b705cfSriastradh w, h, PIXMAN_FORMAT_BPP(channel->pict_format), 162803b705cfSriastradh KGEM_BUFFER_WRITE_INPLACE, 162903b705cfSriastradh &ptr); 163003b705cfSriastradh if (!channel->bo) { 163103b705cfSriastradh DBG(("%s: failed to create upload buffer, using clear\n", 163203b705cfSriastradh __FUNCTION__)); 163303b705cfSriastradh return 0; 163403b705cfSriastradh } 163503b705cfSriastradh 163603b705cfSriastradh /* Composite in the original format to preserve idiosyncracies */ 163703b705cfSriastradh if (!kgem_buffer_is_inplace(channel->bo) && 163803b705cfSriastradh (picture->pDrawable == NULL || 163903b705cfSriastradh alphaless(picture->format) == alphaless(channel->pict_format))) 164003b705cfSriastradh dst = pixman_image_create_bits(channel->pict_format, 164103b705cfSriastradh w, h, ptr, channel->bo->pitch); 164203b705cfSriastradh else 164303b705cfSriastradh dst = pixman_image_create_bits(picture->format, w, h, NULL, 0); 164403b705cfSriastradh if (!dst) { 164503b705cfSriastradh kgem_bo_destroy(&sna->kgem, channel->bo); 164603b705cfSriastradh return 0; 164703b705cfSriastradh } 164803b705cfSriastradh 164903b705cfSriastradh src = image_from_pict(picture, false, &dx, &dy); 165003b705cfSriastradh if (src == NULL) { 165103b705cfSriastradh pixman_image_unref(dst); 165203b705cfSriastradh kgem_bo_destroy(&sna->kgem, channel->bo); 165303b705cfSriastradh return 0; 165403b705cfSriastradh } 165503b705cfSriastradh 165603b705cfSriastradh DBG(("%s: compositing tmp=(%d+%d, %d+%d)x(%d, %d)\n", 165703b705cfSriastradh __FUNCTION__, x, dx, y, dy, w, h)); 165803b705cfSriastradh sna_image_composite(PictOpSrc, src, NULL, dst, 165903b705cfSriastradh x + dx, y + dy, 166003b705cfSriastradh 0, 0, 166103b705cfSriastradh 0, 0, 166203b705cfSriastradh w, h); 166303b705cfSriastradh free_pixman_pict(picture, src); 166403b705cfSriastradh 166503b705cfSriastradh /* Then convert to card format */ 166603b705cfSriastradh if (pixman_image_get_data(dst) != ptr) { 166703b705cfSriastradh DBG(("%s: performing post-conversion %08x->%08x (%d, %d)\n", 166803b705cfSriastradh __FUNCTION__, 166903b705cfSriastradh picture->format, channel->pict_format, 167003b705cfSriastradh w, h)); 167103b705cfSriastradh 167203b705cfSriastradh src = dst; 167303b705cfSriastradh dst = pixman_image_create_bits(channel->pict_format, 167403b705cfSriastradh w, h, ptr, channel->bo->pitch); 167503b705cfSriastradh if (dst) { 167603b705cfSriastradh pixman_image_composite(PictOpSrc, src, NULL, dst, 167703b705cfSriastradh 0, 0, 167803b705cfSriastradh 0, 0, 167903b705cfSriastradh 0, 0, 168003b705cfSriastradh w, h); 168103b705cfSriastradh pixman_image_unref(src); 168203b705cfSriastradh } else { 168303b705cfSriastradh memset(ptr, 0, __kgem_buffer_size(channel->bo)); 168403b705cfSriastradh dst = src; 168503b705cfSriastradh } 168603b705cfSriastradh } 168703b705cfSriastradh pixman_image_unref(dst); 168803b705cfSriastradh 168903b705cfSriastradh channel->width = w; 169003b705cfSriastradh channel->height = h; 169103b705cfSriastradh 169203b705cfSriastradh channel->filter = PictFilterNearest; 169303b705cfSriastradh channel->repeat = RepeatNone; 169403b705cfSriastradh channel->is_affine = true; 169503b705cfSriastradh 169603b705cfSriastradh channel->scale[0] = 1.f/w; 169703b705cfSriastradh channel->scale[1] = 1.f/h; 169803b705cfSriastradh channel->offset[0] = -dst_x; 169903b705cfSriastradh channel->offset[1] = -dst_y; 170003b705cfSriastradh channel->transform = NULL; 170103b705cfSriastradh 170203b705cfSriastradh return 1; 170303b705cfSriastradh} 170403b705cfSriastradh 170503b705cfSriastradhint 170603b705cfSriastradhsna_render_picture_convert(struct sna *sna, 170703b705cfSriastradh PicturePtr picture, 170803b705cfSriastradh struct sna_composite_channel *channel, 170903b705cfSriastradh PixmapPtr pixmap, 171003b705cfSriastradh int16_t x, int16_t y, 171103b705cfSriastradh int16_t w, int16_t h, 171203b705cfSriastradh int16_t dst_x, int16_t dst_y, 171303b705cfSriastradh bool fixup_alpha) 171403b705cfSriastradh{ 171503b705cfSriastradh BoxRec box; 171603b705cfSriastradh 171703b705cfSriastradh#if NO_CONVERT 171803b705cfSriastradh return -1; 171903b705cfSriastradh#endif 172003b705cfSriastradh 172103b705cfSriastradh if (w != 0 && h != 0) { 172203b705cfSriastradh box.x1 = x; 172303b705cfSriastradh box.y1 = y; 172403b705cfSriastradh box.x2 = bound(x, w); 172503b705cfSriastradh box.y2 = bound(y, h); 172603b705cfSriastradh 172703b705cfSriastradh if (channel->transform) { 172803b705cfSriastradh DBG(("%s: has transform, converting whole surface\n", 172903b705cfSriastradh __FUNCTION__)); 173003b705cfSriastradh box.x1 = box.y1 = 0; 173103b705cfSriastradh box.x2 = pixmap->drawable.width; 173203b705cfSriastradh box.y2 = pixmap->drawable.height; 173303b705cfSriastradh } 173403b705cfSriastradh 173503b705cfSriastradh if (box.x1 < 0) 173603b705cfSriastradh box.x1 = 0; 173703b705cfSriastradh if (box.y1 < 0) 173803b705cfSriastradh box.y1 = 0; 173903b705cfSriastradh if (box.x2 > pixmap->drawable.width) 174003b705cfSriastradh box.x2 = pixmap->drawable.width; 174103b705cfSriastradh if (box.y2 > pixmap->drawable.height) 174203b705cfSriastradh box.y2 = pixmap->drawable.height; 174303b705cfSriastradh } else { 174403b705cfSriastradh DBG(("%s: op no bounds, converting whole surface\n", 174503b705cfSriastradh __FUNCTION__)); 174603b705cfSriastradh box.x1 = box.y1 = 0; 174703b705cfSriastradh box.x2 = pixmap->drawable.width; 174803b705cfSriastradh box.y2 = pixmap->drawable.height; 174903b705cfSriastradh } 175003b705cfSriastradh 175103b705cfSriastradh w = box.x2 - box.x1; 175203b705cfSriastradh h = box.y2 - box.y1; 175303b705cfSriastradh 175403b705cfSriastradh DBG(("%s: convert (%d, %d)x(%d, %d), source size %dx%d\n", 175503b705cfSriastradh __FUNCTION__, box.x1, box.y1, w, h, 175603b705cfSriastradh pixmap->drawable.width, 175703b705cfSriastradh pixmap->drawable.height)); 175803b705cfSriastradh 175903b705cfSriastradh if (w <= 0 || h <= 0) { 176003b705cfSriastradh DBG(("%s: sample extents lie outside of source, using clear\n", 176103b705cfSriastradh __FUNCTION__)); 176203b705cfSriastradh return 0; 176303b705cfSriastradh } 176403b705cfSriastradh 176503b705cfSriastradh if (fixup_alpha && is_gpu(sna, &pixmap->drawable, PREFER_GPU_RENDER)) { 176603b705cfSriastradh ScreenPtr screen = pixmap->drawable.pScreen; 176703b705cfSriastradh PixmapPtr tmp; 176803b705cfSriastradh PicturePtr src, dst; 176903b705cfSriastradh int error; 177003b705cfSriastradh 177103b705cfSriastradh assert(PICT_FORMAT_BPP(picture->format) == pixmap->drawable.bitsPerPixel); 177203b705cfSriastradh channel->pict_format = PICT_FORMAT(PICT_FORMAT_BPP(picture->format), 177303b705cfSriastradh PICT_FORMAT_TYPE(picture->format), 177403b705cfSriastradh PICT_FORMAT_BPP(picture->format) - PIXMAN_FORMAT_DEPTH(picture->format), 177503b705cfSriastradh PICT_FORMAT_R(picture->format), 177603b705cfSriastradh PICT_FORMAT_G(picture->format), 177703b705cfSriastradh PICT_FORMAT_B(picture->format)); 177803b705cfSriastradh 177903b705cfSriastradh DBG(("%s: converting to %08x from %08x using composite alpha-fixup\n", 178003b705cfSriastradh __FUNCTION__, 178103b705cfSriastradh (unsigned)channel->pict_format, 178203b705cfSriastradh (unsigned)picture->format)); 178303b705cfSriastradh 178403b705cfSriastradh tmp = screen->CreatePixmap(screen, w, h, pixmap->drawable.bitsPerPixel, 0); 178503b705cfSriastradh if (tmp == NULL) 178603b705cfSriastradh return 0; 178703b705cfSriastradh 178803b705cfSriastradh dst = CreatePicture(0, &tmp->drawable, 178903b705cfSriastradh PictureMatchFormat(screen, 179003b705cfSriastradh pixmap->drawable.bitsPerPixel, 179103b705cfSriastradh channel->pict_format), 179203b705cfSriastradh 0, NULL, serverClient, &error); 179303b705cfSriastradh if (dst == NULL) { 179403b705cfSriastradh screen->DestroyPixmap(tmp); 179503b705cfSriastradh return 0; 179603b705cfSriastradh } 179703b705cfSriastradh 179803b705cfSriastradh src = CreatePicture(0, &pixmap->drawable, 179903b705cfSriastradh PictureMatchFormat(screen, 180003b705cfSriastradh pixmap->drawable.depth, 180103b705cfSriastradh picture->format), 180203b705cfSriastradh 0, NULL, serverClient, &error); 180303b705cfSriastradh if (src == NULL) { 180403b705cfSriastradh FreePicture(dst, 0); 180503b705cfSriastradh screen->DestroyPixmap(tmp); 180603b705cfSriastradh return 0; 180703b705cfSriastradh } 180803b705cfSriastradh 180903b705cfSriastradh ValidatePicture(src); 181003b705cfSriastradh ValidatePicture(dst); 181103b705cfSriastradh 181203b705cfSriastradh sna_composite(PictOpSrc, src, NULL, dst, 181303b705cfSriastradh box.x1, box.y1, 181403b705cfSriastradh 0, 0, 181503b705cfSriastradh 0, 0, 181603b705cfSriastradh w, h); 181703b705cfSriastradh FreePicture(dst, 0); 181803b705cfSriastradh FreePicture(src, 0); 181903b705cfSriastradh 182003b705cfSriastradh channel->bo = __sna_pixmap_get_bo(tmp); 182103b705cfSriastradh kgem_bo_reference(channel->bo); 182203b705cfSriastradh screen->DestroyPixmap(tmp); 182303b705cfSriastradh } else { 182403b705cfSriastradh pixman_image_t *src, *dst; 182503b705cfSriastradh void *ptr; 182603b705cfSriastradh 182703b705cfSriastradh if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ)) 182803b705cfSriastradh return 0; 182903b705cfSriastradh 183003b705cfSriastradh src = pixman_image_create_bits(picture->format, 183103b705cfSriastradh pixmap->drawable.width, 183203b705cfSriastradh pixmap->drawable.height, 183303b705cfSriastradh pixmap->devPrivate.ptr, 183403b705cfSriastradh pixmap->devKind); 183503b705cfSriastradh if (!src) 183603b705cfSriastradh return 0; 183703b705cfSriastradh 183803b705cfSriastradh if (PICT_FORMAT_RGB(picture->format) == 0) { 183903b705cfSriastradh channel->pict_format = PIXMAN_a8; 184003b705cfSriastradh DBG(("%s: converting to a8 from %08x\n", 184103b705cfSriastradh __FUNCTION__, picture->format)); 184203b705cfSriastradh } else { 184303b705cfSriastradh channel->pict_format = PIXMAN_a8r8g8b8; 184403b705cfSriastradh DBG(("%s: converting to a8r8g8b8 from %08x\n", 184503b705cfSriastradh __FUNCTION__, picture->format)); 184603b705cfSriastradh } 184703b705cfSriastradh 184803b705cfSriastradh channel->bo = kgem_create_buffer_2d(&sna->kgem, 184903b705cfSriastradh w, h, PIXMAN_FORMAT_BPP(channel->pict_format), 185003b705cfSriastradh KGEM_BUFFER_WRITE_INPLACE, 185103b705cfSriastradh &ptr); 185203b705cfSriastradh if (!channel->bo) { 185303b705cfSriastradh pixman_image_unref(src); 185403b705cfSriastradh return 0; 185503b705cfSriastradh } 185603b705cfSriastradh 185703b705cfSriastradh dst = pixman_image_create_bits(channel->pict_format, 185803b705cfSriastradh w, h, ptr, channel->bo->pitch); 185903b705cfSriastradh if (!dst) { 186003b705cfSriastradh kgem_bo_destroy(&sna->kgem, channel->bo); 186103b705cfSriastradh pixman_image_unref(src); 186203b705cfSriastradh return 0; 186303b705cfSriastradh } 186403b705cfSriastradh 186503b705cfSriastradh pixman_image_composite(PictOpSrc, src, NULL, dst, 186603b705cfSriastradh box.x1, box.y1, 186703b705cfSriastradh 0, 0, 186803b705cfSriastradh 0, 0, 186903b705cfSriastradh w, h); 187003b705cfSriastradh pixman_image_unref(dst); 187103b705cfSriastradh pixman_image_unref(src); 187203b705cfSriastradh } 187303b705cfSriastradh 187403b705cfSriastradh channel->width = w; 187503b705cfSriastradh channel->height = h; 187603b705cfSriastradh 187703b705cfSriastradh channel->scale[0] = 1.f/w; 187803b705cfSriastradh channel->scale[1] = 1.f/h; 187903b705cfSriastradh channel->offset[0] = x - dst_x - box.x1; 188003b705cfSriastradh channel->offset[1] = y - dst_y - box.y1; 188103b705cfSriastradh 188203b705cfSriastradh DBG(("%s: offset=(%d, %d), size=(%d, %d)\n", 188303b705cfSriastradh __FUNCTION__, 188403b705cfSriastradh channel->offset[0], channel->offset[1], 188503b705cfSriastradh channel->width, channel->height)); 188603b705cfSriastradh return 1; 188703b705cfSriastradh} 188803b705cfSriastradh 188903b705cfSriastradhbool 189003b705cfSriastradhsna_render_composite_redirect(struct sna *sna, 189103b705cfSriastradh struct sna_composite_op *op, 189203b705cfSriastradh int x, int y, int width, int height, 189303b705cfSriastradh bool partial) 189403b705cfSriastradh{ 189503b705cfSriastradh struct sna_composite_redirect *t = &op->redirect; 189603b705cfSriastradh int bpp = op->dst.pixmap->drawable.bitsPerPixel; 189703b705cfSriastradh struct kgem_bo *bo; 189803b705cfSriastradh 189903b705cfSriastradh assert(t->real_bo == NULL); 190003b705cfSriastradh 190103b705cfSriastradh#if NO_REDIRECT 190203b705cfSriastradh return false; 190303b705cfSriastradh#endif 190403b705cfSriastradh 190503b705cfSriastradh DBG(("%s: target too large (%dx%d), copying to temporary %dx%d, max %d / %d\n", 190603b705cfSriastradh __FUNCTION__, 190703b705cfSriastradh op->dst.width, op->dst.height, 190803b705cfSriastradh width, height, 190903b705cfSriastradh sna->render.max_3d_size, 191003b705cfSriastradh sna->render.max_3d_pitch)); 191103b705cfSriastradh 191203b705cfSriastradh if (!width || !height) 191303b705cfSriastradh return false; 191403b705cfSriastradh 191503b705cfSriastradh if (width > sna->render.max_3d_size || 191603b705cfSriastradh height > sna->render.max_3d_size) 191703b705cfSriastradh return false; 191803b705cfSriastradh 191903b705cfSriastradh if (op->dst.bo->pitch <= sna->render.max_3d_pitch) { 192003b705cfSriastradh BoxRec box; 192103b705cfSriastradh int w, h, offset; 192203b705cfSriastradh 192303b705cfSriastradh DBG(("%s: dst pitch (%d) fits within render pipeline (%d)\n", 192403b705cfSriastradh __FUNCTION__, op->dst.bo->pitch, sna->render.max_3d_pitch)); 192503b705cfSriastradh 192603b705cfSriastradh box.x1 = x + op->dst.x; 192703b705cfSriastradh box.x2 = bound(box.x1, width); 192803b705cfSriastradh box.y1 = y + op->dst.y; 192903b705cfSriastradh box.y2 = bound(box.y1, height); 193003b705cfSriastradh 193103b705cfSriastradh if (box.x1 < 0) 193203b705cfSriastradh box.x1 = 0; 193303b705cfSriastradh if (box.y1 < 0) 193403b705cfSriastradh box.y1 = 0; 193503b705cfSriastradh 193603b705cfSriastradh /* Ensure we align to an even tile row */ 193703b705cfSriastradh if (op->dst.bo->tiling) { 193803b705cfSriastradh int tile_width, tile_height, tile_size; 193903b705cfSriastradh 194003b705cfSriastradh kgem_get_tile_size(&sna->kgem, op->dst.bo->tiling, 194103b705cfSriastradh &tile_width, &tile_height, &tile_size); 194203b705cfSriastradh 194303b705cfSriastradh box.y1 = box.y1 & ~(2*tile_height - 1); 194403b705cfSriastradh box.y2 = ALIGN(box.y2, 2*tile_height); 194503b705cfSriastradh 194603b705cfSriastradh box.x1 = box.x1 & ~(tile_width * 8 / op->dst.pixmap->drawable.bitsPerPixel - 1); 194703b705cfSriastradh box.x2 = ALIGN(box.x2, tile_width * 8 / op->dst.pixmap->drawable.bitsPerPixel); 194803b705cfSriastradh 194903b705cfSriastradh offset = box.x1 * op->dst.pixmap->drawable.bitsPerPixel / 8 / tile_width * tile_size; 195003b705cfSriastradh } else { 195103b705cfSriastradh if (sna->kgem.gen < 040) { 195203b705cfSriastradh box.y1 = box.y1 & ~3; 195303b705cfSriastradh box.y2 = ALIGN(box.y2, 4); 195403b705cfSriastradh 195503b705cfSriastradh box.x1 = box.x1 & ~3; 195603b705cfSriastradh box.x2 = ALIGN(box.x2, 4); 195703b705cfSriastradh } else { 195803b705cfSriastradh box.y1 = box.y1 & ~1; 195903b705cfSriastradh box.y2 = ALIGN(box.y2, 2); 196003b705cfSriastradh 196103b705cfSriastradh box.x1 = box.x1 & ~1; 196203b705cfSriastradh box.x2 = ALIGN(box.x2, 2); 196303b705cfSriastradh } 196403b705cfSriastradh 196503b705cfSriastradh offset = box.x1 * op->dst.pixmap->drawable.bitsPerPixel / 8; 196603b705cfSriastradh } 196703b705cfSriastradh 196803b705cfSriastradh if (box.y2 > op->dst.pixmap->drawable.height) 196903b705cfSriastradh box.y2 = op->dst.pixmap->drawable.height; 197003b705cfSriastradh 197103b705cfSriastradh if (box.x2 > op->dst.pixmap->drawable.width) 197203b705cfSriastradh box.x2 = op->dst.pixmap->drawable.width; 197303b705cfSriastradh 197403b705cfSriastradh w = box.x2 - box.x1; 197503b705cfSriastradh h = box.y2 - box.y1; 197603b705cfSriastradh DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d), max %d\n", __FUNCTION__, 197703b705cfSriastradh box.x1, box.y1, box.x2, box.y2, w, h, 197803b705cfSriastradh op->dst.pixmap->drawable.width, 197903b705cfSriastradh op->dst.pixmap->drawable.height, 198003b705cfSriastradh sna->render.max_3d_size)); 198103b705cfSriastradh if (w <= sna->render.max_3d_size && 198203b705cfSriastradh h <= sna->render.max_3d_size) { 198303b705cfSriastradh t->box.x2 = t->box.x1 = op->dst.x; 198403b705cfSriastradh t->box.y2 = t->box.y1 = op->dst.y; 198503b705cfSriastradh t->real_bo = op->dst.bo; 198603b705cfSriastradh t->real_damage = op->damage; 198703b705cfSriastradh if (op->damage) { 198803b705cfSriastradh assert(!DAMAGE_IS_ALL(op->damage)); 198903b705cfSriastradh t->damage = sna_damage_create(); 199003b705cfSriastradh op->damage = &t->damage; 199103b705cfSriastradh } 199203b705cfSriastradh 199303b705cfSriastradh /* How many tiles across are we? */ 199403b705cfSriastradh op->dst.bo = kgem_create_proxy(&sna->kgem, op->dst.bo, 199503b705cfSriastradh box.y1 * op->dst.bo->pitch + offset, 199603b705cfSriastradh h * op->dst.bo->pitch); 199703b705cfSriastradh if (!op->dst.bo) { 199803b705cfSriastradh t->real_bo = NULL; 199903b705cfSriastradh if (t->damage) 200003b705cfSriastradh __sna_damage_destroy(t->damage); 200103b705cfSriastradh return false; 200203b705cfSriastradh } 200303b705cfSriastradh 200403b705cfSriastradh assert(op->dst.bo != t->real_bo); 200503b705cfSriastradh op->dst.bo->unique_id = kgem_get_unique_id(&sna->kgem); 200603b705cfSriastradh op->dst.bo->pitch = t->real_bo->pitch; 200703b705cfSriastradh 200803b705cfSriastradh op->dst.x -= box.x1; 200903b705cfSriastradh op->dst.y -= box.y1; 201003b705cfSriastradh op->dst.width = w; 201103b705cfSriastradh op->dst.height = h; 201203b705cfSriastradh return true; 201303b705cfSriastradh } 201403b705cfSriastradh } 201503b705cfSriastradh 201603b705cfSriastradh /* We can process the operation in a single pass, 201703b705cfSriastradh * but the target is too large for the 3D pipeline. 201803b705cfSriastradh * Copy into a smaller surface and replace afterwards. 201903b705cfSriastradh */ 202003b705cfSriastradh bo = kgem_create_2d(&sna->kgem, 202103b705cfSriastradh width, height, bpp, 202203b705cfSriastradh kgem_choose_tiling(&sna->kgem, I915_TILING_X, 202303b705cfSriastradh width, height, bpp), 202403b705cfSriastradh CREATE_TEMPORARY); 202503b705cfSriastradh if (!bo) 202603b705cfSriastradh return false; 202703b705cfSriastradh 202803b705cfSriastradh t->box.x1 = x + op->dst.x; 202903b705cfSriastradh t->box.y1 = y + op->dst.y; 203003b705cfSriastradh t->box.x2 = bound(t->box.x1, width); 203103b705cfSriastradh t->box.y2 = bound(t->box.y1, height); 203203b705cfSriastradh 203303b705cfSriastradh DBG(("%s: original box (%d, %d), (%d, %d)\n", 203403b705cfSriastradh __FUNCTION__, t->box.x1, t->box.y1, t->box.x2, t->box.y2)); 203503b705cfSriastradh 203603b705cfSriastradh if (partial && 203703b705cfSriastradh !sna_blt_copy_boxes(sna, GXcopy, 203803b705cfSriastradh op->dst.bo, 0, 0, 203903b705cfSriastradh bo, -t->box.x1, -t->box.y1, 204003b705cfSriastradh bpp, &t->box, 1)) { 204103b705cfSriastradh kgem_bo_destroy(&sna->kgem, bo); 204203b705cfSriastradh return false; 204303b705cfSriastradh } 204403b705cfSriastradh 204503b705cfSriastradh t->real_bo = op->dst.bo; 204603b705cfSriastradh t->real_damage = op->damage; 204703b705cfSriastradh if (op->damage) { 204803b705cfSriastradh assert(!DAMAGE_IS_ALL(op->damage)); 204903b705cfSriastradh t->damage = sna_damage_create(); 205003b705cfSriastradh op->damage = &t->damage; 205103b705cfSriastradh } 205203b705cfSriastradh 205303b705cfSriastradh op->dst.bo = bo; 205403b705cfSriastradh op->dst.x = -x; 205503b705cfSriastradh op->dst.y = -y; 205603b705cfSriastradh op->dst.width = width; 205703b705cfSriastradh op->dst.height = height; 205803b705cfSriastradh return true; 205903b705cfSriastradh} 206003b705cfSriastradh 206103b705cfSriastradhvoid 206203b705cfSriastradhsna_render_composite_redirect_done(struct sna *sna, 206303b705cfSriastradh const struct sna_composite_op *op) 206403b705cfSriastradh{ 206503b705cfSriastradh const struct sna_composite_redirect *t = &op->redirect; 206603b705cfSriastradh 206703b705cfSriastradh if (t->real_bo) { 206803b705cfSriastradh assert(op->dst.bo != t->real_bo); 206903b705cfSriastradh 207003b705cfSriastradh if (t->box.x2 > t->box.x1) { 207103b705cfSriastradh bool ok; 207203b705cfSriastradh 207303b705cfSriastradh DBG(("%s: copying temporary to dst\n", __FUNCTION__)); 207403b705cfSriastradh ok = sna_blt_copy_boxes(sna, GXcopy, 207503b705cfSriastradh op->dst.bo, -t->box.x1, -t->box.y1, 207603b705cfSriastradh t->real_bo, 0, 0, 207703b705cfSriastradh op->dst.pixmap->drawable.bitsPerPixel, 207803b705cfSriastradh &t->box, 1); 207903b705cfSriastradh assert(ok); 208003b705cfSriastradh (void)ok; 208103b705cfSriastradh } 208203b705cfSriastradh if (t->damage) { 208303b705cfSriastradh DBG(("%s: combining damage (all? %d), offset=(%d, %d)\n", 208403b705cfSriastradh __FUNCTION__, (int)DAMAGE_IS_ALL(t->damage), 208503b705cfSriastradh t->box.x1, t->box.y1)); 208603b705cfSriastradh sna_damage_combine(t->real_damage, 208703b705cfSriastradh DAMAGE_PTR(t->damage), 208803b705cfSriastradh t->box.x1, t->box.y1); 208903b705cfSriastradh __sna_damage_destroy(DAMAGE_PTR(t->damage)); 209003b705cfSriastradh } 209103b705cfSriastradh 209203b705cfSriastradh kgem_bo_destroy(&sna->kgem, op->dst.bo); 209303b705cfSriastradh } 209403b705cfSriastradh} 209503b705cfSriastradh 209603b705cfSriastradhbool 209703b705cfSriastradhsna_render_copy_boxes__overlap(struct sna *sna, uint8_t alu, 209803b705cfSriastradh PixmapPtr src, struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy, 209903b705cfSriastradh PixmapPtr dst, struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy, 210003b705cfSriastradh const BoxRec *box, int n, const BoxRec *extents) 210103b705cfSriastradh{ 210203b705cfSriastradh ScreenPtr screen = dst->drawable.pScreen; 210303b705cfSriastradh struct kgem_bo *bo; 210403b705cfSriastradh PixmapPtr tmp; 210503b705cfSriastradh bool ret = false; 210603b705cfSriastradh 210703b705cfSriastradh tmp = screen->CreatePixmap(screen, 210803b705cfSriastradh extents->x2 - extents->x1, 210903b705cfSriastradh extents->y2 - extents->y1, 211003b705cfSriastradh dst->drawable.depth, 211103b705cfSriastradh SNA_CREATE_SCRATCH); 211203b705cfSriastradh if (tmp == NULL) 211303b705cfSriastradh return false; 211403b705cfSriastradh 211503b705cfSriastradh bo = __sna_pixmap_get_bo(tmp); 211603b705cfSriastradh if (bo == NULL) 211703b705cfSriastradh goto out; 211803b705cfSriastradh 211903b705cfSriastradh ret = (sna->render.copy_boxes(sna, alu, 212003b705cfSriastradh src, src_bo, src_dx, src_dy, 212103b705cfSriastradh tmp, bo, -extents->x1, -extents->y1, 212203b705cfSriastradh box, n , 0) && 212303b705cfSriastradh sna->render.copy_boxes(sna, alu, 212403b705cfSriastradh tmp, bo, -extents->x1, -extents->y1, 212503b705cfSriastradh dst, dst_bo, dst_dx, dst_dy, 212603b705cfSriastradh box, n , 0)); 212703b705cfSriastradh 212803b705cfSriastradhout: 212903b705cfSriastradh screen->DestroyPixmap(tmp); 213003b705cfSriastradh return ret; 213103b705cfSriastradh} 2132