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 2842542f5fSchristos#ifdef HAVE_CONFIG_H 2942542f5fSchristos#include "config.h" 3042542f5fSchristos#endif 3142542f5fSchristos 3203b705cfSriastradh#include "sna.h" 3303b705cfSriastradh#include "sna_render.h" 3403b705cfSriastradh#include "sna_render_inline.h" 3503b705cfSriastradh#include "fb/fbpict.h" 3603b705cfSriastradh 3703b705cfSriastradh#define NO_REDIRECT 0 3803b705cfSriastradh#define NO_CONVERT 0 3903b705cfSriastradh#define NO_FIXUP 0 4003b705cfSriastradh#define NO_EXTRACT 0 4103b705cfSriastradh 4203b705cfSriastradh#define DBG_FORCE_UPLOAD 0 4303b705cfSriastradh#define DBG_NO_CPU_BO 0 4403b705cfSriastradh 4503b705cfSriastradh#define alphaless(format) PICT_FORMAT(PICT_FORMAT_BPP(format), \ 4603b705cfSriastradh PICT_FORMAT_TYPE(format), \ 4703b705cfSriastradh 0, \ 4803b705cfSriastradh PICT_FORMAT_R(format), \ 4903b705cfSriastradh PICT_FORMAT_G(format), \ 5003b705cfSriastradh PICT_FORMAT_B(format)) 5103b705cfSriastradh 5203b705cfSriastradhCARD32 5303b705cfSriastradhsna_format_for_depth(int depth) 5403b705cfSriastradh{ 5503b705cfSriastradh switch (depth) { 5603b705cfSriastradh case 1: return PICT_a1; 57fe8aea9eSmrg case 4: return PICT_x4a4; 5803b705cfSriastradh case 8: return PICT_a8; 5903b705cfSriastradh case 15: return PICT_x1r5g5b5; 6003b705cfSriastradh case 16: return PICT_r5g6b5; 6103b705cfSriastradh default: assert(0); 6203b705cfSriastradh case 24: return PICT_x8r8g8b8; 63fe8aea9eSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,6,99,900,0) 6403b705cfSriastradh case 30: return PICT_x2r10g10b10; 6542542f5fSchristos#endif 6603b705cfSriastradh case 32: return PICT_a8r8g8b8; 6703b705cfSriastradh } 6803b705cfSriastradh} 6903b705cfSriastradh 7003b705cfSriastradhCARD32 7103b705cfSriastradhsna_render_format_for_depth(int depth) 7203b705cfSriastradh{ 7303b705cfSriastradh switch (depth) { 7403b705cfSriastradh case 1: return PIXMAN_a1; 7503b705cfSriastradh case 4: return PIXMAN_a4; 7603b705cfSriastradh case 8: return PIXMAN_a8; 7703b705cfSriastradh case 15: return PIXMAN_a1r5g5b5; 7803b705cfSriastradh case 16: return PIXMAN_r5g6b5; 7903b705cfSriastradh case 30: return PIXMAN_a2r10g10b10; 8003b705cfSriastradh default: assert(0); 8103b705cfSriastradh case 24: 8203b705cfSriastradh case 32: return PIXMAN_a8r8g8b8; 8303b705cfSriastradh } 8403b705cfSriastradh} 8503b705cfSriastradh 8603b705cfSriastradhstatic bool 8703b705cfSriastradhno_render_composite(struct sna *sna, 8803b705cfSriastradh uint8_t op, 8903b705cfSriastradh PicturePtr src, 9003b705cfSriastradh PicturePtr mask, 9103b705cfSriastradh PicturePtr dst, 9203b705cfSriastradh int16_t src_x, int16_t src_y, 9303b705cfSriastradh int16_t mask_x, int16_t mask_y, 9403b705cfSriastradh int16_t dst_x, int16_t dst_y, 9503b705cfSriastradh int16_t width, int16_t height, 9642542f5fSchristos unsigned flags, 9703b705cfSriastradh struct sna_composite_op *tmp) 9803b705cfSriastradh{ 9903b705cfSriastradh DBG(("%s (op=%d, mask? %d)\n", __FUNCTION__, op, mask != NULL)); 10003b705cfSriastradh 10103b705cfSriastradh if (mask) 10203b705cfSriastradh return false; 10303b705cfSriastradh 10403b705cfSriastradh if (!is_gpu(sna, dst->pDrawable, PREFER_GPU_BLT) && 10503b705cfSriastradh (src->pDrawable == NULL || !is_gpu(sna, src->pDrawable, PREFER_GPU_BLT))) 10603b705cfSriastradh return false; 10703b705cfSriastradh 10803b705cfSriastradh return sna_blt_composite(sna, 10903b705cfSriastradh op, src, dst, 11003b705cfSriastradh src_x, src_y, 11103b705cfSriastradh dst_x, dst_y, 11203b705cfSriastradh width, height, 11342542f5fSchristos flags | COMPOSITE_FALLBACK, tmp); 11403b705cfSriastradh (void)mask_x; 11503b705cfSriastradh (void)mask_y; 11603b705cfSriastradh} 11703b705cfSriastradh 11803b705cfSriastradhstatic bool 11903b705cfSriastradhno_render_check_composite_spans(struct sna *sna, 12003b705cfSriastradh uint8_t op, PicturePtr src, PicturePtr dst, 12103b705cfSriastradh int16_t width, int16_t height, unsigned flags) 12203b705cfSriastradh{ 12303b705cfSriastradh return false; 12403b705cfSriastradh} 12503b705cfSriastradh 12603b705cfSriastradhstatic bool 12703b705cfSriastradhno_render_copy_boxes(struct sna *sna, uint8_t alu, 12842542f5fSchristos const DrawableRec *src, struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy, 12942542f5fSchristos const DrawableRec *dst, struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy, 13003b705cfSriastradh const BoxRec *box, int n, unsigned flags) 13103b705cfSriastradh{ 13203b705cfSriastradh DBG(("%s (n=%d)\n", __FUNCTION__, n)); 13303b705cfSriastradh 13442542f5fSchristos if (!sna_blt_compare_depth(src, dst)) 13503b705cfSriastradh return false; 13603b705cfSriastradh 13703b705cfSriastradh return sna_blt_copy_boxes(sna, alu, 13803b705cfSriastradh src_bo, src_dx, src_dy, 13903b705cfSriastradh dst_bo, dst_dx, dst_dy, 14042542f5fSchristos dst->bitsPerPixel, 14103b705cfSriastradh box, n); 14203b705cfSriastradh} 14303b705cfSriastradh 14403b705cfSriastradhstatic bool 14503b705cfSriastradhno_render_copy(struct sna *sna, uint8_t alu, 14603b705cfSriastradh PixmapPtr src, struct kgem_bo *src_bo, 14703b705cfSriastradh PixmapPtr dst, struct kgem_bo *dst_bo, 14803b705cfSriastradh struct sna_copy_op *tmp) 14903b705cfSriastradh{ 15003b705cfSriastradh DBG(("%s ()\n", __FUNCTION__)); 15103b705cfSriastradh 15203b705cfSriastradh if (sna_blt_compare_depth(&src->drawable, &dst->drawable) && 15303b705cfSriastradh sna_blt_copy(sna, alu, 15403b705cfSriastradh src_bo, dst_bo, dst->drawable.bitsPerPixel, 15503b705cfSriastradh tmp)) 15603b705cfSriastradh return true; 15703b705cfSriastradh 15803b705cfSriastradh return false; 15903b705cfSriastradh} 16003b705cfSriastradh 16103b705cfSriastradhstatic bool 16203b705cfSriastradhno_render_fill_boxes(struct sna *sna, 16303b705cfSriastradh CARD8 op, 16403b705cfSriastradh PictFormat format, 16503b705cfSriastradh const xRenderColor *color, 16642542f5fSchristos const DrawableRec *dst, struct kgem_bo *dst_bo, 16703b705cfSriastradh const BoxRec *box, int n) 16803b705cfSriastradh{ 16903b705cfSriastradh uint8_t alu = GXcopy; 17003b705cfSriastradh uint32_t pixel; 17103b705cfSriastradh 17203b705cfSriastradh DBG(("%s (op=%d, color=(%04x,%04x,%04x, %04x))\n", 17303b705cfSriastradh __FUNCTION__, op, 17403b705cfSriastradh color->red, color->green, color->blue, color->alpha)); 17503b705cfSriastradh 17603b705cfSriastradh if (op == PictOpClear) { 17703b705cfSriastradh pixel = 0; 17803b705cfSriastradh alu = GXclear; 17903b705cfSriastradh op = PictOpSrc; 18003b705cfSriastradh } 18103b705cfSriastradh 18203b705cfSriastradh if (op == PictOpOver) { 18303b705cfSriastradh if ((color->alpha >= 0xff00)) 18403b705cfSriastradh op = PictOpSrc; 18503b705cfSriastradh } 18603b705cfSriastradh 18703b705cfSriastradh if (op != PictOpSrc) 18803b705cfSriastradh return false; 18903b705cfSriastradh 19003b705cfSriastradh if (alu == GXcopy && 19103b705cfSriastradh !sna_get_pixel_from_rgba(&pixel, 19203b705cfSriastradh color->red, 19303b705cfSriastradh color->green, 19403b705cfSriastradh color->blue, 19503b705cfSriastradh color->alpha, 19603b705cfSriastradh format)) 19703b705cfSriastradh return false; 19803b705cfSriastradh 19903b705cfSriastradh return sna_blt_fill_boxes(sna, alu, 20042542f5fSchristos dst_bo, dst->bitsPerPixel, 20103b705cfSriastradh pixel, box, n); 20203b705cfSriastradh} 20303b705cfSriastradh 20403b705cfSriastradhstatic bool 20503b705cfSriastradhno_render_fill(struct sna *sna, uint8_t alu, 20603b705cfSriastradh PixmapPtr dst, struct kgem_bo *dst_bo, 20742542f5fSchristos uint32_t color, unsigned flags, 20803b705cfSriastradh struct sna_fill_op *tmp) 20903b705cfSriastradh{ 21003b705cfSriastradh DBG(("%s (alu=%d, color=%08x)\n", __FUNCTION__, alu, color)); 21103b705cfSriastradh return sna_blt_fill(sna, alu, 21203b705cfSriastradh dst_bo, dst->drawable.bitsPerPixel, 21303b705cfSriastradh color, 21403b705cfSriastradh tmp); 21503b705cfSriastradh} 21603b705cfSriastradh 21703b705cfSriastradhstatic bool 21803b705cfSriastradhno_render_fill_one(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo, 21903b705cfSriastradh uint32_t color, 22003b705cfSriastradh int16_t x1, int16_t y1, int16_t x2, int16_t y2, 22103b705cfSriastradh uint8_t alu) 22203b705cfSriastradh{ 22303b705cfSriastradh BoxRec box; 22403b705cfSriastradh 22503b705cfSriastradh box.x1 = x1; 22603b705cfSriastradh box.y1 = y1; 22703b705cfSriastradh box.x2 = x2; 22803b705cfSriastradh box.y2 = y2; 22903b705cfSriastradh 23003b705cfSriastradh DBG(("%s (alu=%d, color=%08x) (%d,%d), (%d, %d)\n", 23103b705cfSriastradh __FUNCTION__, alu, color, x1, y1, x2, y2)); 23203b705cfSriastradh return sna_blt_fill_boxes(sna, alu, 23303b705cfSriastradh bo, dst->drawable.bitsPerPixel, 23403b705cfSriastradh color, &box, 1); 23503b705cfSriastradh} 23603b705cfSriastradh 23703b705cfSriastradhstatic bool 23803b705cfSriastradhno_render_clear(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo) 23903b705cfSriastradh{ 24003b705cfSriastradh DBG(("%s: pixmap=%ld %dx%d\n", __FUNCTION__, 24103b705cfSriastradh dst->drawable.serialNumber, 24203b705cfSriastradh dst->drawable.width, 24303b705cfSriastradh dst->drawable.height)); 24403b705cfSriastradh return sna->render.fill_one(sna, dst, bo, 0, 24503b705cfSriastradh 0, 0, dst->drawable.width, dst->drawable.height, 24603b705cfSriastradh GXclear); 24703b705cfSriastradh} 24803b705cfSriastradh 24903b705cfSriastradhstatic void no_render_reset(struct sna *sna) 25003b705cfSriastradh{ 25103b705cfSriastradh (void)sna; 25203b705cfSriastradh} 25303b705cfSriastradh 25403b705cfSriastradhstatic void no_render_flush(struct sna *sna) 25503b705cfSriastradh{ 25603b705cfSriastradh (void)sna; 25703b705cfSriastradh} 25803b705cfSriastradh 25903b705cfSriastradhstatic void 26003b705cfSriastradhno_render_context_switch(struct kgem *kgem, 26103b705cfSriastradh int new_mode) 26203b705cfSriastradh{ 26303b705cfSriastradh if (!kgem->nbatch) 26403b705cfSriastradh return; 26503b705cfSriastradh 26603b705cfSriastradh if (kgem_ring_is_idle(kgem, kgem->ring)) { 26703b705cfSriastradh DBG(("%s: GPU idle, flushing\n", __FUNCTION__)); 26803b705cfSriastradh _kgem_submit(kgem); 26903b705cfSriastradh } 27003b705cfSriastradh 27103b705cfSriastradh (void)new_mode; 27203b705cfSriastradh} 27303b705cfSriastradh 27403b705cfSriastradhstatic void 27503b705cfSriastradhno_render_fini(struct sna *sna) 27603b705cfSriastradh{ 27703b705cfSriastradh (void)sna; 27803b705cfSriastradh} 27903b705cfSriastradh 28003b705cfSriastradhconst char *no_render_init(struct sna *sna) 28103b705cfSriastradh{ 28203b705cfSriastradh struct sna_render *render = &sna->render; 28303b705cfSriastradh 28403b705cfSriastradh memset (render, 0, sizeof (*render)); 28503b705cfSriastradh 28603b705cfSriastradh render->prefer_gpu = PREFER_GPU_BLT; 28703b705cfSriastradh 28803b705cfSriastradh render->vertices = render->vertex_data; 28903b705cfSriastradh render->vertex_size = ARRAY_SIZE(render->vertex_data); 29003b705cfSriastradh 29103b705cfSriastradh render->composite = no_render_composite; 29203b705cfSriastradh render->check_composite_spans = no_render_check_composite_spans; 29303b705cfSriastradh 29403b705cfSriastradh render->copy_boxes = no_render_copy_boxes; 29503b705cfSriastradh render->copy = no_render_copy; 29603b705cfSriastradh 29703b705cfSriastradh render->fill_boxes = no_render_fill_boxes; 29803b705cfSriastradh render->fill = no_render_fill; 29903b705cfSriastradh render->fill_one = no_render_fill_one; 30003b705cfSriastradh render->clear = no_render_clear; 30103b705cfSriastradh 30203b705cfSriastradh render->reset = no_render_reset; 30303b705cfSriastradh render->flush = no_render_flush; 30403b705cfSriastradh render->fini = no_render_fini; 30503b705cfSriastradh 30603b705cfSriastradh sna->kgem.context_switch = no_render_context_switch; 30703b705cfSriastradh if (sna->kgem.has_blt) 30803b705cfSriastradh sna->kgem.ring = KGEM_BLT; 30903b705cfSriastradh 31003b705cfSriastradh sna_vertex_init(sna); 31103b705cfSriastradh return "generic"; 31203b705cfSriastradh} 31303b705cfSriastradh 31403b705cfSriastradhstatic struct kgem_bo * 31503b705cfSriastradhuse_cpu_bo(struct sna *sna, PixmapPtr pixmap, const BoxRec *box, bool blt) 31603b705cfSriastradh{ 31703b705cfSriastradh struct sna_pixmap *priv; 31803b705cfSriastradh 31903b705cfSriastradh if (DBG_NO_CPU_BO) 32003b705cfSriastradh return NULL; 32103b705cfSriastradh 32203b705cfSriastradh priv = sna_pixmap(pixmap); 32303b705cfSriastradh if (priv == NULL || priv->cpu_bo == NULL) { 32403b705cfSriastradh DBG(("%s: no cpu bo\n", __FUNCTION__)); 32503b705cfSriastradh return NULL; 32603b705cfSriastradh } 32703b705cfSriastradh 32803b705cfSriastradh if (!blt && priv->cpu_bo->snoop && priv->source_count > SOURCE_BIAS) { 32903b705cfSriastradh DBG(("%s: promoting snooped CPU bo due to reuse\n", 33003b705cfSriastradh __FUNCTION__)); 33103b705cfSriastradh return NULL; 33203b705cfSriastradh } 33303b705cfSriastradh 33403b705cfSriastradh if (priv->gpu_bo) { 33542542f5fSchristos switch (sna_damage_contains_box(&priv->cpu_damage, box)) { 33603b705cfSriastradh case PIXMAN_REGION_OUT: 33703b705cfSriastradh DBG(("%s: has GPU bo and no damage to upload\n", 33803b705cfSriastradh __FUNCTION__)); 33903b705cfSriastradh return NULL; 34003b705cfSriastradh 34103b705cfSriastradh case PIXMAN_REGION_IN: 34203b705cfSriastradh DBG(("%s: has GPU bo but box is completely on CPU\n", 34303b705cfSriastradh __FUNCTION__)); 34403b705cfSriastradh break; 34503b705cfSriastradh default: 34603b705cfSriastradh if (kgem_bo_is_busy(priv->gpu_bo)){ 34703b705cfSriastradh DBG(("%s: box is partially damaged on the CPU, and the GPU is busy\n", 34803b705cfSriastradh __FUNCTION__)); 34903b705cfSriastradh return NULL; 35003b705cfSriastradh } 35142542f5fSchristos if (sna_damage_contains_box(&priv->gpu_damage, 35203b705cfSriastradh box) != PIXMAN_REGION_OUT) { 35303b705cfSriastradh DBG(("%s: box is damaged on the GPU\n", 35403b705cfSriastradh __FUNCTION__)); 35503b705cfSriastradh return NULL; 35603b705cfSriastradh } 35703b705cfSriastradh break; 35803b705cfSriastradh } 35903b705cfSriastradh } 36003b705cfSriastradh 36103b705cfSriastradh if (!blt) { 36203b705cfSriastradh int w = box->x2 - box->x1; 36303b705cfSriastradh int h = box->y2 - box->y1; 36403b705cfSriastradh 36503b705cfSriastradh if (w < pixmap->drawable.width || 36603b705cfSriastradh h < pixmap->drawable.height || 36703b705cfSriastradh priv->source_count != SOURCE_BIAS) { 36803b705cfSriastradh bool want_tiling; 36903b705cfSriastradh 37003b705cfSriastradh if (priv->cpu_bo->pitch >= 4096) { 37103b705cfSriastradh DBG(("%s: size=%dx%d, promoting reused (%d) CPU bo due to TLB miss (%dx%d, pitch=%d)\n", 37203b705cfSriastradh __FUNCTION__, w, h, priv->source_count, 37303b705cfSriastradh pixmap->drawable.width, 37403b705cfSriastradh pixmap->drawable.height, 37503b705cfSriastradh priv->cpu_bo->pitch)); 37603b705cfSriastradh return NULL; 37703b705cfSriastradh } 37803b705cfSriastradh 37903b705cfSriastradh if (priv->gpu_bo) 38003b705cfSriastradh want_tiling = priv->gpu_bo->tiling != I915_TILING_NONE; 38103b705cfSriastradh else 38203b705cfSriastradh want_tiling = kgem_choose_tiling(&sna->kgem, 38303b705cfSriastradh I915_TILING_Y, 38403b705cfSriastradh pixmap->drawable.width, 38503b705cfSriastradh pixmap->drawable.height, 38603b705cfSriastradh pixmap->drawable.bitsPerPixel) != I915_TILING_NONE; 38703b705cfSriastradh if (want_tiling && 38803b705cfSriastradh priv->source_count*w*h >= (int)pixmap->drawable.width * pixmap->drawable.height) { 38903b705cfSriastradh DBG(("%s: pitch (%d) requires tiling\n", 39003b705cfSriastradh __FUNCTION__, priv->cpu_bo->pitch)); 39103b705cfSriastradh return NULL; 39203b705cfSriastradh } 39303b705cfSriastradh } 39403b705cfSriastradh } 39503b705cfSriastradh 396fe8aea9eSmrg add_shm_flush(sna, priv); 39703b705cfSriastradh 39803b705cfSriastradh DBG(("%s for box=(%d, %d), (%d, %d)\n", 39903b705cfSriastradh __FUNCTION__, box->x1, box->y1, box->x2, box->y2)); 40003b705cfSriastradh ++priv->source_count; 40103b705cfSriastradh return priv->cpu_bo; 40203b705cfSriastradh} 40303b705cfSriastradh 40403b705cfSriastradhstatic struct kgem_bo * 40503b705cfSriastradhmove_to_gpu(PixmapPtr pixmap, const BoxRec *box, bool blt) 40603b705cfSriastradh{ 40703b705cfSriastradh struct sna_pixmap *priv; 40803b705cfSriastradh int count, w, h; 40903b705cfSriastradh bool migrate = false; 41003b705cfSriastradh 41103b705cfSriastradh if (DBG_FORCE_UPLOAD > 0) 41203b705cfSriastradh return NULL; 41303b705cfSriastradh 41403b705cfSriastradh priv = sna_pixmap(pixmap); 41503b705cfSriastradh if (priv == NULL) { 41613496ba1Ssnj DBG(("%s: not migrating unattached pixmap=%ld\n", 41713496ba1Ssnj __FUNCTION__, pixmap->drawable.serialNumber)); 41803b705cfSriastradh return NULL; 41903b705cfSriastradh } 42003b705cfSriastradh 42103b705cfSriastradh if (priv->shm) 42203b705cfSriastradh blt = true; 42303b705cfSriastradh 42403b705cfSriastradh if (priv->gpu_bo) { 42503b705cfSriastradh if (priv->cpu_damage && 42642542f5fSchristos sna_damage_contains_box(&priv->cpu_damage, 42703b705cfSriastradh box) != PIXMAN_REGION_OUT) 42803b705cfSriastradh goto upload; 42903b705cfSriastradh 43003b705cfSriastradh return priv->gpu_bo; 43103b705cfSriastradh } 43203b705cfSriastradh 43303b705cfSriastradh if (priv->cpu_damage == NULL) { 43413496ba1Ssnj DBG(("%s: not migrating uninitialised pixmap=%ld\n", 43513496ba1Ssnj __FUNCTION__, pixmap->drawable.serialNumber)); 43603b705cfSriastradh return NULL; 43703b705cfSriastradh } 43803b705cfSriastradh 43903b705cfSriastradh if (pixmap->usage_hint) { 44013496ba1Ssnj DBG(("%s: not migrating pixmap=%ld due to usage_hint=%d\n", 44113496ba1Ssnj __FUNCTION__, 44213496ba1Ssnj pixmap->drawable.serialNumber, 44313496ba1Ssnj pixmap->usage_hint)); 44403b705cfSriastradh return NULL; 44503b705cfSriastradh } 44603b705cfSriastradh 44703b705cfSriastradh if (DBG_FORCE_UPLOAD < 0) { 44803b705cfSriastradh if (!sna_pixmap_force_to_gpu(pixmap, 44913496ba1Ssnj blt ? MOVE_READ : MOVE_SOURCE_HINT | MOVE_ASYNC_HINT | MOVE_READ)) 45003b705cfSriastradh return NULL; 45103b705cfSriastradh 45203b705cfSriastradh return priv->gpu_bo; 45303b705cfSriastradh } 45403b705cfSriastradh 45503b705cfSriastradh w = box->x2 - box->x1; 45603b705cfSriastradh h = box->y2 - box->y1; 45703b705cfSriastradh if (priv->cpu_bo && !priv->cpu_bo->flush) { 45803b705cfSriastradh migrate = true; 45903b705cfSriastradh } else if (w == pixmap->drawable.width && h == pixmap->drawable.height) { 46003b705cfSriastradh migrate = priv->source_count++ > SOURCE_BIAS; 46103b705cfSriastradh 46203b705cfSriastradh DBG(("%s: migrating whole pixmap (%dx%d) for source (%d,%d),(%d,%d), count %d? %d\n", 46303b705cfSriastradh __FUNCTION__, 46403b705cfSriastradh pixmap->drawable.width, pixmap->drawable.height, 46503b705cfSriastradh box->x1, box->y1, box->x2, box->y2, priv->source_count, 46603b705cfSriastradh migrate)); 46703b705cfSriastradh } else if (kgem_choose_tiling(&to_sna_from_pixmap(pixmap)->kgem, 46803b705cfSriastradh blt ? I915_TILING_X : I915_TILING_Y, w, h, 46903b705cfSriastradh pixmap->drawable.bitsPerPixel) != I915_TILING_NONE) { 47003b705cfSriastradh count = priv->source_count++; 47103b705cfSriastradh if ((priv->create & KGEM_CAN_CREATE_GPU) == 0) 47203b705cfSriastradh count -= SOURCE_BIAS; 47303b705cfSriastradh 47403b705cfSriastradh DBG(("%s: migrate box (%d, %d), (%d, %d)? source count=%d, fraction=%d/%d [%d]\n", 47503b705cfSriastradh __FUNCTION__, 47603b705cfSriastradh box->x1, box->y1, box->x2, box->y2, 47703b705cfSriastradh count, w*h, 47803b705cfSriastradh pixmap->drawable.width * pixmap->drawable.height, 47903b705cfSriastradh pixmap->drawable.width * pixmap->drawable.height / (w*h))); 48003b705cfSriastradh 48103b705cfSriastradh migrate = count*w*h > pixmap->drawable.width * pixmap->drawable.height; 48203b705cfSriastradh } 48303b705cfSriastradh 48403b705cfSriastradh if (!migrate) 48503b705cfSriastradh return NULL; 48603b705cfSriastradh 48703b705cfSriastradhupload: 48803b705cfSriastradh if (blt) { 48903b705cfSriastradh if (!sna_pixmap_move_area_to_gpu(pixmap, box, 49003b705cfSriastradh __MOVE_FORCE | MOVE_READ)) 49103b705cfSriastradh return NULL; 49203b705cfSriastradh } else { 49303b705cfSriastradh if (!sna_pixmap_move_to_gpu(pixmap, 49413496ba1Ssnj __MOVE_FORCE | MOVE_ASYNC_HINT | MOVE_SOURCE_HINT | MOVE_READ)) 49503b705cfSriastradh return NULL; 49603b705cfSriastradh } 49703b705cfSriastradh 49803b705cfSriastradh return priv->gpu_bo; 49903b705cfSriastradh} 50003b705cfSriastradh 50103b705cfSriastradhstatic struct kgem_bo *upload(struct sna *sna, 50203b705cfSriastradh struct sna_composite_channel *channel, 50303b705cfSriastradh PixmapPtr pixmap, 50403b705cfSriastradh const BoxRec *box) 50503b705cfSriastradh{ 50603b705cfSriastradh struct sna_pixmap *priv; 50703b705cfSriastradh struct kgem_bo *bo; 50803b705cfSriastradh 50903b705cfSriastradh DBG(("%s: box=(%d, %d), (%d, %d), pixmap=%dx%d\n", 51003b705cfSriastradh __FUNCTION__, box->x1, box->y1, box->x2, box->y2, pixmap->drawable.width, pixmap->drawable.height)); 51103b705cfSriastradh assert(box->x1 >= 0); 51203b705cfSriastradh assert(box->y1 >= 0); 51303b705cfSriastradh assert(box->x2 <= pixmap->drawable.width); 51403b705cfSriastradh assert(box->y2 <= pixmap->drawable.height); 51503b705cfSriastradh 51603b705cfSriastradh priv = sna_pixmap(pixmap); 51703b705cfSriastradh if (priv) { 51803b705cfSriastradh RegionRec region; 51903b705cfSriastradh 52003b705cfSriastradh if (priv->cpu_damage == NULL) 52103b705cfSriastradh return NULL; /* uninitialised */ 52203b705cfSriastradh 52303b705cfSriastradh region.extents = *box; 52403b705cfSriastradh region.data = NULL; 52503b705cfSriastradh if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, 52603b705cfSriastradh ®ion, MOVE_READ)) 52703b705cfSriastradh return NULL; 52803b705cfSriastradh 52903b705cfSriastradh assert(!priv->mapped); 53003b705cfSriastradh if (pixmap->devPrivate.ptr == NULL) 53103b705cfSriastradh return NULL; /* uninitialised */ 53203b705cfSriastradh } 53303b705cfSriastradh 53403b705cfSriastradh bo = kgem_upload_source_image(&sna->kgem, 53503b705cfSriastradh pixmap->devPrivate.ptr, box, 53603b705cfSriastradh pixmap->devKind, 53703b705cfSriastradh pixmap->drawable.bitsPerPixel); 53803b705cfSriastradh if (channel && bo) { 53903b705cfSriastradh channel->width = box->x2 - box->x1; 54003b705cfSriastradh channel->height = box->y2 - box->y1; 54103b705cfSriastradh channel->offset[0] -= box->x1; 54203b705cfSriastradh channel->offset[1] -= box->y1; 54303b705cfSriastradh 54403b705cfSriastradh if (priv && 54503b705cfSriastradh pixmap->usage_hint == 0 && 54603b705cfSriastradh channel->width == pixmap->drawable.width && 54703b705cfSriastradh channel->height == pixmap->drawable.height) { 54803b705cfSriastradh DBG(("%s: adding upload cache to pixmap=%ld\n", 54903b705cfSriastradh __FUNCTION__, pixmap->drawable.serialNumber)); 55003b705cfSriastradh assert(priv->gpu_damage == NULL); 55103b705cfSriastradh assert(priv->gpu_bo == NULL); 55203b705cfSriastradh assert(bo->proxy != NULL); 553fe8aea9eSmrg sna_damage_all(&priv->cpu_damage, pixmap); 55403b705cfSriastradh kgem_proxy_bo_attach(bo, &priv->gpu_bo); 55503b705cfSriastradh } 55603b705cfSriastradh } 55703b705cfSriastradh 55803b705cfSriastradh return bo; 55903b705cfSriastradh} 56003b705cfSriastradh 56103b705cfSriastradhstruct kgem_bo * 56203b705cfSriastradh__sna_render_pixmap_bo(struct sna *sna, 56303b705cfSriastradh PixmapPtr pixmap, 56403b705cfSriastradh const BoxRec *box, 56503b705cfSriastradh bool blt) 56603b705cfSriastradh{ 56703b705cfSriastradh struct kgem_bo *bo; 56803b705cfSriastradh 56903b705cfSriastradh bo = use_cpu_bo(sna, pixmap, box, blt); 57003b705cfSriastradh if (bo == NULL) { 57103b705cfSriastradh bo = move_to_gpu(pixmap, box, blt); 57203b705cfSriastradh if (bo == NULL) 57303b705cfSriastradh return NULL; 57403b705cfSriastradh } 57503b705cfSriastradh 57603b705cfSriastradh return bo; 57703b705cfSriastradh} 57803b705cfSriastradh 57903b705cfSriastradhint 58003b705cfSriastradhsna_render_pixmap_bo(struct sna *sna, 58103b705cfSriastradh struct sna_composite_channel *channel, 58203b705cfSriastradh PixmapPtr pixmap, 58303b705cfSriastradh int16_t x, int16_t y, 58403b705cfSriastradh int16_t w, int16_t h, 58503b705cfSriastradh int16_t dst_x, int16_t dst_y) 58603b705cfSriastradh{ 58703b705cfSriastradh struct sna_pixmap *priv; 58803b705cfSriastradh BoxRec box; 58903b705cfSriastradh 59003b705cfSriastradh DBG(("%s pixmap=%ld, (%d, %d)x(%d, %d)/(%d, %d)\n", 59103b705cfSriastradh __FUNCTION__, pixmap->drawable.serialNumber, 59203b705cfSriastradh x, y, w,h, pixmap->drawable.width, pixmap->drawable.height)); 59303b705cfSriastradh 59403b705cfSriastradh channel->width = pixmap->drawable.width; 59503b705cfSriastradh channel->height = pixmap->drawable.height; 59603b705cfSriastradh channel->offset[0] = x - dst_x; 59703b705cfSriastradh channel->offset[1] = y - dst_y; 59803b705cfSriastradh 59903b705cfSriastradh priv = sna_pixmap(pixmap); 60003b705cfSriastradh if (priv) { 60103b705cfSriastradh if (priv->gpu_bo && 60203b705cfSriastradh (DAMAGE_IS_ALL(priv->gpu_damage) || !priv->cpu_damage || 60303b705cfSriastradh priv->gpu_bo->proxy)) { 60403b705cfSriastradh DBG(("%s: GPU all damaged\n", __FUNCTION__)); 60503b705cfSriastradh channel->bo = priv->gpu_bo; 60603b705cfSriastradh goto done; 60703b705cfSriastradh } 60803b705cfSriastradh 60903b705cfSriastradh if (priv->cpu_bo && 61003b705cfSriastradh (DAMAGE_IS_ALL(priv->cpu_damage) || !priv->gpu_damage) && 61103b705cfSriastradh !priv->cpu_bo->snoop && priv->cpu_bo->pitch < 4096) { 61203b705cfSriastradh DBG(("%s: CPU all damaged\n", __FUNCTION__)); 61303b705cfSriastradh channel->bo = priv->cpu_bo; 614fe8aea9eSmrg add_shm_flush(sna, priv); 61503b705cfSriastradh goto done; 61603b705cfSriastradh } 61703b705cfSriastradh } 61803b705cfSriastradh 61903b705cfSriastradh /* XXX handle transformed repeat */ 62003b705cfSriastradh if (w == 0 || h == 0 || channel->transform) { 62103b705cfSriastradh box.x1 = box.y1 = 0; 62203b705cfSriastradh box.x2 = pixmap->drawable.width; 62303b705cfSriastradh box.y2 = pixmap->drawable.height; 62403b705cfSriastradh } else { 62503b705cfSriastradh box.x1 = x; 62603b705cfSriastradh box.y1 = y; 62703b705cfSriastradh box.x2 = bound(x, w); 62803b705cfSriastradh box.y2 = bound(y, h); 62903b705cfSriastradh 63003b705cfSriastradh if (channel->repeat == RepeatNone || channel->repeat == RepeatPad) { 63103b705cfSriastradh if (box.x1 < 0) 63203b705cfSriastradh box.x1 = 0; 63303b705cfSriastradh if (box.y1 < 0) 63403b705cfSriastradh box.y1 = 0; 63503b705cfSriastradh if (box.x2 > pixmap->drawable.width) 63603b705cfSriastradh box.x2 = pixmap->drawable.width; 63703b705cfSriastradh if (box.y2 > pixmap->drawable.height) 63803b705cfSriastradh box.y2 = pixmap->drawable.height; 63903b705cfSriastradh } else { 64003b705cfSriastradh if (box.x1 < 0 || box.x2 > pixmap->drawable.width) 64103b705cfSriastradh box.x1 = 0, box.x2 = pixmap->drawable.width; 64203b705cfSriastradh if (box.y1 < 0 || box.y2 > pixmap->drawable.height) 64303b705cfSriastradh box.y1 = 0, box.y2 = pixmap->drawable.height; 64403b705cfSriastradh } 64503b705cfSriastradh } 64603b705cfSriastradh 64703b705cfSriastradh w = box.x2 - box.x1; 64803b705cfSriastradh h = box.y2 - box.y1; 64903b705cfSriastradh DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d)\n", __FUNCTION__, 65003b705cfSriastradh box.x1, box.y1, box.x2, box.y2, w, h, 65103b705cfSriastradh pixmap->drawable.width, pixmap->drawable.height)); 65203b705cfSriastradh if (w <= 0 || h <= 0) { 65303b705cfSriastradh DBG(("%s: sample extents outside of texture -> clear\n", 65403b705cfSriastradh __FUNCTION__)); 65503b705cfSriastradh return 0; 65603b705cfSriastradh } 65703b705cfSriastradh 65803b705cfSriastradh DBG(("%s: offset=(%d, %d), size=(%d, %d)\n", 65903b705cfSriastradh __FUNCTION__, 66003b705cfSriastradh channel->offset[0], channel->offset[1], 66103b705cfSriastradh pixmap->drawable.width, pixmap->drawable.height)); 66203b705cfSriastradh 66303b705cfSriastradh channel->bo = __sna_render_pixmap_bo(sna, pixmap, &box, false); 66403b705cfSriastradh if (channel->bo == NULL) { 66503b705cfSriastradh DBG(("%s: uploading CPU box (%d, %d), (%d, %d)\n", 66603b705cfSriastradh __FUNCTION__, box.x1, box.y1, box.x2, box.y2)); 66703b705cfSriastradh channel->bo = upload(sna, channel, pixmap, &box); 66803b705cfSriastradh if (channel->bo == NULL) 66903b705cfSriastradh return 0; 67003b705cfSriastradh } else { 67103b705cfSriastradhdone: 67203b705cfSriastradh kgem_bo_reference(channel->bo); 67303b705cfSriastradh } 67403b705cfSriastradh 67503b705cfSriastradh channel->scale[0] = 1.f / channel->width; 67603b705cfSriastradh channel->scale[1] = 1.f / channel->height; 67703b705cfSriastradh return 1; 67803b705cfSriastradh} 67903b705cfSriastradh 68003b705cfSriastradhstatic int sna_render_picture_downsample(struct sna *sna, 68103b705cfSriastradh PicturePtr picture, 68203b705cfSriastradh struct sna_composite_channel *channel, 68303b705cfSriastradh const int16_t x, const int16_t y, 68403b705cfSriastradh const int16_t w, const int16_t h, 68503b705cfSriastradh const int16_t dst_x, const int16_t dst_y) 68603b705cfSriastradh{ 68703b705cfSriastradh PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable); 68803b705cfSriastradh ScreenPtr screen = pixmap->drawable.pScreen; 68903b705cfSriastradh PicturePtr tmp_src, tmp_dst; 69003b705cfSriastradh PictFormatPtr format; 69103b705cfSriastradh struct sna_pixmap *priv; 69203b705cfSriastradh pixman_transform_t t; 69303b705cfSriastradh PixmapPtr tmp; 69442542f5fSchristos int width, height, size, max_size; 69503b705cfSriastradh int sx, sy, sw, sh; 69603b705cfSriastradh int error, ret = 0; 69703b705cfSriastradh BoxRec box, b; 69803b705cfSriastradh 69903b705cfSriastradh box.x1 = x; 70003b705cfSriastradh box.y1 = y; 70103b705cfSriastradh box.x2 = bound(x, w); 70203b705cfSriastradh box.y2 = bound(y, h); 70303b705cfSriastradh if (channel->transform) { 70403b705cfSriastradh pixman_vector_t v; 70503b705cfSriastradh 70603b705cfSriastradh pixman_transform_bounds(channel->transform, &box); 70703b705cfSriastradh 70803b705cfSriastradh v.vector[0] = x << 16; 70903b705cfSriastradh v.vector[1] = y << 16; 71003b705cfSriastradh v.vector[2] = 1 << 16; 71103b705cfSriastradh pixman_transform_point(channel->transform, &v); 71203b705cfSriastradh } 71303b705cfSriastradh 71403b705cfSriastradh if (channel->repeat == RepeatNone || channel->repeat == RepeatPad) { 71503b705cfSriastradh if (box.x1 < 0) 71603b705cfSriastradh box.x1 = 0; 71703b705cfSriastradh if (box.y1 < 0) 71803b705cfSriastradh box.y1 = 0; 71903b705cfSriastradh if (box.x2 > pixmap->drawable.width) 72003b705cfSriastradh box.x2 = pixmap->drawable.width; 72103b705cfSriastradh if (box.y2 > pixmap->drawable.height) 72203b705cfSriastradh box.y2 = pixmap->drawable.height; 72303b705cfSriastradh } else { 72403b705cfSriastradh /* XXX tiled repeats? */ 72503b705cfSriastradh if (box.x1 < 0 || box.x2 > pixmap->drawable.width) 72603b705cfSriastradh box.x1 = 0, box.x2 = pixmap->drawable.width; 72703b705cfSriastradh if (box.y1 < 0 || box.y2 > pixmap->drawable.height) 72803b705cfSriastradh box.y1 = 0, box.y2 = pixmap->drawable.height; 72903b705cfSriastradh 73003b705cfSriastradh } 73103b705cfSriastradh 73203b705cfSriastradh sw = box.x2 - box.x1; 73303b705cfSriastradh sh = box.y2 - box.y1; 73403b705cfSriastradh 73503b705cfSriastradh DBG(("%s: sample (%d, %d), (%d, %d)\n", 73603b705cfSriastradh __FUNCTION__, box.x1, box.y1, box.x2, box.y2)); 73703b705cfSriastradh 73803b705cfSriastradh sx = (sw + sna->render.max_3d_size - 1) / sna->render.max_3d_size; 73903b705cfSriastradh sy = (sh + sna->render.max_3d_size - 1) / sna->render.max_3d_size; 74003b705cfSriastradh 74103b705cfSriastradh DBG(("%s: scaling (%d, %d) down by %dx%d\n", 74203b705cfSriastradh __FUNCTION__, sw, sh, sx, sy)); 74303b705cfSriastradh 74403b705cfSriastradh width = sw / sx; 74503b705cfSriastradh height = sh / sy; 74603b705cfSriastradh 74703b705cfSriastradh DBG(("%s: creating temporary GPU bo %dx%d\n", 74803b705cfSriastradh __FUNCTION__, width, height)); 74903b705cfSriastradh 75003b705cfSriastradh tmp = screen->CreatePixmap(screen, 75103b705cfSriastradh width, height, 75203b705cfSriastradh pixmap->drawable.depth, 75303b705cfSriastradh SNA_CREATE_SCRATCH); 75442542f5fSchristos if (tmp == NULL) 75542542f5fSchristos goto fixup; 75603b705cfSriastradh 75703b705cfSriastradh priv = sna_pixmap(tmp); 75842542f5fSchristos assert(priv && priv->gpu_bo); 75942542f5fSchristos 76013496ba1Ssnj if (!sna_pixmap_move_to_gpu(pixmap, MOVE_ASYNC_HINT | MOVE_SOURCE_HINT | MOVE_READ)) { 76142542f5fSchristosfixup: 76242542f5fSchristos DBG(("%s: unable to create GPU bo for target or temporary pixmaps\n", 76342542f5fSchristos __FUNCTION__)); 76442542f5fSchristos return sna_render_picture_fixup(sna, picture, channel, 76542542f5fSchristos x, y, w, h, 76642542f5fSchristos dst_x, dst_y); 76742542f5fSchristos } 76803b705cfSriastradh 76903b705cfSriastradh format = PictureMatchFormat(screen, 77003b705cfSriastradh pixmap->drawable.depth, 77103b705cfSriastradh picture->format); 77242542f5fSchristos if (format == NULL) { 77342542f5fSchristos DBG(("%s: invalid depth=%d, format=%08x\n", 77442542f5fSchristos __FUNCTION__, pixmap->drawable.depth, picture->format)); 77542542f5fSchristos goto fixup; 77642542f5fSchristos } 77703b705cfSriastradh 77803b705cfSriastradh tmp_dst = CreatePicture(0, &tmp->drawable, format, 0, NULL, 77903b705cfSriastradh serverClient, &error); 78003b705cfSriastradh if (!tmp_dst) 78103b705cfSriastradh goto cleanup_tmp; 78203b705cfSriastradh 78303b705cfSriastradh tmp_src = CreatePicture(0, &pixmap->drawable, format, 0, NULL, 78403b705cfSriastradh serverClient, &error); 78503b705cfSriastradh if (!tmp_src) 78603b705cfSriastradh goto cleanup_dst; 78703b705cfSriastradh 78803b705cfSriastradh tmp_src->repeat = 1; 78903b705cfSriastradh tmp_src->repeatType = RepeatPad; 79003b705cfSriastradh /* Prefer to use nearest as it helps reduce artefacts from 79103b705cfSriastradh * interpolating and filtering twice. 79203b705cfSriastradh */ 79303b705cfSriastradh tmp_src->filter = PictFilterNearest; 79403b705cfSriastradh memset(&t, 0, sizeof(t)); 79503b705cfSriastradh t.matrix[0][0] = (sw << 16) / width; 79603b705cfSriastradh t.matrix[0][2] = box.x1 << 16; 79703b705cfSriastradh t.matrix[1][1] = (sh << 16) / height; 79803b705cfSriastradh t.matrix[1][2] = box.y1 << 16; 79903b705cfSriastradh t.matrix[2][2] = 1 << 16; 80003b705cfSriastradh tmp_src->transform = &t; 80103b705cfSriastradh 80203b705cfSriastradh ValidatePicture(tmp_dst); 80303b705cfSriastradh ValidatePicture(tmp_src); 80403b705cfSriastradh 80503b705cfSriastradh /* Use a small size to accommodate enlargement through tile alignment */ 80642542f5fSchristos max_size = sna_max_tile_copy_size(sna, sna_pixmap(pixmap)->gpu_bo, priv->gpu_bo); 80742542f5fSchristos if (max_size == 0) 80842542f5fSchristos goto cleanup_dst; 80942542f5fSchristos 81003b705cfSriastradh size = sna->render.max_3d_size - 4096 / pixmap->drawable.bitsPerPixel; 81142542f5fSchristos while (size * size * 4 > max_size) 81203b705cfSriastradh size /= 2; 81313496ba1Ssnj DBG(("%s: size=%d (max=%d), scale %dx%d\n", 81413496ba1Ssnj __FUNCTION__, size, max_size, sx, sy)); 81503b705cfSriastradh 81603b705cfSriastradh sw = size / sx - 2 * sx; 81713496ba1Ssnj if (sw < 1) 81813496ba1Ssnj sw = 1; 81903b705cfSriastradh sh = size / sy - 2 * sy; 82013496ba1Ssnj if (sh < 1) 82113496ba1Ssnj sh = 1; 82203b705cfSriastradh DBG(("%s %d:%d downsampling using %dx%d GPU tiles\n", 82303b705cfSriastradh __FUNCTION__, (width + sw-1)/sw, (height + sh-1)/sh, sw, sh)); 82403b705cfSriastradh 82503b705cfSriastradh for (b.y1 = 0; b.y1 < height; b.y1 = b.y2) { 82603b705cfSriastradh b.y2 = b.y1 + sh; 82703b705cfSriastradh if (b.y2 > height) 82803b705cfSriastradh b.y2 = height; 82903b705cfSriastradh 83003b705cfSriastradh for (b.x1 = 0; b.x1 < width; b.x1 = b.x2) { 83103b705cfSriastradh struct sna_composite_op op; 83203b705cfSriastradh 83303b705cfSriastradh b.x2 = b.x1 + sw; 83403b705cfSriastradh if (b.x2 > width) 83503b705cfSriastradh b.x2 = width; 83603b705cfSriastradh 83703b705cfSriastradh DBG(("%s: tile (%d, %d), (%d, %d)\n", 83803b705cfSriastradh __FUNCTION__, b.x1, b.y1, b.x2, b.y2)); 83903b705cfSriastradh 84003b705cfSriastradh memset(&op, 0, sizeof(op)); 84103b705cfSriastradh if (!sna->render.composite(sna, 84203b705cfSriastradh PictOpSrc, 84303b705cfSriastradh tmp_src, NULL, tmp_dst, 84403b705cfSriastradh b.x1, b.y1, 84503b705cfSriastradh 0, 0, 84603b705cfSriastradh b.x1, b.y1, 84703b705cfSriastradh b.x2 - b.x1, b.y2 - b.y1, 84842542f5fSchristos 0, &op)) 84903b705cfSriastradh goto cleanup_src; 85003b705cfSriastradh 85103b705cfSriastradh op.box(sna, &op, &b); 85203b705cfSriastradh op.done(sna, &op); 85303b705cfSriastradh } 85403b705cfSriastradh } 85503b705cfSriastradh 85603b705cfSriastradh pixman_transform_invert(&channel->embedded_transform, &t); 85703b705cfSriastradh if (channel->transform) 85803b705cfSriastradh pixman_transform_multiply(&channel->embedded_transform, 85903b705cfSriastradh &channel->embedded_transform, 86003b705cfSriastradh channel->transform); 86103b705cfSriastradh channel->transform = &channel->embedded_transform; 86203b705cfSriastradh 86303b705cfSriastradh channel->offset[0] = x - dst_x; 86403b705cfSriastradh channel->offset[1] = y - dst_y; 86503b705cfSriastradh channel->scale[0] = 1.f/width; 86603b705cfSriastradh channel->scale[1] = 1.f/height; 86703b705cfSriastradh channel->width = width; 86803b705cfSriastradh channel->height = height; 86903b705cfSriastradh channel->bo = kgem_bo_reference(priv->gpu_bo); 87003b705cfSriastradh 87103b705cfSriastradh ret = 1; 87203b705cfSriastradhcleanup_src: 87303b705cfSriastradh tmp_src->transform = NULL; 87403b705cfSriastradh FreePicture(tmp_src, 0); 87503b705cfSriastradhcleanup_dst: 87603b705cfSriastradh FreePicture(tmp_dst, 0); 87703b705cfSriastradhcleanup_tmp: 87803b705cfSriastradh screen->DestroyPixmap(tmp); 87903b705cfSriastradh return ret; 88003b705cfSriastradh} 88103b705cfSriastradh 88203b705cfSriastradhbool 88303b705cfSriastradhsna_render_pixmap_partial(struct sna *sna, 88442542f5fSchristos const DrawableRec *draw, 88503b705cfSriastradh struct kgem_bo *bo, 88603b705cfSriastradh struct sna_composite_channel *channel, 88703b705cfSriastradh int16_t x, int16_t y, 88803b705cfSriastradh int16_t w, int16_t h) 88903b705cfSriastradh{ 89003b705cfSriastradh BoxRec box; 89103b705cfSriastradh int offset; 89203b705cfSriastradh 89303b705cfSriastradh DBG(("%s (%d, %d)x(%d, %d), pitch %d, max %d\n", 89403b705cfSriastradh __FUNCTION__, x, y, w, h, bo->pitch, sna->render.max_3d_pitch)); 89503b705cfSriastradh 89642542f5fSchristos if (bo->pitch > sna->render.max_3d_pitch) { 89742542f5fSchristos DBG(("%s: pitch too great %d > %d\n", __FUNCTION__, bo->pitch, sna->render.max_3d_pitch)); 89803b705cfSriastradh return false; 89942542f5fSchristos } 90003b705cfSriastradh 90103b705cfSriastradh box.x1 = x; 90203b705cfSriastradh box.y1 = y; 90303b705cfSriastradh box.x2 = bound(x, w); 90403b705cfSriastradh box.y2 = bound(y, h); 90503b705cfSriastradh DBG(("%s: unaligned box (%d, %d), (%d, %d)\n", 90603b705cfSriastradh __FUNCTION__, box.x1, box.y1, box.x2, box.y2)); 90703b705cfSriastradh 90803b705cfSriastradh if (box.x1 < 0) 90903b705cfSriastradh box.x1 = 0; 91003b705cfSriastradh if (box.y1 < 0) 91103b705cfSriastradh box.y1 = 0; 91203b705cfSriastradh 91303b705cfSriastradh if (bo->tiling) { 91403b705cfSriastradh int tile_width, tile_height, tile_size; 91503b705cfSriastradh 91642542f5fSchristos kgem_get_tile_size(&sna->kgem, bo->tiling, bo->pitch, 91703b705cfSriastradh &tile_width, &tile_height, &tile_size); 91803b705cfSriastradh DBG(("%s: tile size for tiling %d: %dx%d, size=%d\n", 91903b705cfSriastradh __FUNCTION__, bo->tiling, tile_width, tile_height, tile_size)); 92003b705cfSriastradh 92103b705cfSriastradh /* Ensure we align to an even tile row */ 92203b705cfSriastradh box.y1 = box.y1 & ~(2*tile_height - 1); 92303b705cfSriastradh box.y2 = ALIGN(box.y2, 2*tile_height); 92403b705cfSriastradh 92542542f5fSchristos assert(tile_width * 8 >= draw->bitsPerPixel); 92642542f5fSchristos box.x1 = box.x1 & ~(tile_width * 8 / draw->bitsPerPixel - 1); 92742542f5fSchristos box.x2 = ALIGN(box.x2, tile_width * 8 / draw->bitsPerPixel); 92803b705cfSriastradh 92942542f5fSchristos offset = box.x1 * draw->bitsPerPixel / 8 / tile_width * tile_size; 93003b705cfSriastradh } else { 93103b705cfSriastradh box.y1 = box.y1 & ~1; 93203b705cfSriastradh box.y2 = ALIGN(box.y2, 2); 93303b705cfSriastradh 93403b705cfSriastradh box.x1 = box.x1 & ~1; 93503b705cfSriastradh box.x2 = ALIGN(box.x2, 2); 93603b705cfSriastradh 93742542f5fSchristos offset = box.x1 * draw->bitsPerPixel / 8; 93803b705cfSriastradh } 93903b705cfSriastradh 94042542f5fSchristos if (box.x2 > draw->width) 94142542f5fSchristos box.x2 = draw->width; 94242542f5fSchristos if (box.y2 > draw->height) 94342542f5fSchristos box.y2 = draw->height; 94403b705cfSriastradh 94503b705cfSriastradh w = box.x2 - box.x1; 94603b705cfSriastradh h = box.y2 - box.y1; 94703b705cfSriastradh DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d)\n", __FUNCTION__, 94803b705cfSriastradh box.x1, box.y1, box.x2, box.y2, w, h, 94942542f5fSchristos draw->width, draw->height)); 95003b705cfSriastradh if (w <= 0 || h <= 0 || 95103b705cfSriastradh w > sna->render.max_3d_size || 95203b705cfSriastradh h > sna->render.max_3d_size) { 95303b705cfSriastradh DBG(("%s: box too large (%dx%d) for 3D pipeline (max %d)\n", 95403b705cfSriastradh __FUNCTION__, w, h, sna->render.max_3d_size)); 95503b705cfSriastradh return false; 95603b705cfSriastradh } 95703b705cfSriastradh 95803b705cfSriastradh /* How many tiles across are we? */ 95903b705cfSriastradh channel->bo = kgem_create_proxy(&sna->kgem, bo, 96003b705cfSriastradh box.y1 * bo->pitch + offset, 96103b705cfSriastradh h * bo->pitch); 96242542f5fSchristos if (channel->bo == NULL) { 96342542f5fSchristos DBG(("%s: failed to create proxy for partial (offset=%d, size=%d)\n", 96442542f5fSchristos __FUNCTION__, box.y1 * bo->pitch + offset, h * bo->pitch)); 96503b705cfSriastradh return false; 96642542f5fSchristos } 96703b705cfSriastradh 96803b705cfSriastradh channel->bo->pitch = bo->pitch; 96903b705cfSriastradh 97003b705cfSriastradh channel->offset[0] = -box.x1; 97103b705cfSriastradh channel->offset[1] = -box.y1; 97203b705cfSriastradh channel->scale[0] = 1.f/w; 97303b705cfSriastradh channel->scale[1] = 1.f/h; 97403b705cfSriastradh channel->width = w; 97503b705cfSriastradh channel->height = h; 97603b705cfSriastradh return true; 97703b705cfSriastradh} 97803b705cfSriastradh 97942542f5fSchristosstatic bool 98003b705cfSriastradhsna_render_picture_partial(struct sna *sna, 98103b705cfSriastradh PicturePtr picture, 98203b705cfSriastradh struct sna_composite_channel *channel, 98303b705cfSriastradh int16_t x, int16_t y, 98403b705cfSriastradh int16_t w, int16_t h, 98503b705cfSriastradh int16_t dst_x, int16_t dst_y) 98603b705cfSriastradh{ 98703b705cfSriastradh struct kgem_bo *bo = NULL; 98803b705cfSriastradh PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable); 98903b705cfSriastradh BoxRec box; 99003b705cfSriastradh int offset; 99103b705cfSriastradh 99203b705cfSriastradh DBG(("%s (%d, %d)x(%d, %d) [dst=(%d, %d)]\n", 99303b705cfSriastradh __FUNCTION__, x, y, w, h, dst_x, dst_y)); 99403b705cfSriastradh 99503b705cfSriastradh box.x1 = x; 99603b705cfSriastradh box.y1 = y; 99703b705cfSriastradh box.x2 = bound(x, w); 99803b705cfSriastradh box.y2 = bound(y, h); 99903b705cfSriastradh if (channel->transform) 100003b705cfSriastradh pixman_transform_bounds(channel->transform, &box); 100103b705cfSriastradh 100203b705cfSriastradh DBG(("%s sample=(%d, %d), (%d, %d): (%d, %d)/(%d, %d), repeat=%d\n", __FUNCTION__, 100303b705cfSriastradh box.x1, box.y1, box.x2, box.y2, w, h, 100403b705cfSriastradh pixmap->drawable.width, pixmap->drawable.height, 100503b705cfSriastradh channel->repeat)); 100603b705cfSriastradh 100703b705cfSriastradh if (channel->repeat == RepeatNone || channel->repeat == RepeatPad) { 100803b705cfSriastradh if (box.x1 < 0) 100903b705cfSriastradh box.x1 = 0; 101003b705cfSriastradh if (box.y1 < 0) 101103b705cfSriastradh box.y1 = 0; 101203b705cfSriastradh if (box.x2 > pixmap->drawable.width) 101303b705cfSriastradh box.x2 = pixmap->drawable.width; 101403b705cfSriastradh if (box.y2 > pixmap->drawable.height) 101503b705cfSriastradh box.y2 = pixmap->drawable.height; 101603b705cfSriastradh } else { 101703b705cfSriastradh if (box.x1 < 0 || box.x2 > pixmap->drawable.width) 101803b705cfSriastradh box.x1 = 0, box.x2 = pixmap->drawable.width; 101903b705cfSriastradh if (box.y1 < 0 || box.y2 > pixmap->drawable.height) 102003b705cfSriastradh box.y1 = 0, box.y2 = pixmap->drawable.height; 102103b705cfSriastradh } 102203b705cfSriastradh 102303b705cfSriastradh if (use_cpu_bo(sna, pixmap, &box, false)) { 102403b705cfSriastradh bo = sna_pixmap(pixmap)->cpu_bo; 102503b705cfSriastradh } else { 102603b705cfSriastradh struct sna_pixmap *priv; 102703b705cfSriastradh 102803b705cfSriastradh priv = sna_pixmap_force_to_gpu(pixmap, 102913496ba1Ssnj MOVE_READ | MOVE_ASYNC_HINT | MOVE_SOURCE_HINT); 103003b705cfSriastradh if (priv == NULL) 103142542f5fSchristos return false; 103203b705cfSriastradh 103303b705cfSriastradh bo = priv->gpu_bo; 103403b705cfSriastradh } 103503b705cfSriastradh 103642542f5fSchristos if (bo->pitch > sna->render.max_3d_pitch) { 103742542f5fSchristos DBG(("%s: pitch too great %d > %d\n", __FUNCTION__, bo->pitch, sna->render.max_3d_pitch)); 103842542f5fSchristos return false; 103942542f5fSchristos } 104003b705cfSriastradh 104103b705cfSriastradh if (bo->tiling) { 104203b705cfSriastradh int tile_width, tile_height, tile_size; 104303b705cfSriastradh 104442542f5fSchristos kgem_get_tile_size(&sna->kgem, bo->tiling, bo->pitch, 104503b705cfSriastradh &tile_width, &tile_height, &tile_size); 104603b705cfSriastradh 104703b705cfSriastradh DBG(("%s: tiling=%d, size=%dx%d, chunk=%d\n", 104803b705cfSriastradh __FUNCTION__, bo->tiling, 104903b705cfSriastradh tile_width, tile_height, tile_size)); 105003b705cfSriastradh 105103b705cfSriastradh /* Ensure we align to an even tile row */ 105203b705cfSriastradh box.y1 = box.y1 & ~(2*tile_height - 1); 105303b705cfSriastradh box.y2 = ALIGN(box.y2, 2*tile_height); 105403b705cfSriastradh if (box.y2 > pixmap->drawable.height) 105503b705cfSriastradh box.y2 = pixmap->drawable.height; 105603b705cfSriastradh 105703b705cfSriastradh box.x1 = box.x1 & ~(tile_width * 8 / pixmap->drawable.bitsPerPixel - 1); 105803b705cfSriastradh box.x2 = ALIGN(box.x2, tile_width * 8 / pixmap->drawable.bitsPerPixel); 105903b705cfSriastradh if (box.x2 > pixmap->drawable.width) 106003b705cfSriastradh box.x2 = pixmap->drawable.width; 106103b705cfSriastradh 106203b705cfSriastradh offset = box.x1 * pixmap->drawable.bitsPerPixel / 8 / tile_width * tile_size; 106303b705cfSriastradh } else 106403b705cfSriastradh offset = box.x1 * pixmap->drawable.bitsPerPixel / 8; 106503b705cfSriastradh 106603b705cfSriastradh w = box.x2 - box.x1; 106703b705cfSriastradh h = box.y2 - box.y1; 106803b705cfSriastradh DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d)\n", __FUNCTION__, 106903b705cfSriastradh box.x1, box.y1, box.x2, box.y2, w, h, 107003b705cfSriastradh pixmap->drawable.width, pixmap->drawable.height)); 107103b705cfSriastradh if (w <= 0 || h <= 0 || 107203b705cfSriastradh w > sna->render.max_3d_size || 107303b705cfSriastradh h > sna->render.max_3d_size) 107442542f5fSchristos return false; 107503b705cfSriastradh 107603b705cfSriastradh /* How many tiles across are we? */ 107703b705cfSriastradh channel->bo = kgem_create_proxy(&sna->kgem, bo, 107803b705cfSriastradh box.y1 * bo->pitch + offset, 107903b705cfSriastradh h * bo->pitch); 108003b705cfSriastradh if (channel->bo == NULL) 108142542f5fSchristos return false; 108203b705cfSriastradh 108303b705cfSriastradh if (channel->transform) { 108403b705cfSriastradh memset(&channel->embedded_transform, 108503b705cfSriastradh 0, 108603b705cfSriastradh sizeof(channel->embedded_transform)); 108703b705cfSriastradh channel->embedded_transform.matrix[0][0] = 1 << 16; 108803b705cfSriastradh channel->embedded_transform.matrix[0][2] = -box.x1 << 16; 108903b705cfSriastradh channel->embedded_transform.matrix[1][1] = 1 << 16; 109003b705cfSriastradh channel->embedded_transform.matrix[1][2] = -box.y1 << 16; 109103b705cfSriastradh channel->embedded_transform.matrix[2][2] = 1 << 16; 109203b705cfSriastradh pixman_transform_multiply(&channel->embedded_transform, 109303b705cfSriastradh &channel->embedded_transform, 109403b705cfSriastradh channel->transform); 109503b705cfSriastradh channel->transform = &channel->embedded_transform; 109603b705cfSriastradh } else { 109703b705cfSriastradh x -= box.x1; 109803b705cfSriastradh y -= box.y1; 109903b705cfSriastradh } 110003b705cfSriastradh 110103b705cfSriastradh channel->offset[0] = x - dst_x; 110203b705cfSriastradh channel->offset[1] = y - dst_y; 110303b705cfSriastradh channel->scale[0] = 1.f/w; 110403b705cfSriastradh channel->scale[1] = 1.f/h; 110503b705cfSriastradh channel->width = w; 110603b705cfSriastradh channel->height = h; 110742542f5fSchristos return true; 110803b705cfSriastradh} 110903b705cfSriastradh 111003b705cfSriastradhint 111103b705cfSriastradhsna_render_picture_extract(struct sna *sna, 111203b705cfSriastradh PicturePtr picture, 111303b705cfSriastradh struct sna_composite_channel *channel, 111403b705cfSriastradh int16_t x, int16_t y, 111503b705cfSriastradh int16_t w, int16_t h, 111603b705cfSriastradh int16_t dst_x, int16_t dst_y) 111703b705cfSriastradh{ 111803b705cfSriastradh struct kgem_bo *bo = NULL, *src_bo; 111903b705cfSriastradh PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable); 112003b705cfSriastradh int16_t ox, oy, ow, oh; 112103b705cfSriastradh BoxRec box; 112203b705cfSriastradh 112303b705cfSriastradh#if NO_EXTRACT 112403b705cfSriastradh return -1; 112503b705cfSriastradh#endif 112603b705cfSriastradh 112703b705cfSriastradh DBG(("%s (%d, %d)x(%d, %d) [dst=(%d, %d)]\n", 112803b705cfSriastradh __FUNCTION__, x, y, w, h, dst_x, dst_y)); 112903b705cfSriastradh 113003b705cfSriastradh if (w == 0 || h == 0) { 113103b705cfSriastradh DBG(("%s: fallback -- unknown bounds\n", __FUNCTION__)); 113203b705cfSriastradh return -1; 113303b705cfSriastradh } 113403b705cfSriastradh 113503b705cfSriastradh if (sna_render_picture_partial(sna, picture, channel, 113603b705cfSriastradh x, y, w, h, 113703b705cfSriastradh dst_x, dst_y)) 113803b705cfSriastradh return 1; 113903b705cfSriastradh 114003b705cfSriastradh ow = w; 114103b705cfSriastradh oh = h; 114203b705cfSriastradh 114303b705cfSriastradh ox = box.x1 = x; 114403b705cfSriastradh oy = box.y1 = y; 114503b705cfSriastradh box.x2 = bound(x, w); 114603b705cfSriastradh box.y2 = bound(y, h); 114703b705cfSriastradh if (channel->transform) { 114803b705cfSriastradh pixman_vector_t v; 114903b705cfSriastradh 115003b705cfSriastradh pixman_transform_bounds(channel->transform, &box); 115103b705cfSriastradh 115203b705cfSriastradh v.vector[0] = ox << 16; 115303b705cfSriastradh v.vector[1] = oy << 16; 115403b705cfSriastradh v.vector[2] = 1 << 16; 115503b705cfSriastradh pixman_transform_point(channel->transform, &v); 115603b705cfSriastradh ox = v.vector[0] / v.vector[2]; 115703b705cfSriastradh oy = v.vector[1] / v.vector[2]; 115803b705cfSriastradh } 115903b705cfSriastradh 116003b705cfSriastradh DBG(("%s sample=(%d, %d), (%d, %d): (%d, %d)/(%d, %d), repeat=%d\n", __FUNCTION__, 116103b705cfSriastradh box.x1, box.y1, box.x2, box.y2, w, h, 116203b705cfSriastradh pixmap->drawable.width, pixmap->drawable.height, 116303b705cfSriastradh channel->repeat)); 116403b705cfSriastradh 116503b705cfSriastradh if (channel->repeat == RepeatNone || channel->repeat == RepeatPad) { 116603b705cfSriastradh if (box.x1 < 0) 116703b705cfSriastradh box.x1 = 0; 116803b705cfSriastradh if (box.y1 < 0) 116903b705cfSriastradh box.y1 = 0; 117003b705cfSriastradh if (box.x2 > pixmap->drawable.width) 117103b705cfSriastradh box.x2 = pixmap->drawable.width; 117203b705cfSriastradh if (box.y2 > pixmap->drawable.height) 117303b705cfSriastradh box.y2 = pixmap->drawable.height; 117403b705cfSriastradh } else { 117503b705cfSriastradh /* XXX tiled repeats? */ 117603b705cfSriastradh if (box.x1 < 0 || box.x2 > pixmap->drawable.width) 117703b705cfSriastradh box.x1 = 0, box.x2 = pixmap->drawable.width; 117803b705cfSriastradh if (box.y1 < 0 || box.y2 > pixmap->drawable.height) 117903b705cfSriastradh box.y1 = 0, box.y2 = pixmap->drawable.height; 118003b705cfSriastradh } 118103b705cfSriastradh 118203b705cfSriastradh w = box.x2 - box.x1; 118303b705cfSriastradh h = box.y2 - box.y1; 118403b705cfSriastradh DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d)\n", __FUNCTION__, 118503b705cfSriastradh box.x1, box.y1, box.x2, box.y2, w, h, 118603b705cfSriastradh pixmap->drawable.width, pixmap->drawable.height)); 118703b705cfSriastradh if (w <= 0 || h <= 0) { 118803b705cfSriastradh DBG(("%s: sample extents outside of texture -> clear\n", 118903b705cfSriastradh __FUNCTION__)); 119003b705cfSriastradh return 0; 119103b705cfSriastradh } 119203b705cfSriastradh 119303b705cfSriastradh if (w > sna->render.max_3d_size || h > sna->render.max_3d_size) { 119403b705cfSriastradh DBG(("%s: fallback -- sample too large for texture (%d, %d)x(%d, %d)\n", 119503b705cfSriastradh __FUNCTION__, box.x1, box.y1, w, h)); 119603b705cfSriastradh return sna_render_picture_downsample(sna, picture, channel, 119703b705cfSriastradh x, y, ow, oh, 119803b705cfSriastradh dst_x, dst_y); 119903b705cfSriastradh } 120003b705cfSriastradh 120103b705cfSriastradh src_bo = use_cpu_bo(sna, pixmap, &box, true); 120242542f5fSchristos if (src_bo == NULL) 120303b705cfSriastradh src_bo = move_to_gpu(pixmap, &box, false); 120403b705cfSriastradh if (src_bo) { 120503b705cfSriastradh bo = kgem_create_2d(&sna->kgem, w, h, 120603b705cfSriastradh pixmap->drawable.bitsPerPixel, 120703b705cfSriastradh kgem_choose_tiling(&sna->kgem, 120803b705cfSriastradh I915_TILING_X, w, h, 120903b705cfSriastradh pixmap->drawable.bitsPerPixel), 121003b705cfSriastradh CREATE_TEMPORARY); 121103b705cfSriastradh if (bo) { 121242542f5fSchristos DrawableRec tmp; 121303b705cfSriastradh 121442542f5fSchristos tmp.width = w; 121542542f5fSchristos tmp.height = h; 121642542f5fSchristos tmp.depth = pixmap->drawable.depth; 121742542f5fSchristos tmp.bitsPerPixel = pixmap->drawable.bitsPerPixel; 121803b705cfSriastradh 121942542f5fSchristos assert(tmp.width); 122042542f5fSchristos assert(tmp.height); 122103b705cfSriastradh 122203b705cfSriastradh if (!sna->render.copy_boxes(sna, GXcopy, 122342542f5fSchristos &pixmap->drawable, src_bo, 0, 0, 122403b705cfSriastradh &tmp, bo, -box.x1, -box.y1, 122503b705cfSriastradh &box, 1, 0)) { 122603b705cfSriastradh kgem_bo_destroy(&sna->kgem, bo); 122703b705cfSriastradh bo = NULL; 122803b705cfSriastradh } 122903b705cfSriastradh } 123042542f5fSchristos } else { 123142542f5fSchristos struct sna_pixmap *priv = sna_pixmap(pixmap); 123242542f5fSchristos if (priv) { 123342542f5fSchristos RegionRec region; 123442542f5fSchristos 123542542f5fSchristos region.extents = box; 123642542f5fSchristos region.data = NULL; 123742542f5fSchristos if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, 123842542f5fSchristos ®ion, MOVE_READ)) 123942542f5fSchristos return 0; 124042542f5fSchristos 124142542f5fSchristos assert(!priv->mapped); 124242542f5fSchristos if (pixmap->devPrivate.ptr == NULL) 124342542f5fSchristos return 0; /* uninitialised */ 124442542f5fSchristos } 124542542f5fSchristos 124642542f5fSchristos bo = kgem_upload_source_image(&sna->kgem, 124742542f5fSchristos pixmap->devPrivate.ptr, 124842542f5fSchristos &box, 124942542f5fSchristos pixmap->devKind, 125042542f5fSchristos pixmap->drawable.bitsPerPixel); 125142542f5fSchristos if (priv != NULL && bo != NULL && 125242542f5fSchristos box.x2 - box.x1 == pixmap->drawable.width && 125342542f5fSchristos box.y2 - box.y1 == pixmap->drawable.height) { 125442542f5fSchristos DBG(("%s: adding upload cache to pixmap=%ld\n", 125542542f5fSchristos __FUNCTION__, pixmap->drawable.serialNumber)); 125642542f5fSchristos assert(priv->gpu_damage == NULL); 125742542f5fSchristos assert(priv->gpu_bo == NULL); 125842542f5fSchristos assert(bo->proxy != NULL); 1259fe8aea9eSmrg sna_damage_all(&priv->cpu_damage, pixmap); 126042542f5fSchristos kgem_proxy_bo_attach(bo, &priv->gpu_bo); 126142542f5fSchristos } 126203b705cfSriastradh } 126303b705cfSriastradh 126403b705cfSriastradh if (bo == NULL) { 126503b705cfSriastradh DBG(("%s: falback -- pixmap is not on the GPU\n", 126603b705cfSriastradh __FUNCTION__)); 126703b705cfSriastradh return sna_render_picture_fixup(sna, picture, channel, 126803b705cfSriastradh x, y, ow, oh, dst_x, dst_y); 126903b705cfSriastradh } 127003b705cfSriastradh 127103b705cfSriastradh if (ox == x && oy == y) { 127203b705cfSriastradh x = y = 0; 127303b705cfSriastradh } else if (channel->transform) { 127403b705cfSriastradh pixman_vector_t v; 127503b705cfSriastradh pixman_transform_t m; 127603b705cfSriastradh 127703b705cfSriastradh v.vector[0] = (ox - box.x1) << 16; 127803b705cfSriastradh v.vector[1] = (oy - box.y1) << 16; 127903b705cfSriastradh v.vector[2] = 1 << 16; 128003b705cfSriastradh pixman_transform_invert(&m, channel->transform); 128103b705cfSriastradh pixman_transform_point(&m, &v); 128203b705cfSriastradh x = v.vector[0] / v.vector[2]; 128303b705cfSriastradh y = v.vector[1] / v.vector[2]; 128403b705cfSriastradh } else { 128503b705cfSriastradh x = ox - box.x1; 128603b705cfSriastradh y = oy - box.y1; 128703b705cfSriastradh } 128803b705cfSriastradh 128903b705cfSriastradh channel->offset[0] = x - dst_x; 129003b705cfSriastradh channel->offset[1] = y - dst_y; 129103b705cfSriastradh channel->scale[0] = 1.f/w; 129203b705cfSriastradh channel->scale[1] = 1.f/h; 129303b705cfSriastradh channel->width = w; 129403b705cfSriastradh channel->height = h; 129503b705cfSriastradh channel->bo = bo; 129603b705cfSriastradh return 1; 129703b705cfSriastradh} 129803b705cfSriastradh 129903b705cfSriastradhstatic int 130003b705cfSriastradhsna_render_picture_convolve(struct sna *sna, 130103b705cfSriastradh PicturePtr picture, 130203b705cfSriastradh struct sna_composite_channel *channel, 130303b705cfSriastradh int16_t x, int16_t y, 130403b705cfSriastradh int16_t w, int16_t h, 130503b705cfSriastradh int16_t dst_x, int16_t dst_y) 130603b705cfSriastradh{ 130703b705cfSriastradh ScreenPtr screen = picture->pDrawable->pScreen; 130803b705cfSriastradh PixmapPtr pixmap; 130903b705cfSriastradh PicturePtr tmp; 131003b705cfSriastradh pixman_fixed_t *params = picture->filter_params; 131103b705cfSriastradh int x_off = -pixman_fixed_to_int((params[0] - pixman_fixed_1) >> 1); 131203b705cfSriastradh int y_off = -pixman_fixed_to_int((params[1] - pixman_fixed_1) >> 1); 131303b705cfSriastradh int cw = pixman_fixed_to_int(params[0]); 131403b705cfSriastradh int ch = pixman_fixed_to_int(params[1]); 131503b705cfSriastradh int i, j, error, depth; 131603b705cfSriastradh struct kgem_bo *bo; 131703b705cfSriastradh 131803b705cfSriastradh /* Lame multi-pass accumulation implementation of a general convolution 131903b705cfSriastradh * that works everywhere. 132003b705cfSriastradh */ 132103b705cfSriastradh DBG(("%s: origin=(%d,%d) kernel=%dx%d, size=%dx%d\n", 132203b705cfSriastradh __FUNCTION__, x_off, y_off, cw, ch, w, h)); 1323fe8aea9eSmrg if (cw*ch > 32) /* too much loss of precision from quantization! */ 1324fe8aea9eSmrg return -1; 132503b705cfSriastradh 132603b705cfSriastradh assert(picture->pDrawable); 132703b705cfSriastradh assert(picture->filter == PictFilterConvolution); 132803b705cfSriastradh assert(w <= sna->render.max_3d_size && h <= sna->render.max_3d_size); 132903b705cfSriastradh 133003b705cfSriastradh if (PICT_FORMAT_RGB(picture->format) == 0) { 133103b705cfSriastradh channel->pict_format = PIXMAN_a8; 133203b705cfSriastradh depth = 8; 133303b705cfSriastradh } else { 133403b705cfSriastradh channel->pict_format = PIXMAN_a8r8g8b8; 133503b705cfSriastradh depth = 32; 133603b705cfSriastradh } 133703b705cfSriastradh 133803b705cfSriastradh pixmap = screen->CreatePixmap(screen, w, h, depth, SNA_CREATE_SCRATCH); 133942542f5fSchristos if (pixmap == NullPixmap) { 134042542f5fSchristos DBG(("%s: pixmap allocation failed\n", __FUNCTION__)); 134142542f5fSchristos return -1; 134242542f5fSchristos } 134303b705cfSriastradh 134442542f5fSchristos tmp = NULL; 134542542f5fSchristos bo = __sna_pixmap_get_bo(pixmap); 134642542f5fSchristos assert(bo); 134742542f5fSchristos if (sna->render.clear(sna, pixmap, bo)) 134842542f5fSchristos tmp = CreatePicture(0, &pixmap->drawable, 134942542f5fSchristos PictureMatchFormat(screen, depth, channel->pict_format), 135042542f5fSchristos 0, NULL, serverClient, &error); 135103b705cfSriastradh screen->DestroyPixmap(pixmap); 135203b705cfSriastradh if (tmp == NULL) 135342542f5fSchristos return -1; 135403b705cfSriastradh 135503b705cfSriastradh ValidatePicture(tmp); 135603b705cfSriastradh 135703b705cfSriastradh picture->filter = PictFilterBilinear; 135803b705cfSriastradh params += 2; 135903b705cfSriastradh for (j = 0; j < ch; j++) { 136003b705cfSriastradh for (i = 0; i < cw; i++) { 136103b705cfSriastradh xRenderColor color; 136203b705cfSriastradh PicturePtr alpha; 136303b705cfSriastradh 136403b705cfSriastradh color.alpha = *params++; 136503b705cfSriastradh color.red = color.green = color.blue = 0; 136603b705cfSriastradh DBG(("%s: (%d, %d), alpha=%x\n", 136703b705cfSriastradh __FUNCTION__, i,j, color.alpha)); 136803b705cfSriastradh 136903b705cfSriastradh if (color.alpha <= 0x00ff) 137003b705cfSriastradh continue; 137103b705cfSriastradh 137203b705cfSriastradh alpha = CreateSolidPicture(0, &color, &error); 137303b705cfSriastradh if (alpha) { 137403b705cfSriastradh sna_composite(PictOpAdd, picture, alpha, tmp, 1375fe8aea9eSmrg x-(x_off+i), y-(y_off+j), 1376fe8aea9eSmrg 0, 0, 137703b705cfSriastradh 0, 0, 137803b705cfSriastradh w, h); 137903b705cfSriastradh FreePicture(alpha, 0); 138003b705cfSriastradh } 138103b705cfSriastradh } 138203b705cfSriastradh } 138303b705cfSriastradh picture->filter = PictFilterConvolution; 138403b705cfSriastradh 138503b705cfSriastradh channel->height = h; 138603b705cfSriastradh channel->width = w; 138703b705cfSriastradh channel->filter = PictFilterNearest; 138803b705cfSriastradh channel->repeat = RepeatNone; 138903b705cfSriastradh channel->is_affine = true; 139003b705cfSriastradh channel->transform = NULL; 139103b705cfSriastradh channel->scale[0] = 1.f / w; 139203b705cfSriastradh channel->scale[1] = 1.f / h; 139303b705cfSriastradh channel->offset[0] = -dst_x; 139403b705cfSriastradh channel->offset[1] = -dst_y; 139503b705cfSriastradh channel->bo = kgem_bo_reference(bo); /* transfer ownership */ 139603b705cfSriastradh FreePicture(tmp, 0); 139703b705cfSriastradh 139803b705cfSriastradh return 1; 139903b705cfSriastradh} 140003b705cfSriastradh 140142542f5fSchristosstatic bool 140203b705cfSriastradhsna_render_picture_flatten(struct sna *sna, 140303b705cfSriastradh PicturePtr picture, 140403b705cfSriastradh struct sna_composite_channel *channel, 140503b705cfSriastradh int16_t x, int16_t y, 140603b705cfSriastradh int16_t w, int16_t h, 140703b705cfSriastradh int16_t dst_x, int16_t dst_y) 140803b705cfSriastradh{ 140903b705cfSriastradh ScreenPtr screen = picture->pDrawable->pScreen; 141003b705cfSriastradh PixmapPtr pixmap; 141103b705cfSriastradh PicturePtr tmp, alpha; 141203b705cfSriastradh int old_format, error; 141303b705cfSriastradh 141403b705cfSriastradh assert(picture->pDrawable); 141503b705cfSriastradh assert(picture->alphaMap); 141603b705cfSriastradh assert(w <= sna->render.max_3d_size && h <= sna->render.max_3d_size); 141703b705cfSriastradh 141803b705cfSriastradh /* XXX shortcut a8? */ 141903b705cfSriastradh DBG(("%s: %dx%d\n", __FUNCTION__, w, h)); 142003b705cfSriastradh 142103b705cfSriastradh pixmap = screen->CreatePixmap(screen, w, h, 32, SNA_CREATE_SCRATCH); 142242542f5fSchristos if (pixmap == NullPixmap) { 142342542f5fSchristos DBG(("%s: pixmap allocation failed\n", __FUNCTION__)); 142442542f5fSchristos return false; 142542542f5fSchristos } 142642542f5fSchristos 142742542f5fSchristos assert(__sna_pixmap_get_bo(pixmap)); 142803b705cfSriastradh 142903b705cfSriastradh tmp = CreatePicture(0, &pixmap->drawable, 143003b705cfSriastradh PictureMatchFormat(screen, 32, PICT_a8r8g8b8), 143103b705cfSriastradh 0, NULL, serverClient, &error); 143203b705cfSriastradh screen->DestroyPixmap(pixmap); 143303b705cfSriastradh if (tmp == NULL) 143442542f5fSchristos return false; 143503b705cfSriastradh 143603b705cfSriastradh ValidatePicture(tmp); 143703b705cfSriastradh 143803b705cfSriastradh old_format = picture->format; 143903b705cfSriastradh picture->format = PICT_FORMAT(PICT_FORMAT_BPP(picture->format), 144003b705cfSriastradh PICT_FORMAT_TYPE(picture->format), 144103b705cfSriastradh 0, 144203b705cfSriastradh PICT_FORMAT_R(picture->format), 144303b705cfSriastradh PICT_FORMAT_G(picture->format), 144403b705cfSriastradh PICT_FORMAT_B(picture->format)); 144503b705cfSriastradh 144603b705cfSriastradh alpha = picture->alphaMap; 144703b705cfSriastradh picture->alphaMap = NULL; 144803b705cfSriastradh 144903b705cfSriastradh sna_composite(PictOpSrc, picture, alpha, tmp, 145003b705cfSriastradh x, y, 145103b705cfSriastradh x + picture->alphaOrigin.x, y + picture->alphaOrigin.y, 145203b705cfSriastradh 0, 0, 145303b705cfSriastradh w, h); 145403b705cfSriastradh 145503b705cfSriastradh picture->format = old_format; 145603b705cfSriastradh picture->alphaMap = alpha; 145703b705cfSriastradh 145803b705cfSriastradh channel->height = h; 145903b705cfSriastradh channel->width = w; 146003b705cfSriastradh channel->filter = PictFilterNearest; 146103b705cfSriastradh channel->repeat = RepeatNone; 146203b705cfSriastradh channel->pict_format = PIXMAN_a8r8g8b8; 146303b705cfSriastradh channel->is_affine = true; 146403b705cfSriastradh channel->transform = NULL; 146503b705cfSriastradh channel->scale[0] = 1.f / w; 146603b705cfSriastradh channel->scale[1] = 1.f / h; 146703b705cfSriastradh channel->offset[0] = -dst_x; 146803b705cfSriastradh channel->offset[1] = -dst_y; 146903b705cfSriastradh channel->bo = kgem_bo_reference(__sna_pixmap_get_bo(pixmap)); 147003b705cfSriastradh FreePicture(tmp, 0); 147103b705cfSriastradh 147242542f5fSchristos return true; 147303b705cfSriastradh} 147403b705cfSriastradh 147503b705cfSriastradhint 147603b705cfSriastradhsna_render_picture_approximate_gradient(struct sna *sna, 147703b705cfSriastradh PicturePtr picture, 147803b705cfSriastradh struct sna_composite_channel *channel, 147903b705cfSriastradh int16_t x, int16_t y, 148003b705cfSriastradh int16_t w, int16_t h, 148103b705cfSriastradh int16_t dst_x, int16_t dst_y) 148203b705cfSriastradh{ 148303b705cfSriastradh pixman_image_t *dst, *src; 148403b705cfSriastradh pixman_transform_t t; 148503b705cfSriastradh int w2 = w/2, h2 = h/2; 148603b705cfSriastradh int dx, dy; 148703b705cfSriastradh void *ptr; 148803b705cfSriastradh 148903b705cfSriastradh#if NO_FIXUP 149003b705cfSriastradh return -1; 149103b705cfSriastradh#endif 149203b705cfSriastradh 149303b705cfSriastradh DBG(("%s: (%d, %d)x(%d, %d), dst=(%d, %d)\n", 149403b705cfSriastradh __FUNCTION__, x, y, w, h, dst_x, dst_y)); 149503b705cfSriastradh 149603b705cfSriastradh if (w2 == 0 || h2 == 0) { 149703b705cfSriastradh DBG(("%s: fallback - unknown bounds\n", __FUNCTION__)); 149803b705cfSriastradh return -1; 149903b705cfSriastradh } 150003b705cfSriastradh if (w2 > sna->render.max_3d_size || h2 > sna->render.max_3d_size) { 150103b705cfSriastradh DBG(("%s: fallback - too large (%dx%d)\n", __FUNCTION__, w, h)); 150203b705cfSriastradh return -1; 150303b705cfSriastradh } 150403b705cfSriastradh 150503b705cfSriastradh channel->is_opaque = sna_gradient_is_opaque((PictGradient*)picture->pSourcePict); 150603b705cfSriastradh channel->pict_format = 150703b705cfSriastradh channel->is_opaque ? PIXMAN_x8r8g8b8 : PIXMAN_a8r8g8b8; 150803b705cfSriastradh DBG(("%s: gradient is opaque? %d, selecting format %08x\n", 150903b705cfSriastradh __FUNCTION__, channel->is_opaque, channel->pict_format)); 151003b705cfSriastradh assert(channel->card_format == -1); 151103b705cfSriastradh 151203b705cfSriastradh channel->bo = kgem_create_buffer_2d(&sna->kgem, 151303b705cfSriastradh w2, h2, 32, 151403b705cfSriastradh KGEM_BUFFER_WRITE_INPLACE, 151503b705cfSriastradh &ptr); 151603b705cfSriastradh if (!channel->bo) { 151703b705cfSriastradh DBG(("%s: failed to create upload buffer, using clear\n", 151803b705cfSriastradh __FUNCTION__)); 151903b705cfSriastradh return 0; 152003b705cfSriastradh } 152103b705cfSriastradh 152203b705cfSriastradh dst = pixman_image_create_bits(channel->pict_format, 152303b705cfSriastradh w2, h2, ptr, channel->bo->pitch); 152403b705cfSriastradh if (!dst) { 152503b705cfSriastradh kgem_bo_destroy(&sna->kgem, channel->bo); 152603b705cfSriastradh channel->bo = NULL; 152703b705cfSriastradh return 0; 152803b705cfSriastradh } 152903b705cfSriastradh 153003b705cfSriastradh src = image_from_pict(picture, false, &dx, &dy); 153103b705cfSriastradh if (src == NULL) { 153203b705cfSriastradh pixman_image_unref(dst); 153303b705cfSriastradh kgem_bo_destroy(&sna->kgem, channel->bo); 153403b705cfSriastradh channel->bo = NULL; 153503b705cfSriastradh return 0; 153603b705cfSriastradh } 153703b705cfSriastradh DBG(("%s: source offset (%d, %d)\n", __FUNCTION__, dx, dy)); 153803b705cfSriastradh 153903b705cfSriastradh memset(&t, 0, sizeof(t)); 154003b705cfSriastradh t.matrix[0][0] = (w << 16) / w2; 154103b705cfSriastradh t.matrix[0][2] = (x + dx) << 16; 154203b705cfSriastradh t.matrix[1][1] = (h << 16) / h2; 154303b705cfSriastradh t.matrix[1][2] = (y + dy) << 16; 154403b705cfSriastradh t.matrix[2][2] = 1 << 16; 154503b705cfSriastradh if (picture->transform) 154603b705cfSriastradh pixman_transform_multiply(&t, picture->transform, &t); 154703b705cfSriastradh DBG(("%s: applying transform [(%f, %f, %f), (%f, %f, %f), (%f, %f, %f)]\n", 154803b705cfSriastradh __FUNCTION__, 154903b705cfSriastradh pixman_fixed_to_double(t.matrix[0][0]), 155003b705cfSriastradh pixman_fixed_to_double(t.matrix[0][1]), 155103b705cfSriastradh pixman_fixed_to_double(t.matrix[0][2]), 155203b705cfSriastradh pixman_fixed_to_double(t.matrix[1][0]), 155303b705cfSriastradh pixman_fixed_to_double(t.matrix[1][1]), 155403b705cfSriastradh pixman_fixed_to_double(t.matrix[1][2]), 155503b705cfSriastradh pixman_fixed_to_double(t.matrix[2][0]), 155603b705cfSriastradh pixman_fixed_to_double(t.matrix[2][1]), 155703b705cfSriastradh pixman_fixed_to_double(t.matrix[2][2]))); 155803b705cfSriastradh pixman_image_set_transform(src, &t); 155903b705cfSriastradh 156003b705cfSriastradh sna_image_composite(PictOpSrc, src, NULL, dst, 156103b705cfSriastradh 0, 0, 156203b705cfSriastradh 0, 0, 156303b705cfSriastradh 0, 0, 156403b705cfSriastradh w2, h2); 156503b705cfSriastradh free_pixman_pict(picture, src); 156603b705cfSriastradh pixman_image_unref(dst); 156703b705cfSriastradh 156803b705cfSriastradh channel->width = w2; 156903b705cfSriastradh channel->height = h2; 157003b705cfSriastradh 157103b705cfSriastradh channel->filter = PictFilterNearest; 157203b705cfSriastradh channel->repeat = RepeatNone; 157303b705cfSriastradh channel->is_affine = true; 157403b705cfSriastradh 157503b705cfSriastradh channel->scale[0] = 1.f/w; 157603b705cfSriastradh channel->scale[1] = 1.f/h; 157703b705cfSriastradh channel->offset[0] = -dst_x; 157803b705cfSriastradh channel->offset[1] = -dst_y; 157903b705cfSriastradh channel->transform = NULL; 158003b705cfSriastradh 158103b705cfSriastradh return 1; 158203b705cfSriastradh} 158303b705cfSriastradh 158403b705cfSriastradhint 158503b705cfSriastradhsna_render_picture_fixup(struct sna *sna, 158603b705cfSriastradh PicturePtr picture, 158703b705cfSriastradh struct sna_composite_channel *channel, 158803b705cfSriastradh int16_t x, int16_t y, 158903b705cfSriastradh int16_t w, int16_t h, 159003b705cfSriastradh int16_t dst_x, int16_t dst_y) 159103b705cfSriastradh{ 159203b705cfSriastradh pixman_image_t *dst, *src; 159303b705cfSriastradh int dx, dy; 159403b705cfSriastradh void *ptr; 159503b705cfSriastradh 159603b705cfSriastradh#if NO_FIXUP 159703b705cfSriastradh return -1; 159803b705cfSriastradh#endif 159903b705cfSriastradh 160003b705cfSriastradh DBG(("%s: (%d, %d)x(%d, %d)\n", __FUNCTION__, x, y, w, h)); 160103b705cfSriastradh 160203b705cfSriastradh if (w == 0 || h == 0) { 160303b705cfSriastradh DBG(("%s: fallback - unknown bounds\n", __FUNCTION__)); 160403b705cfSriastradh return -1; 160503b705cfSriastradh } 160603b705cfSriastradh if (w > sna->render.max_3d_size || h > sna->render.max_3d_size) { 160703b705cfSriastradh DBG(("%s: fallback - too large (%dx%d)\n", __FUNCTION__, w, h)); 160803b705cfSriastradh return -1; 160903b705cfSriastradh } 161003b705cfSriastradh 161103b705cfSriastradh if (picture->alphaMap) { 161203b705cfSriastradh DBG(("%s: alphamap\n", __FUNCTION__)); 161303b705cfSriastradh if (is_gpu(sna, picture->pDrawable, PREFER_GPU_RENDER) || 161403b705cfSriastradh is_gpu(sna, picture->alphaMap->pDrawable, PREFER_GPU_RENDER)) { 161542542f5fSchristos if (sna_render_picture_flatten(sna, picture, channel, 161642542f5fSchristos x, y, w, h, dst_x, dst_y)) 161742542f5fSchristos return 1; 161803b705cfSriastradh } 161903b705cfSriastradh 162003b705cfSriastradh goto do_fixup; 162103b705cfSriastradh } 162203b705cfSriastradh 162303b705cfSriastradh if (picture->filter == PictFilterConvolution) { 162403b705cfSriastradh DBG(("%s: convolution\n", __FUNCTION__)); 162503b705cfSriastradh if (is_gpu(sna, picture->pDrawable, PREFER_GPU_RENDER)) { 162603b705cfSriastradh return sna_render_picture_convolve(sna, picture, channel, 162703b705cfSriastradh x, y, w, h, dst_x, dst_y); 162803b705cfSriastradh } 162903b705cfSriastradh 163003b705cfSriastradh goto do_fixup; 163103b705cfSriastradh } 163203b705cfSriastradh 163303b705cfSriastradhdo_fixup: 163403b705cfSriastradh if (PICT_FORMAT_RGB(picture->format) == 0) 163503b705cfSriastradh channel->pict_format = PIXMAN_a8; 163603b705cfSriastradh else 163703b705cfSriastradh channel->pict_format = PIXMAN_a8r8g8b8; 163803b705cfSriastradh 163903b705cfSriastradh if (picture->pDrawable && 164003b705cfSriastradh !sna_drawable_move_to_cpu(picture->pDrawable, MOVE_READ)) 164103b705cfSriastradh return 0; 164203b705cfSriastradh 164303b705cfSriastradh channel->bo = kgem_create_buffer_2d(&sna->kgem, 164403b705cfSriastradh w, h, PIXMAN_FORMAT_BPP(channel->pict_format), 164503b705cfSriastradh KGEM_BUFFER_WRITE_INPLACE, 164603b705cfSriastradh &ptr); 164703b705cfSriastradh if (!channel->bo) { 164803b705cfSriastradh DBG(("%s: failed to create upload buffer, using clear\n", 164903b705cfSriastradh __FUNCTION__)); 165003b705cfSriastradh return 0; 165103b705cfSriastradh } 165203b705cfSriastradh 165303b705cfSriastradh /* Composite in the original format to preserve idiosyncracies */ 165403b705cfSriastradh if (!kgem_buffer_is_inplace(channel->bo) && 165503b705cfSriastradh (picture->pDrawable == NULL || 165603b705cfSriastradh alphaless(picture->format) == alphaless(channel->pict_format))) 165703b705cfSriastradh dst = pixman_image_create_bits(channel->pict_format, 165803b705cfSriastradh w, h, ptr, channel->bo->pitch); 165903b705cfSriastradh else 166042542f5fSchristos dst = pixman_image_create_bits((pixman_format_code_t)picture->format, 166142542f5fSchristos w, h, NULL, 0); 166203b705cfSriastradh if (!dst) { 166303b705cfSriastradh kgem_bo_destroy(&sna->kgem, channel->bo); 166403b705cfSriastradh return 0; 166503b705cfSriastradh } 166603b705cfSriastradh 166703b705cfSriastradh src = image_from_pict(picture, false, &dx, &dy); 166803b705cfSriastradh if (src == NULL) { 166903b705cfSriastradh pixman_image_unref(dst); 167003b705cfSriastradh kgem_bo_destroy(&sna->kgem, channel->bo); 167103b705cfSriastradh return 0; 167203b705cfSriastradh } 167303b705cfSriastradh 167403b705cfSriastradh DBG(("%s: compositing tmp=(%d+%d, %d+%d)x(%d, %d)\n", 167503b705cfSriastradh __FUNCTION__, x, dx, y, dy, w, h)); 167603b705cfSriastradh sna_image_composite(PictOpSrc, src, NULL, dst, 167703b705cfSriastradh x + dx, y + dy, 167803b705cfSriastradh 0, 0, 167903b705cfSriastradh 0, 0, 168003b705cfSriastradh w, h); 168103b705cfSriastradh free_pixman_pict(picture, src); 168203b705cfSriastradh 168303b705cfSriastradh /* Then convert to card format */ 168403b705cfSriastradh if (pixman_image_get_data(dst) != ptr) { 168503b705cfSriastradh DBG(("%s: performing post-conversion %08x->%08x (%d, %d)\n", 168603b705cfSriastradh __FUNCTION__, 168703b705cfSriastradh picture->format, channel->pict_format, 168803b705cfSriastradh w, h)); 168903b705cfSriastradh 169003b705cfSriastradh src = dst; 169103b705cfSriastradh dst = pixman_image_create_bits(channel->pict_format, 169203b705cfSriastradh w, h, ptr, channel->bo->pitch); 169303b705cfSriastradh if (dst) { 169442542f5fSchristos sna_image_composite(PictOpSrc, src, NULL, dst, 169542542f5fSchristos 0, 0, 169642542f5fSchristos 0, 0, 169742542f5fSchristos 0, 0, 169842542f5fSchristos w, h); 169903b705cfSriastradh pixman_image_unref(src); 170003b705cfSriastradh } else { 170103b705cfSriastradh memset(ptr, 0, __kgem_buffer_size(channel->bo)); 170203b705cfSriastradh dst = src; 170303b705cfSriastradh } 170403b705cfSriastradh } 170503b705cfSriastradh pixman_image_unref(dst); 170603b705cfSriastradh 170703b705cfSriastradh channel->width = w; 170803b705cfSriastradh channel->height = h; 170903b705cfSriastradh 171003b705cfSriastradh channel->filter = PictFilterNearest; 171103b705cfSriastradh channel->repeat = RepeatNone; 171203b705cfSriastradh channel->is_affine = true; 171303b705cfSriastradh 171403b705cfSriastradh channel->scale[0] = 1.f/w; 171503b705cfSriastradh channel->scale[1] = 1.f/h; 171603b705cfSriastradh channel->offset[0] = -dst_x; 171703b705cfSriastradh channel->offset[1] = -dst_y; 171803b705cfSriastradh channel->transform = NULL; 171903b705cfSriastradh 172003b705cfSriastradh return 1; 172103b705cfSriastradh} 172203b705cfSriastradh 172303b705cfSriastradhint 172403b705cfSriastradhsna_render_picture_convert(struct sna *sna, 172503b705cfSriastradh PicturePtr picture, 172603b705cfSriastradh struct sna_composite_channel *channel, 172703b705cfSriastradh PixmapPtr pixmap, 172803b705cfSriastradh int16_t x, int16_t y, 172903b705cfSriastradh int16_t w, int16_t h, 173003b705cfSriastradh int16_t dst_x, int16_t dst_y, 173103b705cfSriastradh bool fixup_alpha) 173203b705cfSriastradh{ 173303b705cfSriastradh BoxRec box; 173403b705cfSriastradh 173503b705cfSriastradh#if NO_CONVERT 173603b705cfSriastradh return -1; 173703b705cfSriastradh#endif 173803b705cfSriastradh 173903b705cfSriastradh if (w != 0 && h != 0) { 174003b705cfSriastradh box.x1 = x; 174103b705cfSriastradh box.y1 = y; 174203b705cfSriastradh box.x2 = bound(x, w); 174303b705cfSriastradh box.y2 = bound(y, h); 174403b705cfSriastradh 174503b705cfSriastradh if (channel->transform) { 174603b705cfSriastradh DBG(("%s: has transform, converting whole surface\n", 174703b705cfSriastradh __FUNCTION__)); 174803b705cfSriastradh box.x1 = box.y1 = 0; 174903b705cfSriastradh box.x2 = pixmap->drawable.width; 175003b705cfSriastradh box.y2 = pixmap->drawable.height; 175103b705cfSriastradh } 175203b705cfSriastradh 175303b705cfSriastradh if (box.x1 < 0) 175403b705cfSriastradh box.x1 = 0; 175503b705cfSriastradh if (box.y1 < 0) 175603b705cfSriastradh box.y1 = 0; 175703b705cfSriastradh if (box.x2 > pixmap->drawable.width) 175803b705cfSriastradh box.x2 = pixmap->drawable.width; 175903b705cfSriastradh if (box.y2 > pixmap->drawable.height) 176003b705cfSriastradh box.y2 = pixmap->drawable.height; 176103b705cfSriastradh } else { 176203b705cfSriastradh DBG(("%s: op no bounds, converting whole surface\n", 176303b705cfSriastradh __FUNCTION__)); 176403b705cfSriastradh box.x1 = box.y1 = 0; 176503b705cfSriastradh box.x2 = pixmap->drawable.width; 176603b705cfSriastradh box.y2 = pixmap->drawable.height; 176703b705cfSriastradh } 176803b705cfSriastradh 176903b705cfSriastradh w = box.x2 - box.x1; 177003b705cfSriastradh h = box.y2 - box.y1; 177103b705cfSriastradh 177203b705cfSriastradh DBG(("%s: convert (%d, %d)x(%d, %d), source size %dx%d\n", 177303b705cfSriastradh __FUNCTION__, box.x1, box.y1, w, h, 177403b705cfSriastradh pixmap->drawable.width, 177503b705cfSriastradh pixmap->drawable.height)); 177603b705cfSriastradh 177703b705cfSriastradh if (w <= 0 || h <= 0) { 177803b705cfSriastradh DBG(("%s: sample extents lie outside of source, using clear\n", 177903b705cfSriastradh __FUNCTION__)); 178003b705cfSriastradh return 0; 178103b705cfSriastradh } 178203b705cfSriastradh 178303b705cfSriastradh if (fixup_alpha && is_gpu(sna, &pixmap->drawable, PREFER_GPU_RENDER)) { 178403b705cfSriastradh ScreenPtr screen = pixmap->drawable.pScreen; 178503b705cfSriastradh PixmapPtr tmp; 178603b705cfSriastradh PicturePtr src, dst; 178703b705cfSriastradh int error; 178803b705cfSriastradh 178903b705cfSriastradh assert(PICT_FORMAT_BPP(picture->format) == pixmap->drawable.bitsPerPixel); 179003b705cfSriastradh channel->pict_format = PICT_FORMAT(PICT_FORMAT_BPP(picture->format), 179103b705cfSriastradh PICT_FORMAT_TYPE(picture->format), 179203b705cfSriastradh PICT_FORMAT_BPP(picture->format) - PIXMAN_FORMAT_DEPTH(picture->format), 179303b705cfSriastradh PICT_FORMAT_R(picture->format), 179403b705cfSriastradh PICT_FORMAT_G(picture->format), 179503b705cfSriastradh PICT_FORMAT_B(picture->format)); 179603b705cfSriastradh 179703b705cfSriastradh DBG(("%s: converting to %08x from %08x using composite alpha-fixup\n", 179803b705cfSriastradh __FUNCTION__, 179903b705cfSriastradh (unsigned)channel->pict_format, 180003b705cfSriastradh (unsigned)picture->format)); 180103b705cfSriastradh 180242542f5fSchristos tmp = screen->CreatePixmap(screen, w, h, pixmap->drawable.bitsPerPixel, SNA_CREATE_SCRATCH); 180303b705cfSriastradh if (tmp == NULL) 180442542f5fSchristos return -1; 180542542f5fSchristos 180642542f5fSchristos assert(__sna_pixmap_get_bo(tmp)); 180703b705cfSriastradh 180803b705cfSriastradh dst = CreatePicture(0, &tmp->drawable, 180903b705cfSriastradh PictureMatchFormat(screen, 181003b705cfSriastradh pixmap->drawable.bitsPerPixel, 181103b705cfSriastradh channel->pict_format), 181203b705cfSriastradh 0, NULL, serverClient, &error); 181303b705cfSriastradh if (dst == NULL) { 181403b705cfSriastradh screen->DestroyPixmap(tmp); 181503b705cfSriastradh return 0; 181603b705cfSriastradh } 181703b705cfSriastradh 181803b705cfSriastradh src = CreatePicture(0, &pixmap->drawable, 181903b705cfSriastradh PictureMatchFormat(screen, 182003b705cfSriastradh pixmap->drawable.depth, 182103b705cfSriastradh picture->format), 182203b705cfSriastradh 0, NULL, serverClient, &error); 182303b705cfSriastradh if (src == NULL) { 182403b705cfSriastradh FreePicture(dst, 0); 182503b705cfSriastradh screen->DestroyPixmap(tmp); 182603b705cfSriastradh return 0; 182703b705cfSriastradh } 182803b705cfSriastradh 182903b705cfSriastradh ValidatePicture(src); 183003b705cfSriastradh ValidatePicture(dst); 183103b705cfSriastradh 183203b705cfSriastradh sna_composite(PictOpSrc, src, NULL, dst, 183303b705cfSriastradh box.x1, box.y1, 183403b705cfSriastradh 0, 0, 183503b705cfSriastradh 0, 0, 183603b705cfSriastradh w, h); 183703b705cfSriastradh FreePicture(dst, 0); 183803b705cfSriastradh FreePicture(src, 0); 183903b705cfSriastradh 184003b705cfSriastradh channel->bo = __sna_pixmap_get_bo(tmp); 184103b705cfSriastradh kgem_bo_reference(channel->bo); 184203b705cfSriastradh screen->DestroyPixmap(tmp); 184303b705cfSriastradh } else { 184403b705cfSriastradh pixman_image_t *src, *dst; 184503b705cfSriastradh void *ptr; 184603b705cfSriastradh 184703b705cfSriastradh if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ)) 184803b705cfSriastradh return 0; 184903b705cfSriastradh 185042542f5fSchristos src = pixman_image_create_bits((pixman_format_code_t)picture->format, 185103b705cfSriastradh pixmap->drawable.width, 185203b705cfSriastradh pixmap->drawable.height, 185303b705cfSriastradh pixmap->devPrivate.ptr, 185403b705cfSriastradh pixmap->devKind); 185503b705cfSriastradh if (!src) 185603b705cfSriastradh return 0; 185703b705cfSriastradh 185803b705cfSriastradh if (PICT_FORMAT_RGB(picture->format) == 0) { 185903b705cfSriastradh channel->pict_format = PIXMAN_a8; 186003b705cfSriastradh DBG(("%s: converting to a8 from %08x\n", 186103b705cfSriastradh __FUNCTION__, picture->format)); 186203b705cfSriastradh } else { 186303b705cfSriastradh channel->pict_format = PIXMAN_a8r8g8b8; 186403b705cfSriastradh DBG(("%s: converting to a8r8g8b8 from %08x\n", 186503b705cfSriastradh __FUNCTION__, picture->format)); 186603b705cfSriastradh } 186703b705cfSriastradh 186803b705cfSriastradh channel->bo = kgem_create_buffer_2d(&sna->kgem, 186903b705cfSriastradh w, h, PIXMAN_FORMAT_BPP(channel->pict_format), 187003b705cfSriastradh KGEM_BUFFER_WRITE_INPLACE, 187103b705cfSriastradh &ptr); 187203b705cfSriastradh if (!channel->bo) { 187303b705cfSriastradh pixman_image_unref(src); 187403b705cfSriastradh return 0; 187503b705cfSriastradh } 187603b705cfSriastradh 187703b705cfSriastradh dst = pixman_image_create_bits(channel->pict_format, 187803b705cfSriastradh w, h, ptr, channel->bo->pitch); 187903b705cfSriastradh if (!dst) { 188003b705cfSriastradh kgem_bo_destroy(&sna->kgem, channel->bo); 188103b705cfSriastradh pixman_image_unref(src); 188203b705cfSriastradh return 0; 188303b705cfSriastradh } 188403b705cfSriastradh 188542542f5fSchristos if (sigtrap_get() == 0) { 188642542f5fSchristos sna_image_composite(PictOpSrc, src, NULL, dst, 188742542f5fSchristos box.x1, box.y1, 188842542f5fSchristos 0, 0, 188942542f5fSchristos 0, 0, 189042542f5fSchristos w, h); 189142542f5fSchristos sigtrap_put(); 189242542f5fSchristos } 189303b705cfSriastradh pixman_image_unref(dst); 189403b705cfSriastradh pixman_image_unref(src); 189503b705cfSriastradh } 189603b705cfSriastradh 189703b705cfSriastradh channel->width = w; 189803b705cfSriastradh channel->height = h; 189903b705cfSriastradh 190003b705cfSriastradh channel->scale[0] = 1.f/w; 190103b705cfSriastradh channel->scale[1] = 1.f/h; 190203b705cfSriastradh channel->offset[0] = x - dst_x - box.x1; 190303b705cfSriastradh channel->offset[1] = y - dst_y - box.y1; 190403b705cfSriastradh 190503b705cfSriastradh DBG(("%s: offset=(%d, %d), size=(%d, %d)\n", 190603b705cfSriastradh __FUNCTION__, 190703b705cfSriastradh channel->offset[0], channel->offset[1], 190803b705cfSriastradh channel->width, channel->height)); 190903b705cfSriastradh return 1; 191003b705cfSriastradh} 191103b705cfSriastradh 191203b705cfSriastradhbool 191303b705cfSriastradhsna_render_composite_redirect(struct sna *sna, 191403b705cfSriastradh struct sna_composite_op *op, 191503b705cfSriastradh int x, int y, int width, int height, 191603b705cfSriastradh bool partial) 191703b705cfSriastradh{ 191803b705cfSriastradh struct sna_composite_redirect *t = &op->redirect; 191903b705cfSriastradh int bpp = op->dst.pixmap->drawable.bitsPerPixel; 192003b705cfSriastradh struct kgem_bo *bo; 192103b705cfSriastradh 192203b705cfSriastradh assert(t->real_bo == NULL); 192303b705cfSriastradh 192403b705cfSriastradh#if NO_REDIRECT 192503b705cfSriastradh return false; 192603b705cfSriastradh#endif 192703b705cfSriastradh 192803b705cfSriastradh DBG(("%s: target too large (%dx%d), copying to temporary %dx%d, max %d / %d\n", 192903b705cfSriastradh __FUNCTION__, 193003b705cfSriastradh op->dst.width, op->dst.height, 193103b705cfSriastradh width, height, 193203b705cfSriastradh sna->render.max_3d_size, 193303b705cfSriastradh sna->render.max_3d_pitch)); 193403b705cfSriastradh 193503b705cfSriastradh if (!width || !height) 193603b705cfSriastradh return false; 193703b705cfSriastradh 193803b705cfSriastradh if (width > sna->render.max_3d_size || 193903b705cfSriastradh height > sna->render.max_3d_size) 194003b705cfSriastradh return false; 194103b705cfSriastradh 194203b705cfSriastradh if (op->dst.bo->pitch <= sna->render.max_3d_pitch) { 194303b705cfSriastradh BoxRec box; 194403b705cfSriastradh int w, h, offset; 194503b705cfSriastradh 194603b705cfSriastradh DBG(("%s: dst pitch (%d) fits within render pipeline (%d)\n", 194703b705cfSriastradh __FUNCTION__, op->dst.bo->pitch, sna->render.max_3d_pitch)); 194803b705cfSriastradh 194903b705cfSriastradh box.x1 = x + op->dst.x; 195003b705cfSriastradh box.x2 = bound(box.x1, width); 195103b705cfSriastradh box.y1 = y + op->dst.y; 195203b705cfSriastradh box.y2 = bound(box.y1, height); 195303b705cfSriastradh 195403b705cfSriastradh if (box.x1 < 0) 195503b705cfSriastradh box.x1 = 0; 195603b705cfSriastradh if (box.y1 < 0) 195703b705cfSriastradh box.y1 = 0; 195803b705cfSriastradh 195903b705cfSriastradh /* Ensure we align to an even tile row */ 196003b705cfSriastradh if (op->dst.bo->tiling) { 196103b705cfSriastradh int tile_width, tile_height, tile_size; 196203b705cfSriastradh 196342542f5fSchristos kgem_get_tile_size(&sna->kgem, op->dst.bo->tiling, op->dst.bo->pitch, 196403b705cfSriastradh &tile_width, &tile_height, &tile_size); 196503b705cfSriastradh 196603b705cfSriastradh box.y1 = box.y1 & ~(2*tile_height - 1); 196703b705cfSriastradh box.y2 = ALIGN(box.y2, 2*tile_height); 196803b705cfSriastradh 196903b705cfSriastradh box.x1 = box.x1 & ~(tile_width * 8 / op->dst.pixmap->drawable.bitsPerPixel - 1); 197003b705cfSriastradh box.x2 = ALIGN(box.x2, tile_width * 8 / op->dst.pixmap->drawable.bitsPerPixel); 197103b705cfSriastradh 197213496ba1Ssnj if (box.x1 > sna->render.max_3d_size && 197313496ba1Ssnj box.x2 <= 2*sna->render.max_3d_size) 197413496ba1Ssnj box.x1 = sna->render.max_3d_size; 197513496ba1Ssnj 197613496ba1Ssnj if (box.y1 > sna->render.max_3d_size && 197713496ba1Ssnj box.y2 <= 2*sna->render.max_3d_size) 197813496ba1Ssnj box.y1 = sna->render.max_3d_size; 197913496ba1Ssnj 198003b705cfSriastradh offset = box.x1 * op->dst.pixmap->drawable.bitsPerPixel / 8 / tile_width * tile_size; 198103b705cfSriastradh } else { 198203b705cfSriastradh if (sna->kgem.gen < 040) { 198303b705cfSriastradh box.y1 = box.y1 & ~3; 198403b705cfSriastradh box.y2 = ALIGN(box.y2, 4); 198503b705cfSriastradh 198603b705cfSriastradh box.x1 = box.x1 & ~3; 198703b705cfSriastradh box.x2 = ALIGN(box.x2, 4); 198803b705cfSriastradh } else { 198903b705cfSriastradh box.y1 = box.y1 & ~1; 199003b705cfSriastradh box.y2 = ALIGN(box.y2, 2); 199103b705cfSriastradh 199203b705cfSriastradh box.x1 = box.x1 & ~1; 199303b705cfSriastradh box.x2 = ALIGN(box.x2, 2); 199403b705cfSriastradh } 199503b705cfSriastradh 199613496ba1Ssnj if (box.x1 > sna->render.max_3d_size && 199713496ba1Ssnj box.x2 <= 2*sna->render.max_3d_size) 199813496ba1Ssnj box.x1 = sna->render.max_3d_size; 199913496ba1Ssnj 200013496ba1Ssnj if (box.y1 > sna->render.max_3d_size && 200113496ba1Ssnj box.y2 <= 2*sna->render.max_3d_size) 200213496ba1Ssnj box.y1 = sna->render.max_3d_size; 200313496ba1Ssnj 200403b705cfSriastradh offset = box.x1 * op->dst.pixmap->drawable.bitsPerPixel / 8; 200503b705cfSriastradh } 200603b705cfSriastradh 200703b705cfSriastradh if (box.y2 > op->dst.pixmap->drawable.height) 200803b705cfSriastradh box.y2 = op->dst.pixmap->drawable.height; 200903b705cfSriastradh 201003b705cfSriastradh if (box.x2 > op->dst.pixmap->drawable.width) 201103b705cfSriastradh box.x2 = op->dst.pixmap->drawable.width; 201203b705cfSriastradh 201303b705cfSriastradh w = box.x2 - box.x1; 201403b705cfSriastradh h = box.y2 - box.y1; 201503b705cfSriastradh DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d), max %d\n", __FUNCTION__, 201603b705cfSriastradh box.x1, box.y1, box.x2, box.y2, w, h, 201703b705cfSriastradh op->dst.pixmap->drawable.width, 201803b705cfSriastradh op->dst.pixmap->drawable.height, 201903b705cfSriastradh sna->render.max_3d_size)); 202003b705cfSriastradh if (w <= sna->render.max_3d_size && 202103b705cfSriastradh h <= sna->render.max_3d_size) { 202203b705cfSriastradh t->box.x2 = t->box.x1 = op->dst.x; 202303b705cfSriastradh t->box.y2 = t->box.y1 = op->dst.y; 202403b705cfSriastradh t->real_bo = op->dst.bo; 202503b705cfSriastradh t->real_damage = op->damage; 202603b705cfSriastradh if (op->damage) { 202703b705cfSriastradh assert(!DAMAGE_IS_ALL(op->damage)); 202803b705cfSriastradh t->damage = sna_damage_create(); 202903b705cfSriastradh op->damage = &t->damage; 203003b705cfSriastradh } 203103b705cfSriastradh 203203b705cfSriastradh /* How many tiles across are we? */ 203303b705cfSriastradh op->dst.bo = kgem_create_proxy(&sna->kgem, op->dst.bo, 203403b705cfSriastradh box.y1 * op->dst.bo->pitch + offset, 203503b705cfSriastradh h * op->dst.bo->pitch); 203603b705cfSriastradh if (!op->dst.bo) { 203703b705cfSriastradh t->real_bo = NULL; 203803b705cfSriastradh if (t->damage) 203903b705cfSriastradh __sna_damage_destroy(t->damage); 204003b705cfSriastradh return false; 204103b705cfSriastradh } 204203b705cfSriastradh 204303b705cfSriastradh assert(op->dst.bo != t->real_bo); 204403b705cfSriastradh op->dst.bo->pitch = t->real_bo->pitch; 204503b705cfSriastradh 204603b705cfSriastradh op->dst.x -= box.x1; 204703b705cfSriastradh op->dst.y -= box.y1; 204803b705cfSriastradh op->dst.width = w; 204903b705cfSriastradh op->dst.height = h; 205003b705cfSriastradh return true; 205103b705cfSriastradh } 205203b705cfSriastradh } 205303b705cfSriastradh 205403b705cfSriastradh /* We can process the operation in a single pass, 205503b705cfSriastradh * but the target is too large for the 3D pipeline. 205603b705cfSriastradh * Copy into a smaller surface and replace afterwards. 205703b705cfSriastradh */ 205803b705cfSriastradh bo = kgem_create_2d(&sna->kgem, 205903b705cfSriastradh width, height, bpp, 206003b705cfSriastradh kgem_choose_tiling(&sna->kgem, I915_TILING_X, 206103b705cfSriastradh width, height, bpp), 206203b705cfSriastradh CREATE_TEMPORARY); 206303b705cfSriastradh if (!bo) 206403b705cfSriastradh return false; 206503b705cfSriastradh 206603b705cfSriastradh t->box.x1 = x + op->dst.x; 206703b705cfSriastradh t->box.y1 = y + op->dst.y; 206803b705cfSriastradh t->box.x2 = bound(t->box.x1, width); 206903b705cfSriastradh t->box.y2 = bound(t->box.y1, height); 207003b705cfSriastradh 207103b705cfSriastradh DBG(("%s: original box (%d, %d), (%d, %d)\n", 207203b705cfSriastradh __FUNCTION__, t->box.x1, t->box.y1, t->box.x2, t->box.y2)); 207303b705cfSriastradh 207403b705cfSriastradh if (partial && 207503b705cfSriastradh !sna_blt_copy_boxes(sna, GXcopy, 207603b705cfSriastradh op->dst.bo, 0, 0, 207703b705cfSriastradh bo, -t->box.x1, -t->box.y1, 207803b705cfSriastradh bpp, &t->box, 1)) { 207903b705cfSriastradh kgem_bo_destroy(&sna->kgem, bo); 208003b705cfSriastradh return false; 208103b705cfSriastradh } 208203b705cfSriastradh 208303b705cfSriastradh t->real_bo = op->dst.bo; 208403b705cfSriastradh t->real_damage = op->damage; 208503b705cfSriastradh if (op->damage) { 208603b705cfSriastradh assert(!DAMAGE_IS_ALL(op->damage)); 208703b705cfSriastradh t->damage = sna_damage_create(); 208803b705cfSriastradh op->damage = &t->damage; 208903b705cfSriastradh } 209003b705cfSriastradh 209103b705cfSriastradh op->dst.bo = bo; 209203b705cfSriastradh op->dst.x = -x; 209303b705cfSriastradh op->dst.y = -y; 209403b705cfSriastradh op->dst.width = width; 209503b705cfSriastradh op->dst.height = height; 209603b705cfSriastradh return true; 209703b705cfSriastradh} 209803b705cfSriastradh 209903b705cfSriastradhvoid 210003b705cfSriastradhsna_render_composite_redirect_done(struct sna *sna, 210103b705cfSriastradh const struct sna_composite_op *op) 210203b705cfSriastradh{ 210303b705cfSriastradh const struct sna_composite_redirect *t = &op->redirect; 210403b705cfSriastradh 210503b705cfSriastradh if (t->real_bo) { 210603b705cfSriastradh assert(op->dst.bo != t->real_bo); 210703b705cfSriastradh 210803b705cfSriastradh if (t->box.x2 > t->box.x1) { 210903b705cfSriastradh bool ok; 211003b705cfSriastradh 211103b705cfSriastradh DBG(("%s: copying temporary to dst\n", __FUNCTION__)); 211203b705cfSriastradh ok = sna_blt_copy_boxes(sna, GXcopy, 211303b705cfSriastradh op->dst.bo, -t->box.x1, -t->box.y1, 211403b705cfSriastradh t->real_bo, 0, 0, 211503b705cfSriastradh op->dst.pixmap->drawable.bitsPerPixel, 211603b705cfSriastradh &t->box, 1); 211703b705cfSriastradh assert(ok); 211803b705cfSriastradh (void)ok; 211903b705cfSriastradh } 212003b705cfSriastradh if (t->damage) { 212103b705cfSriastradh DBG(("%s: combining damage (all? %d), offset=(%d, %d)\n", 212203b705cfSriastradh __FUNCTION__, (int)DAMAGE_IS_ALL(t->damage), 212303b705cfSriastradh t->box.x1, t->box.y1)); 212403b705cfSriastradh sna_damage_combine(t->real_damage, 212503b705cfSriastradh DAMAGE_PTR(t->damage), 212603b705cfSriastradh t->box.x1, t->box.y1); 212703b705cfSriastradh __sna_damage_destroy(DAMAGE_PTR(t->damage)); 212803b705cfSriastradh } 212903b705cfSriastradh 213003b705cfSriastradh kgem_bo_destroy(&sna->kgem, op->dst.bo); 213103b705cfSriastradh } 213203b705cfSriastradh} 213303b705cfSriastradh 213442542f5fSchristosstatic bool 213542542f5fSchristoscopy_overlap(struct sna *sna, uint8_t alu, 213642542f5fSchristos const DrawableRec *draw, struct kgem_bo *bo, 213742542f5fSchristos int16_t src_dx, int16_t src_dy, 213842542f5fSchristos int16_t dst_dx, int16_t dst_dy, 213942542f5fSchristos const BoxRec *box, int n, const BoxRec *extents) 214003b705cfSriastradh{ 214142542f5fSchristos ScreenPtr screen = draw->pScreen; 214242542f5fSchristos struct kgem_bo *tmp_bo; 214303b705cfSriastradh PixmapPtr tmp; 214403b705cfSriastradh bool ret = false; 214503b705cfSriastradh 214642542f5fSchristos if (n == 0) 214742542f5fSchristos return true; 214842542f5fSchristos 214942542f5fSchristos DBG(("%s: %d x %dx%d src=(%d, %d), dst=(%d, %d)\n", 215042542f5fSchristos __FUNCTION__, n, 215142542f5fSchristos extents->x2 - extents->x1, 215242542f5fSchristos extents->y2 - extents->y1, 215342542f5fSchristos src_dx, src_dy, 215442542f5fSchristos dst_dx, dst_dy)); 215542542f5fSchristos 215603b705cfSriastradh tmp = screen->CreatePixmap(screen, 215703b705cfSriastradh extents->x2 - extents->x1, 215803b705cfSriastradh extents->y2 - extents->y1, 215942542f5fSchristos draw->depth, 216003b705cfSriastradh SNA_CREATE_SCRATCH); 216103b705cfSriastradh if (tmp == NULL) 216203b705cfSriastradh return false; 216303b705cfSriastradh 216442542f5fSchristos tmp_bo = __sna_pixmap_get_bo(tmp); 216542542f5fSchristos assert(tmp_bo); 216603b705cfSriastradh 216742542f5fSchristos ret = (sna->render.copy_boxes(sna, GXcopy, 216842542f5fSchristos draw, bo, src_dx, src_dy, 216942542f5fSchristos &tmp->drawable, tmp_bo, -extents->x1, -extents->y1, 2170fe8aea9eSmrg box, n, 0) && 217103b705cfSriastradh sna->render.copy_boxes(sna, alu, 217242542f5fSchristos &tmp->drawable, tmp_bo, -extents->x1, -extents->y1, 217342542f5fSchristos draw, bo, dst_dx, dst_dy, 2174fe8aea9eSmrg box, n, 0)); 217503b705cfSriastradh 217603b705cfSriastradh screen->DestroyPixmap(tmp); 217703b705cfSriastradh return ret; 217803b705cfSriastradh} 217942542f5fSchristosbool 218042542f5fSchristossna_render_copy_boxes__overlap(struct sna *sna, uint8_t alu, 218142542f5fSchristos const DrawableRec *draw, struct kgem_bo *bo, 218242542f5fSchristos int16_t src_dx, int16_t src_dy, 218342542f5fSchristos int16_t dst_dx, int16_t dst_dy, 218442542f5fSchristos const BoxRec *box, int n, const BoxRec *extents) 218542542f5fSchristos{ 218642542f5fSchristos bool ret = false; 218742542f5fSchristos RegionRec overlap, non_overlap; 218842542f5fSchristos pixman_region16_t region; 218942542f5fSchristos pixman_box16_t stack_boxes[64], *boxes = stack_boxes; 219042542f5fSchristos int num_boxes, i; 219142542f5fSchristos 219242542f5fSchristos DBG(("%s: pixmap=%ld, handle=%d, %d x [(%d, %d), (%d, %d)], dst=(%d, %d), src=(%d, %d)\n", 219342542f5fSchristos __FUNCTION__, draw->serialNumber, bo->handle, 219442542f5fSchristos n, extents->x1, extents->y1, extents->x2, extents->y2, 219542542f5fSchristos src_dx, src_dy, dst_dx, dst_dy)); 219642542f5fSchristos 219742542f5fSchristos if ((dst_dx - src_dx < 4 && src_dx - dst_dx < 4) && 219842542f5fSchristos (dst_dy - src_dy < 4 && src_dy - dst_dy < 4)) 219942542f5fSchristos return copy_overlap(sna, alu, draw, bo, 220042542f5fSchristos src_dx, src_dy, 220142542f5fSchristos dst_dx, dst_dy, 220242542f5fSchristos box, n, extents); 220342542f5fSchristos 220442542f5fSchristos if (n > ARRAY_SIZE(stack_boxes)) { 220542542f5fSchristos boxes = malloc(sizeof(pixman_box16_t) * n); 220642542f5fSchristos if (boxes == NULL) 220742542f5fSchristos return copy_overlap(sna, alu, draw, bo, 220842542f5fSchristos src_dx, src_dy, 220942542f5fSchristos dst_dx, dst_dy, 221042542f5fSchristos box, n, extents); 221142542f5fSchristos } 221242542f5fSchristos 221342542f5fSchristos region.extents.x1 = extents->x1 + dst_dx; 221442542f5fSchristos region.extents.x2 = extents->x2 + dst_dx; 221542542f5fSchristos region.extents.y1 = extents->y1 + dst_dy; 221642542f5fSchristos region.extents.y2 = extents->y2 + dst_dy; 221742542f5fSchristos 221842542f5fSchristos for (i = num_boxes = 0; i < n; i++) { 221942542f5fSchristos boxes[num_boxes].x1 = box[i].x1 + dst_dx; 222042542f5fSchristos if (boxes[num_boxes].x1 < region.extents.x1) 222142542f5fSchristos boxes[num_boxes].x1 = region.extents.x1; 222242542f5fSchristos 222342542f5fSchristos boxes[num_boxes].y1 = box[i].y1 + dst_dy; 222442542f5fSchristos if (boxes[num_boxes].y1 < region.extents.y1) 222542542f5fSchristos boxes[num_boxes].y1 = region.extents.y1; 222642542f5fSchristos 222742542f5fSchristos boxes[num_boxes].x2 = box[i].x2 + dst_dx; 222842542f5fSchristos if (boxes[num_boxes].x2 > region.extents.x2) 222942542f5fSchristos boxes[num_boxes].x2 = region.extents.x2; 223042542f5fSchristos 223142542f5fSchristos boxes[num_boxes].y2 = box[i].y2 + dst_dy; 223242542f5fSchristos if (boxes[num_boxes].y2 > region.extents.y2) 223342542f5fSchristos boxes[num_boxes].y2 = region.extents.y2; 223442542f5fSchristos 223542542f5fSchristos if (boxes[num_boxes].x2 > boxes[num_boxes].x1 && 223642542f5fSchristos boxes[num_boxes].y2 > boxes[num_boxes].y1) 223742542f5fSchristos num_boxes++; 223842542f5fSchristos } 223942542f5fSchristos 224042542f5fSchristos if (num_boxes == 0) { 224142542f5fSchristos ret = true; 224242542f5fSchristos goto cleanup_boxes; 224342542f5fSchristos } 224442542f5fSchristos 224542542f5fSchristos if (!pixman_region_init_rects(®ion, boxes, num_boxes)) 224642542f5fSchristos goto cleanup_boxes; 224742542f5fSchristos 224842542f5fSchristos overlap.extents.x1 = extents->x1 + src_dx; 224942542f5fSchristos overlap.extents.x2 = extents->x2 + src_dx; 225042542f5fSchristos overlap.extents.y1 = extents->y1 + src_dy; 225142542f5fSchristos overlap.extents.y2 = extents->y2 + src_dy; 225242542f5fSchristos overlap.data = NULL; 225342542f5fSchristos 225442542f5fSchristos RegionIntersect(&overlap, &overlap, ®ion); 225542542f5fSchristos DBG(("%s: overlapping extents: (%d, %d), (%d, %d) x %d\n", 225642542f5fSchristos __FUNCTION__, 225742542f5fSchristos overlap.extents.x1, overlap.extents.y1, 225842542f5fSchristos overlap.extents.x2, overlap.extents.y2, 225942542f5fSchristos region_num_rects(&overlap))); 226042542f5fSchristos 226142542f5fSchristos RegionNull(&non_overlap); 226242542f5fSchristos RegionSubtract(&non_overlap, ®ion, &overlap); 226342542f5fSchristos DBG(("%s: non-overlapping extents: (%d, %d), (%d, %d) x %d\n", 226442542f5fSchristos __FUNCTION__, 226542542f5fSchristos non_overlap.extents.x1, non_overlap.extents.y1, 226642542f5fSchristos non_overlap.extents.x2, non_overlap.extents.y2, 226742542f5fSchristos region_num_rects(&non_overlap))); 226842542f5fSchristos 226942542f5fSchristos n = region_num_rects(&non_overlap); 227042542f5fSchristos box = region_rects(&non_overlap); 227142542f5fSchristos if (n && !sna->render.copy_boxes(sna, alu, 227242542f5fSchristos draw, bo, -dst_dx + src_dx, -dst_dy + src_dy, 227342542f5fSchristos draw, bo, 0, 0, 227442542f5fSchristos box, n , COPY_NO_OVERLAP)) 227542542f5fSchristos goto cleanup_boxes; 227642542f5fSchristos 227742542f5fSchristos n = region_num_rects(&overlap); 227842542f5fSchristos box = region_rects(&overlap); 227942542f5fSchristos ret = copy_overlap(sna, alu, draw, bo, 228042542f5fSchristos -dst_dx + src_dx, -dst_dy + src_dy, 228142542f5fSchristos 0, 0, 228242542f5fSchristos box, n, &overlap.extents); 228342542f5fSchristos 228442542f5fSchristoscleanup_boxes: 228542542f5fSchristos if (boxes != stack_boxes) 228642542f5fSchristos free(boxes); 228742542f5fSchristos 228842542f5fSchristos return ret; 228942542f5fSchristos} 229013496ba1Ssnj 229113496ba1Ssnjstatic bool can_copy_cpu(struct sna *sna, 229213496ba1Ssnj struct kgem_bo *src, 229313496ba1Ssnj struct kgem_bo *dst) 229413496ba1Ssnj{ 2295fe8aea9eSmrg DBG(("%s: tiling=%d:%d, pitch=%d:%d, can_map=%d:%d[%d]\n", 2296fe8aea9eSmrg __FUNCTION__, 2297fe8aea9eSmrg src->tiling, dst->tiling, 2298fe8aea9eSmrg src->pitch, dst->pitch, 2299fe8aea9eSmrg kgem_bo_can_map__cpu(&sna->kgem, src, false), 2300fe8aea9eSmrg kgem_bo_can_map__cpu(&sna->kgem, dst, true), 2301fe8aea9eSmrg sna->kgem.has_wc_mmap)); 230213496ba1Ssnj 2303fe8aea9eSmrg if (src->tiling != dst->tiling) 230413496ba1Ssnj return false; 230513496ba1Ssnj 230613496ba1Ssnj if (!kgem_bo_can_map__cpu(&sna->kgem, src, false)) 230713496ba1Ssnj return false; 230813496ba1Ssnj 2309fe8aea9eSmrg if (!kgem_bo_can_map__cpu(&sna->kgem, dst, true) && 2310fe8aea9eSmrg !sna->kgem.has_wc_mmap) 231113496ba1Ssnj return false; 231213496ba1Ssnj 231313496ba1Ssnj DBG(("%s -- yes, src handle=%d, dst handle=%d\n", __FUNCTION__, src->handle, dst->handle)); 231413496ba1Ssnj return true; 231513496ba1Ssnj} 231613496ba1Ssnj 231713496ba1Ssnjbool 231813496ba1Ssnjmemcpy_copy_boxes(struct sna *sna, uint8_t op, 231913496ba1Ssnj const DrawableRec *src_draw, struct kgem_bo *src_bo, int16_t sx, int16_t sy, 232013496ba1Ssnj const DrawableRec *dst_draw, struct kgem_bo *dst_bo, int16_t dx, int16_t dy, 232113496ba1Ssnj const BoxRec *box, int n, unsigned flags) 232213496ba1Ssnj{ 2323fe8aea9eSmrg memcpy_box_func detile = NULL; 232413496ba1Ssnj void *dst, *src; 232513496ba1Ssnj 232613496ba1Ssnj if (op != GXcopy) 232713496ba1Ssnj return false; 232813496ba1Ssnj 2329fe8aea9eSmrg if (src_draw->depth != dst_draw->depth) 2330fe8aea9eSmrg return false; 233113496ba1Ssnj 233213496ba1Ssnj dst = src = NULL; 2333fe8aea9eSmrg if (can_copy_cpu(sna, src_bo, dst_bo)) { 2334fe8aea9eSmrg if (src_bo->pitch != dst_bo->pitch || 2335fe8aea9eSmrg dx != sx || dy != sy || n > 1 || 2336fe8aea9eSmrg box->x1 + dx > 0 || 2337fe8aea9eSmrg box->y1 + dy > 0 || 2338fe8aea9eSmrg box->x2 + dx < dst_draw->width || 2339fe8aea9eSmrg box->y2 + dy < dst_draw->height) { 2340fe8aea9eSmrg if (dx != sx) /* not implemented in memcpy yet */ 2341fe8aea9eSmrg goto use_gtt; 2342fe8aea9eSmrg 2343fe8aea9eSmrg switch (dst_bo->tiling) { 2344fe8aea9eSmrg default: 2345fe8aea9eSmrg case I915_TILING_Y: 2346fe8aea9eSmrg goto use_gtt; 2347fe8aea9eSmrg 2348fe8aea9eSmrg case I915_TILING_X: 2349fe8aea9eSmrg detile = sna->kgem.memcpy_between_tiled_x; 2350fe8aea9eSmrg if (detile == NULL) 2351fe8aea9eSmrg goto use_gtt; 2352fe8aea9eSmrg break; 2353fe8aea9eSmrg 2354fe8aea9eSmrg case I915_TILING_NONE: 2355fe8aea9eSmrg break; 2356fe8aea9eSmrg } 2357fe8aea9eSmrg } 2358fe8aea9eSmrg 2359fe8aea9eSmrg if (kgem_bo_can_map__cpu(&sna->kgem, dst_bo, true)) 2360fe8aea9eSmrg dst = kgem_bo_map__cpu(&sna->kgem, dst_bo); 2361fe8aea9eSmrg else 2362fe8aea9eSmrg dst = kgem_bo_map__wc(&sna->kgem, dst_bo); 236313496ba1Ssnj src = kgem_bo_map__cpu(&sna->kgem, src_bo); 236413496ba1Ssnj } 236513496ba1Ssnj 236613496ba1Ssnj if (dst == NULL || src == NULL) { 2367fe8aea9eSmrguse_gtt: 236813496ba1Ssnj dst = kgem_bo_map__gtt(&sna->kgem, dst_bo); 236913496ba1Ssnj src = kgem_bo_map__gtt(&sna->kgem, src_bo); 237013496ba1Ssnj if (dst == NULL || src == NULL) 237113496ba1Ssnj return false; 2372fe8aea9eSmrg 2373fe8aea9eSmrg kgem_bo_sync__gtt(&sna->kgem, dst_bo); 2374fe8aea9eSmrg kgem_bo_sync__gtt(&sna->kgem, src_bo); 2375fe8aea9eSmrg 2376fe8aea9eSmrg detile = NULL; 237713496ba1Ssnj } else { 2378fe8aea9eSmrg if (dst == dst_bo->map__wc) 2379fe8aea9eSmrg kgem_bo_sync__gtt(&sna->kgem, dst_bo); 2380fe8aea9eSmrg else 2381fe8aea9eSmrg kgem_bo_sync__cpu_full(&sna->kgem, dst_bo, true); 238213496ba1Ssnj kgem_bo_sync__cpu_full(&sna->kgem, src_bo, false); 238313496ba1Ssnj } 238413496ba1Ssnj 238513496ba1Ssnj DBG(("%s: src(%d, %d), dst(%d, %d) x %d\n", 238613496ba1Ssnj __FUNCTION__, sx, sy, dx, dy, n)); 238713496ba1Ssnj 238813496ba1Ssnj if (sigtrap_get() == 0) { 2389fe8aea9eSmrg if (detile) { 2390fe8aea9eSmrg do { 2391fe8aea9eSmrg detile(src, dst, dst_draw->bitsPerPixel, 2392fe8aea9eSmrg src_bo->pitch, dst_bo->pitch, 2393fe8aea9eSmrg box->x1 + sx, box->y1 + sy, 2394fe8aea9eSmrg box->x1 + dx, box->y1 + dy, 2395fe8aea9eSmrg box->x2 - box->x1, box->y2 - box->y1); 2396fe8aea9eSmrg box++; 2397fe8aea9eSmrg } while (--n); 2398fe8aea9eSmrg } else do { 239913496ba1Ssnj memcpy_blt(src, dst, dst_draw->bitsPerPixel, 240013496ba1Ssnj src_bo->pitch, dst_bo->pitch, 240113496ba1Ssnj box->x1 + sx, box->y1 + sy, 240213496ba1Ssnj box->x1 + dx, box->y1 + dy, 240313496ba1Ssnj box->x2 - box->x1, box->y2 - box->y1); 240413496ba1Ssnj box++; 240513496ba1Ssnj } while (--n); 240613496ba1Ssnj sigtrap_put(); 240713496ba1Ssnj } 240813496ba1Ssnj 240913496ba1Ssnj return true; 241013496ba1Ssnj} 241113496ba1Ssnj 241213496ba1Ssnjvoid 241313496ba1Ssnjsna_render_mark_wedged(struct sna *sna) 241413496ba1Ssnj{ 241513496ba1Ssnj sna->render.copy_boxes = memcpy_copy_boxes; 2416fe8aea9eSmrg sna->render.prefer_gpu = 0; 241713496ba1Ssnj} 2418