From 66f3db6789727b99ec34afe3ceaecc9e549e55ee Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 15 Apr 2015 08:31:35 +0100 Subject: [PATCH 01/61] sna: Use addfb2.1 for extended scanout support If at first you don't succeed, try, try again. The kernel API is lame and requires a new interface for something that is designed to be supported through the old interface... Signed-off-by: Chris Wilson --- src/sna/kgem.c | 26 ++++++++++++++ src/sna/sna_display.c | 81 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 98 insertions(+), 9 deletions(-) diff --git a/src/sna/kgem.c b/src/sna/kgem.c index 952f2494..05fe4070 100644 --- a/src/sna/kgem.c +++ b/src/sna/kgem.c @@ -1262,6 +1262,32 @@ static bool test_can_scanout_y(struct kgem *kgem) if (gem_set_tiling(kgem->fd, arg.handle, I915_TILING_Y, arg.pitch)) ret = do_ioctl(kgem->fd, DRM_IOCTL_MODE_ADDFB, &arg) == 0; + if (!ret) { + struct local_mode_fb_cmd2 { + uint32_t fb_id; + uint32_t width, height; + uint32_t pixel_format; + uint32_t flags; + + uint32_t handles[4]; + uint32_t pitches[4]; + uint32_t offsets[4]; + uint64_t modifiers[4]; + } f; +#define LOCAL_IOCTL_MODE_ADDFB2 DRM_IOWR(0xb8, struct local_mode_fb_cmd2) + memset(&f, 0, sizeof(f)); + f.width = arg.width; + f.height = arg.height; + f.handles[0] = arg.handle; + f.pitches[0] = arg.pitch; + f.modifiers[0] = (uint64_t)1 << 56 | 2; /* MOD_Y_TILED */ + f.pixel_format = 'X' | 'R' << 8 | '2' << 16 | '4' << 24; /* XRGB8888 */ + f.flags = 1 << 1; /* + modifier */ + if (drmIoctl(kgem->fd, LOCAL_IOCTL_MODE_ADDFB2, &f) == 0) { + ret = true; + arg.fb_id = f.fb_id; + } + } do_ioctl(kgem->fd, DRM_IOCTL_MODE_RMFB, &arg.fb_id); gem_close(kgem->fd, arg.handle); diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c index c842d9a2..6b2c3ef2 100644 --- a/src/sna/sna_display.c +++ b/src/sna/sna_display.c @@ -442,6 +442,7 @@ static unsigned get_fb(struct sna *sna, struct kgem_bo *bo, assert(bo->tiling != I915_TILING_Y || sna->kgem.can_scanout_y); assert((bo->pitch & 63) == 0); + assert(scrn->vtSema); /* must be master */ VG_CLEAR(arg); arg.width = width; @@ -451,21 +452,83 @@ static unsigned get_fb(struct sna *sna, struct kgem_bo *bo, arg.depth = scrn->depth; arg.handle = bo->handle; - assert(sna->scrn->vtSema); /* must be master */ if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_ADDFB, &arg)) { - xf86DrvMsg(scrn->scrnIndex, X_ERROR, - "%s: failed to add fb: %dx%d depth=%d, bpp=%d, pitch=%d: %d\n", - __FUNCTION__, width, height, - scrn->depth, scrn->bitsPerPixel, bo->pitch, errno); - return 0; + /* Try again with the fancy version */ + struct local_mode_fb_cmd2 { + uint32_t fb_id; + uint32_t width, height; + uint32_t pixel_format; + uint32_t flags; + + uint32_t handles[4]; + uint32_t pitches[4]; /* pitch for each plane */ + uint32_t offsets[4]; /* offset of each plane */ + uint64_t modifiers[4]; + } f; +#define LOCAL_IOCTL_MODE_ADDFB2 DRM_IOWR(0xb8, struct local_mode_fb_cmd2) + memset(&f, 0, sizeof(f)); + f.width = width; + f.height = height; + /* XXX interlaced */ + f.flags = 1 << 1; /* +modifiers */ + f.handles[0] = bo->handle; + f.pitches[0] = bo->pitch; + + switch (bo->tiling) { + case I915_TILING_NONE: + break; + case I915_TILING_X: + /* I915_FORMAT_MOD_X_TILED */ + f.modifiers[0] = (uint64_t)1 << 56 | 1; + break; + case I915_TILING_Y: + /* I915_FORMAT_MOD_X_TILED */ + f.modifiers[0] = (uint64_t)1 << 56 | 2; + break; + } + +#define fourcc(a,b,c,d) ((a) | (b) << 8 | (c) << 16 | (d) << 24) + switch (scrn->depth) { + default: + ERR(("%s: unhandled screen format, depth=%d\n", + __FUNCTION__, scrn->depth)); + goto fail; + case 8: + f.pixel_format = fourcc('C', '8', ' ', ' '); + break; + case 15: + f.pixel_format = fourcc('X', 'R', '1', '5'); + break; + case 16: + f.pixel_format = fourcc('R', 'G', '1', '6'); + break; + case 24: + f.pixel_format = fourcc('X', 'R', '2', '4'); + break; + case 30: + f.pixel_format = fourcc('X', 'R', '3', '0'); + break; + } +#undef fourcc + + if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_ADDFB2, &f)) { +fail: + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "%s: failed to add fb: %dx%d depth=%d, bpp=%d, pitch=%d: %d\n", + __FUNCTION__, width, height, + scrn->depth, scrn->bitsPerPixel, bo->pitch, errno); + return 0; + } + + arg.fb_id = f.fb_id; } assert(arg.fb_id != 0); - + bo->delta = arg.fb_id; DBG(("%s: attached fb=%d to handle=%d\n", - __FUNCTION__, arg.fb_id, arg.handle)); + __FUNCTION__, bo->delta, arg.handle)); bo->scanout = true; - return bo->delta = arg.fb_id; + return bo->delta; } static uint32_t gem_create(int fd, int size) From 5df16db52ec994fce2f3af952ad08a13c9c700aa Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 16 Apr 2015 14:22:33 +0100 Subject: [PATCH 02/61] sna/dri3: Mark incoming sna_pixmap->flags We use the flags for deciding how to operate on the GPU bo, so we should set them! Signed-off-by: Chris Wilson --- src/sna/sna_dri3.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sna/sna_dri3.c b/src/sna/sna_dri3.c index f586e242..ecfb6f30 100644 --- a/src/sna/sna_dri3.c +++ b/src/sna/sna_dri3.c @@ -270,6 +270,8 @@ static PixmapPtr sna_dri3_pixmap_from_fd(ScreenPtr screen, priv->ptr = MAKE_STATIC_PTR(pixmap->devPrivate.ptr); } else { assert(priv->gpu_bo == bo); + priv->create = kgem_can_create_2d(&sna->kgem, + width, height, depth); priv->pinned |= PIN_DRI3; } list_add(&priv->cow_list, &sna->dri3.pixmaps); From 57252b63f92c8f58cb62c28461d86becf463302b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 16 Apr 2015 14:29:53 +0100 Subject: [PATCH 03/61] sna: Force GTT fallback if we cannot BLT or RENDER download Signed-off-by: Chris Wilson --- src/sna/sna_io.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sna/sna_io.c b/src/sna/sna_io.c index d6aa1294..4250f9ee 100644 --- a/src/sna/sna_io.c +++ b/src/sna/sna_io.c @@ -281,6 +281,9 @@ fallback: if (box[n].y2 > extents.y2) extents.y2 = box[n].y2; } + if (!can_blt && sna->render.max_3d_size == 0) + goto fallback; + if (kgem_bo_can_map(kgem, src_bo)) { /* Is it worth detiling? */ if ((extents.y2 - extents.y1 - 1) * src_bo->pitch < 4096) @@ -849,6 +852,8 @@ bool sna_write_boxes(struct sna *sna, PixmapPtr dst, if (box[n].y2 > extents.y2) extents.y2 = box[n].y2; } + if (!can_blt && sna->render.max_3d_size == 0) + goto fallback; /* Try to avoid switching rings... */ if (!can_blt || kgem->ring == KGEM_RENDER || From c43617b739e358064396912c7a7a8028ca91d201 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 16 Apr 2015 20:40:39 +0300 Subject: [PATCH 04/61] gen8: Fix the YUV->RGB shader MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the correct register (Yn_01) with first half of the Y samples instead of using the register (Yn_23) with the second half twice when computing the green channel. Also use the Yn_01 register name instead of Yn for the red channel as well, just for a bit of extra consistency. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=89807 Signed-off-by: Ville Syrjälä Tested-by: Chris Wilson --- src/render_program/exa_wm_yuv_rgb.g8a | 4 ++-- src/render_program/exa_wm_yuv_rgb.g8b | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/render_program/exa_wm_yuv_rgb.g8a b/src/render_program/exa_wm_yuv_rgb.g8a index 7def0930..34973ba8 100644 --- a/src/render_program/exa_wm_yuv_rgb.g8a +++ b/src/render_program/exa_wm_yuv_rgb.g8a @@ -76,7 +76,7 @@ add (16) Cbn<1>F Cb<8,8,1>F -0.501961F { compr align1 }; /* * R = Y + Cr * 1.596 */ -mov (8) acc0<1>F Yn<8,8,1>F { compr align1 }; +mov (8) acc0<1>F Yn_01<8,8,1>F { compr align1 }; mac.sat(8) src_sample_r_01<1>F Crn_01<8,8,1>F 1.596F { compr align1 }; mov (8) acc0<1>F Yn_23<8,8,1>F { compr align1 }; @@ -84,7 +84,7 @@ mac.sat(8) src_sample_r_23<1>F Crn_23<8,8,1>F 1.596F { compr align1 }; /* * G = Crn * -0.813 + Cbn * -0.392 + Y */ -mov (8) acc0<1>F Yn_23<8,8,1>F { compr align1 }; +mov (8) acc0<1>F Yn_01<8,8,1>F { compr align1 }; mac (8) acc0<1>F Crn_01<8,8,1>F -0.813F { compr align1 }; mac.sat(8) src_sample_g_01<1>F Cbn_01<8,8,1>F -0.392F { compr align1 }; diff --git a/src/render_program/exa_wm_yuv_rgb.g8b b/src/render_program/exa_wm_yuv_rgb.g8b index 44949538..2cd6fc44 100644 --- a/src/render_program/exa_wm_yuv_rgb.g8b +++ b/src/render_program/exa_wm_yuv_rgb.g8b @@ -6,7 +6,7 @@ { 0x80600048, 0x21c03ae8, 0x3e8d02c0, 0x3fcc49ba }, { 0x00600001, 0x24003ae0, 0x008d0320, 0x00000000 }, { 0x80600048, 0x21e03ae8, 0x3e8d02e0, 0x3fcc49ba }, - { 0x00600001, 0x24003ae0, 0x008d0320, 0x00000000 }, + { 0x00600001, 0x24003ae0, 0x008d0300, 0x00000000 }, { 0x00600048, 0x24003ae0, 0x3e8d02c0, 0xbf5020c5 }, { 0x80600048, 0x22003ae8, 0x3e8d0340, 0xbec8b439 }, { 0x00600001, 0x24003ae0, 0x008d0320, 0x00000000 }, From 1e1a7875cf6ff7a46e373ddb5c76621df72b8f74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 16 Apr 2015 20:40:37 +0300 Subject: [PATCH 05/61] intel: Add marketing names for CHV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All CHV devices will be branded as "Intel(r) HD Graphics". Signed-off-by: Ville Syrjälä --- src/intel_module.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/intel_module.c b/src/intel_module.c index bb744224..faf70abd 100644 --- a/src/intel_module.c +++ b/src/intel_module.c @@ -259,6 +259,12 @@ static const SymTabRec intel_chipsets[] = { {0x163D, "HD graphics"}, {0x163E, "HD graphics"}, + /* Cherryview (Cherrytrail/Braswell) */ + {0x22b0, "HD Graphics"}, + {0x22b1, "HD Graphics"}, + {0x22b2, "HD Graphics"}, + {0x22b3, "HD Graphics"}, + /* When adding new identifiers, also update: * 1. intel_identify() * 2. man/intel.man From 3abc3ce3b52a4bd4de4e7e21f05e60c1bd576b6a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 16 Apr 2015 20:59:16 +0100 Subject: [PATCH 06/61] sna/gen8: reduce CHV VS URB entries to 640 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to BSpec the max number of VS URB entries for CHV is 640. Based on a patch by Ville Syrjälä. v2: Start using a GT info block like earlier generations. Signed-off-by: Ville Syrjälä [v1] Signed-off-by: Chris Wilson --- src/sna/gen8_render.c | 38 ++++++++++++++++++++++++++++++++++++-- src/sna/sna_render.h | 2 +- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/sna/gen8_render.c b/src/sna/gen8_render.c index ebabb2e5..c0fe9f9c 100644 --- a/src/sna/gen8_render.c +++ b/src/sna/gen8_render.c @@ -205,6 +205,33 @@ static const struct blendinfo { #define OUT_VERTEX(x,y) vertex_emit_2s(sna, x,y) #define OUT_VERTEX_F(v) vertex_emit(sna, v) +struct gt_info { + const char *name; + struct { + int max_vs_entries; + } urb; +}; + +static const struct gt_info bdw_gt_info = { + .name = "Broadwell (gen8)", + .urb = { .max_vs_entries = 960 }, +}; + +static bool is_bdw(struct sna *sna) +{ + return sna->kgem.gen == 0100; +} + +static const struct gt_info chv_gt_info = { + .name = "Cherryview (gen8)", + .urb = { .max_vs_entries = 640 }, +}; + +static bool is_chv(struct sna *sna) +{ + return sna->kgem.gen == 0101; +} + static inline bool too_large(int width, int height) { return width > GEN8_MAX_SIZE || height > GEN8_MAX_SIZE; @@ -462,7 +489,7 @@ gen8_emit_urb(struct sna *sna) { /* num of VS entries must be divisible by 8 if size < 9 */ OUT_BATCH(GEN8_3DSTATE_URB_VS | (2 - 2)); - OUT_BATCH(960 << URB_ENTRY_NUMBER_SHIFT | + OUT_BATCH(sna->render_state.gen8.info->urb.max_vs_entries << URB_ENTRY_NUMBER_SHIFT | (2 - 1) << URB_ENTRY_SIZE_SHIFT | 4 << URB_STARTING_ADDRESS_SHIFT); @@ -3915,6 +3942,13 @@ static bool gen8_render_setup(struct sna *sna) state->gt = ((devid >> 4) & 0xf) + 1; DBG(("%s: gt=%d\n", __FUNCTION__, state->gt)); + if (is_bdw(sna)) + state->info = &bdw_gt_info; + else if (is_chv(sna)) + state->info = &chv_gt_info; + else + return false; + sna_static_stream_init(&general); /* Zero pad the start. If you see an offset of 0x0 in the batchbuffer @@ -4026,5 +4060,5 @@ const char *gen8_render_init(struct sna *sna, const char *backend) sna->render.max_3d_size = GEN8_MAX_SIZE; sna->render.max_3d_pitch = 1 << 18; - return "Broadwell"; + return sna->render_state.gen8.info->name; } diff --git a/src/sna/sna_render.h b/src/sna/sna_render.h index f59a9283..723de80b 100644 --- a/src/sna/sna_render.h +++ b/src/sna/sna_render.h @@ -540,7 +540,7 @@ enum { struct gen8_render_state { unsigned gt; - + const struct gt_info *info; struct kgem_bo *general_bo; uint32_t vs_state; From 4b4bcbfcff25cf2df6fe9c3bba783a4ac1811e2e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 16 Apr 2015 21:11:01 +0100 Subject: [PATCH 07/61] intel: Fix inconsistent captilisation of "graphics" As we treat it as a name we should capitilize each word, but we forgot that rule (sometimes!) for Broadwell. Signed-off-by: Chris Wilson --- src/intel_module.c | 48 +++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/intel_module.c b/src/intel_module.c index faf70abd..2a3b0166 100644 --- a/src/intel_module.c +++ b/src/intel_module.c @@ -234,30 +234,30 @@ static const SymTabRec intel_chipsets[] = { {0x0157, "HD Graphics"}, /* Broadwell Marketing names */ - {0x1602, "HD graphics"}, - {0x1606, "HD graphics"}, - {0x160B, "HD graphics"}, - {0x160A, "HD graphics"}, - {0x160D, "HD graphics"}, - {0x160E, "HD graphics"}, - {0x1612, "HD graphics 5600"}, - {0x1616, "HD graphics 5500"}, - {0x161B, "HD graphics"}, - {0x161A, "HD graphics"}, - {0x161D, "HD graphics"}, - {0x161E, "HD graphics 5300"}, - {0x1622, "Iris Pro graphics 6200"}, - {0x1626, "HD graphics 6000"}, - {0x162B, "Iris graphics 6100"}, - {0x162A, "Iris Pro graphics P6300"}, - {0x162D, "HD graphics"}, - {0x162E, "HD graphics"}, - {0x1632, "HD graphics"}, - {0x1636, "HD graphics"}, - {0x163B, "HD graphics"}, - {0x163A, "HD graphics"}, - {0x163D, "HD graphics"}, - {0x163E, "HD graphics"}, + {0x1602, "HD Graphics"}, + {0x1606, "HD Graphics"}, + {0x160B, "HD Graphics"}, + {0x160A, "HD Graphics"}, + {0x160D, "HD Graphics"}, + {0x160E, "HD Graphics"}, + {0x1612, "HD Graphics 5600"}, + {0x1616, "HD Graphics 5500"}, + {0x161B, "HD Graphics"}, + {0x161A, "HD Graphics"}, + {0x161D, "HD Graphics"}, + {0x161E, "HD Graphics 5300"}, + {0x1622, "Iris Pro Graphics 6200"}, + {0x1626, "HD Graphics 6000"}, + {0x162B, "Iris Graphics 6100"}, + {0x162A, "Iris Pro Graphics P6300"}, + {0x162D, "HD Graphics"}, + {0x162E, "HD Graphics"}, + {0x1632, "HD Graphics"}, + {0x1636, "HD Graphics"}, + {0x163B, "HD Graphics"}, + {0x163A, "HD Graphics"}, + {0x163D, "HD Graphics"}, + {0x163E, "HD Graphics"}, /* Cherryview (Cherrytrail/Braswell) */ {0x22b0, "HD Graphics"}, From 432e0775ee26a81e8e00f04c6864205d9f0bc2a2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 17 Apr 2015 10:21:30 +0100 Subject: [PATCH 08/61] sna/present: Check earlier for an incompatilble tiled Pixmap Signed-off-by: Chris Wilson --- src/sna/sna_present.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/sna/sna_present.c b/src/sna/sna_present.c index 82f772f1..a344dac8 100644 --- a/src/sna/sna_present.c +++ b/src/sna/sna_present.c @@ -444,6 +444,24 @@ sna_present_check_flip(RRCrtcPtr crtc, return FALSE; } + if (flip->pinned) { + assert(flip->gpu_bo); + if (sna->flags & SNA_LINEAR_FB) { + if (flip->gpu_bo->tiling != I915_TILING_NONE) { + DBG(("%s: pined bo, tilng=%d needs NONE\n", + __FUNCTION__, flip->gpu_bo->tiling)); + return FALSE; + } + } else { + if (!sna->kgem.can_scanout_y && + flip->gpu_bo->tiling == I915_TILING_Y) { + DBG(("%s: pined bo, tilng=%d and can't scanout Y\n", + __FUNCTION__, flip->gpu_bo->tiling)); + return FALSE; + } + } + } + return TRUE; } @@ -560,7 +578,7 @@ get_flip_bo(PixmapPtr pixmap) if (priv->gpu_bo->scanout) return priv->gpu_bo; - if (sna->kgem.has_llc && !wedged(sna)) { + if (sna->kgem.has_llc && !wedged(sna) && !priv->pinned) { struct kgem_bo *bo; uint32_t tiling; From 75d87762471e195dddd73056fc6a06e17db1c8b0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 17 Apr 2015 10:29:28 +0100 Subject: [PATCH 09/61] sna: Enable blitting with Y-tiled surfaces Since gen6, there has been a magic register bit to change the interpretation of the tiling mode between X and Y for BLT operations. With the advent of DRI3 and scanouts supporting Y, enabling support at last appears interesting, perhapss even by default for non-scanouts? Signed-off-by: Chris Wilson --- src/sna/gen6_common.h | 3 + src/sna/kgem.c | 141 +++++++++++++++++++++++++++++++++++++++++- src/sna/kgem.h | 23 ++++++- src/sna/sna_accel.c | 34 ++++++++++ src/sna/sna_blt.c | 29 ++++++++- src/sna/sna_io.c | 17 ++++- 6 files changed, 239 insertions(+), 8 deletions(-) diff --git a/src/sna/gen6_common.h b/src/sna/gen6_common.h index 409bab3b..5da739e2 100644 --- a/src/sna/gen6_common.h +++ b/src/sna/gen6_common.h @@ -93,6 +93,9 @@ static int prefer_blt_bo(struct sna *sna, if (src->rq) return RQ_IS_BLT(src->rq); + + if (src->tiling == I915_TILING_Y) + return false; } else { if (sna->render_state.gt > 2) return false; diff --git a/src/sna/kgem.c b/src/sna/kgem.c index 05fe4070..76e69135 100644 --- a/src/sna/kgem.c +++ b/src/sna/kgem.c @@ -84,6 +84,7 @@ search_snoop_cache(struct kgem *kgem, unsigned int num_pages, unsigned flags); #define DBG_NO_HANDLE_LUT 0 #define DBG_NO_WT 0 #define DBG_NO_WC_MMAP 0 +#define DBG_NO_BLT_Y 0 #define DBG_NO_SCANOUT_Y 0 #define DBG_NO_DETILING 0 #define DBG_DUMP 0 @@ -1244,6 +1245,54 @@ static bool test_has_create2(struct kgem *kgem) #endif } +static bool test_can_blt_y(struct kgem *kgem) +{ + struct drm_i915_gem_exec_object2 object; + uint32_t batch[] = { +#define MI_LOAD_REGISTER_IMM (0x22<<23 | (3-2)) +#define BCS_SWCTRL 0x22200 +#define BCS_SRC_Y (1 << 0) +#define BCS_DST_Y (1 << 1) + MI_LOAD_REGISTER_IMM, + BCS_SWCTRL, + (BCS_SRC_Y | BCS_DST_Y) << 16 | (BCS_SRC_Y | BCS_DST_Y), + + MI_LOAD_REGISTER_IMM, + BCS_SWCTRL, + (BCS_SRC_Y | BCS_DST_Y) << 16, + + MI_BATCH_BUFFER_END, + 0, + }; + int ret; + + if (DBG_NO_BLT_Y) + return false; + + if (kgem->gen < 060) + return false; + + memset(&object, 0, sizeof(object)); + object.handle = gem_create(kgem->fd, 1); + + ret = gem_write(kgem->fd, object.handle, 0, sizeof(batch), batch); + if (ret == 0) { + struct drm_i915_gem_execbuffer2 execbuf; + + memset(&execbuf, 0, sizeof(execbuf)); + execbuf.buffers_ptr = (uintptr_t)&object; + execbuf.buffer_count = 1; + execbuf.flags = I915_EXEC_BLT; + + ret = do_ioctl(kgem->fd, + DRM_IOCTL_I915_GEM_EXECBUFFER2, + &execbuf); + } + gem_close(kgem->fd, object.handle); + + return ret == 0; +} + static bool test_can_scanout_y(struct kgem *kgem) { struct drm_mode_fb_cmd arg; @@ -1672,12 +1721,16 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen) DBG(("%s: can blt to cpu? %d\n", __FUNCTION__, kgem->can_blt_cpu)); + kgem->can_blt_y = test_can_blt_y(kgem); + DBG(("%s: can blit to Y-tiled surfaces? %d\n", __FUNCTION__, + kgem->can_blt_y)); + kgem->can_render_y = gen != 021 && (gen >> 3) != 4; DBG(("%s: can render to Y-tiled surfaces? %d\n", __FUNCTION__, kgem->can_render_y)); kgem->can_scanout_y = test_can_scanout_y(kgem); - DBG(("%s: can render to Y-tiled surfaces? %d\n", __FUNCTION__, + DBG(("%s: can scanout Y-tiled surfaces? %d\n", __FUNCTION__, kgem->can_scanout_y)); kgem->has_secure_batches = test_has_secure_batches(kgem); @@ -2136,8 +2189,32 @@ static void kgem_add_bo(struct kgem *kgem, struct kgem_bo *bo) kgem->flush |= bo->flush; } +static void kgem_clear_swctrl(struct kgem *kgem) +{ + uint32_t *b; + + if (kgem->bcs_state == 0) + return; + + DBG(("%s: clearin SWCTRL LRI from %x\n", + __FUNCTION__, kgem->bcs_state)); + + b = kgem->batch + kgem->nbatch; + kgem->nbatch += 7; + + *b++ = MI_FLUSH_DW; + *b++ = 0; + *b++ = 0; + *b++ = 0; + + *b++ = MI_LOAD_REGISTER_IMM; + *b++ = BCS_SWCTRL; + *b++ = kgem->bcs_state << 16; +} + static uint32_t kgem_end_batch(struct kgem *kgem) { + kgem_clear_swctrl(kgem); kgem->batch[kgem->nbatch++] = MI_BATCH_BUFFER_END; if (kgem->nbatch & 1) kgem->batch[kgem->nbatch++] = MI_NOOP; @@ -3480,6 +3557,7 @@ void kgem_reset(struct kgem *kgem) kgem->needs_reservation = false; kgem->flush = 0; kgem->batch_flags = kgem->batch_flags_base; + kgem->bcs_state = 0; assert(kgem->batch); kgem->next_request = __kgem_request_alloc(kgem); @@ -6114,6 +6192,66 @@ bool kgem_check_many_bo_fenced(struct kgem *kgem, ...) return kgem_flush(kgem, flush); } +void __kgem_bcs_set_tiling(struct kgem *kgem, + struct kgem_bo *src, + struct kgem_bo *dst) +{ + uint32_t state, mask, *b; + + DBG(("%s: src handle=%d:tiling=%d, dst handle=%d:tiling=%d\n", + __FUNCTION__, + src ? src->handle : 0, src ? src->tiling : 0, + dst ? dst->handle : 0, dst ? dst->tiling : 0)); + assert(kgem->mode == KGEM_BLT); + + mask = state = 0; + if (dst && dst->tiling) { + assert(kgem_bo_can_blt(kgem, dst)); + mask |= BCS_DST_Y; + if (dst->tiling == I915_TILING_Y) + state |= BCS_DST_Y; + } + + if (src && src->tiling) { + assert(kgem_bo_can_blt(kgem, src)); + mask |= BCS_SRC_Y; + if (src->tiling == I915_TILING_Y) + state |= BCS_SRC_Y; + } + + if ((kgem->bcs_state & mask) == state) + return; + + DBG(("%s: updating SWCTRL %x -> %x\n", __FUNCTION__, + kgem->bcs_state, (kgem->bcs_state & ~mask) | state)); + + /* Over-estimate space in case we need to re-emit the cmd packet */ + if (!kgem_check_batch(kgem, 24)) { + _kgem_submit(kgem); + _kgem_set_mode(kgem, KGEM_BLT); + } + + b = kgem->batch + kgem->nbatch; + if (kgem->nbatch) { + DBG(("%s: emitting flush before SWCTRL LRI\n", + __FUNCTION__)); + *b++ = MI_FLUSH_DW; + *b++ = 0; + *b++ = 0; + *b++ = 0; + } + + DBG(("%s: emitting SWCTRL LRI to %x\n", + __FUNCTION__, mask << 16 | state)); + *b++ = MI_LOAD_REGISTER_IMM; + *b++ = BCS_SWCTRL; + *b++ = mask << 16 | state; + kgem->nbatch = b - kgem->batch; + + kgem->bcs_state &= ~mask; + kgem->bcs_state |= state; +} + uint32_t kgem_add_reloc(struct kgem *kgem, uint32_t pos, struct kgem_bo *bo, @@ -7619,6 +7757,7 @@ kgem_replace_bo(struct kgem *kgem, } _kgem_set_mode(kgem, KGEM_BLT); } + kgem_bcs_set_tiling(kgem, src, dst); br00 = XY_SRC_COPY_BLT_CMD; br13 = pitch; diff --git a/src/sna/kgem.h b/src/sna/kgem.h index f1042a02..adc777de 100644 --- a/src/sna/kgem.h +++ b/src/sna/kgem.h @@ -158,6 +158,8 @@ struct kgem { int16_t count; } vma[NUM_MAP_TYPES]; + uint32_t bcs_state; + uint32_t batch_flags; uint32_t batch_flags_base; #define I915_EXEC_SECURE (1<<9) @@ -189,6 +191,7 @@ struct kgem { uint32_t has_wc_mmap :1; uint32_t can_blt_cpu :1; + uint32_t can_blt_y :1; uint32_t can_render_y :1; uint32_t can_scanout_y :1; @@ -232,7 +235,7 @@ struct kgem { #define KGEM_MAX_DEFERRED_VBO 16 -#define KGEM_BATCH_RESERVED 1 +#define KGEM_BATCH_RESERVED 8 /* LRI(SWCTRL) + END */ #define KGEM_RELOC_RESERVED (KGEM_MAX_DEFERRED_VBO) #define KGEM_EXEC_RESERVED (1+KGEM_MAX_DEFERRED_VBO) @@ -573,7 +576,7 @@ static inline bool kgem_bo_can_blt(struct kgem *kgem, { assert(bo->refcnt); - if (bo->tiling == I915_TILING_Y) { + if (bo->tiling == I915_TILING_Y && !kgem->can_blt_y) { DBG(("%s: can not blt to handle=%d, tiling=Y\n", __FUNCTION__, bo->handle)); return false; @@ -588,6 +591,22 @@ static inline bool kgem_bo_can_blt(struct kgem *kgem, return kgem_bo_blt_pitch_is_ok(kgem, bo); } +void __kgem_bcs_set_tiling(struct kgem *kgem, + struct kgem_bo *src, + struct kgem_bo *dst); + +inline static void kgem_bcs_set_tiling(struct kgem *kgem, + struct kgem_bo *src, + struct kgem_bo *dst) +{ + assert(kgem->mode == KGEM_BLT); + + if (!kgem->can_blt_y) + return; + + __kgem_bcs_set_tiling(kgem, src, dst); +} + static inline bool kgem_bo_is_snoop(struct kgem_bo *bo) { assert(bo->refcnt); diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c index f76447bd..ce096650 100644 --- a/src/sna/sna_accel.c +++ b/src/sna/sna_accel.c @@ -5297,6 +5297,7 @@ sna_put_xybitmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region, kgem_set_mode(&sna->kgem, KGEM_BLT, bo); assert(kgem_bo_can_blt(&sna->kgem, bo)); + kgem_bcs_set_tiling(&sna->kgem, NULL, bo); /* Region is pre-clipped and translated into pixmap space */ box = region_rects(region); @@ -5318,6 +5319,7 @@ sna_put_xybitmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region, return false; _kgem_set_mode(&sna->kgem, KGEM_BLT); } + kgem_bcs_set_tiling(&sna->kgem, NULL, bo); upload = kgem_create_buffer(&sna->kgem, bstride*bh, @@ -5461,6 +5463,7 @@ sna_put_xypixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region, kgem_set_mode(&sna->kgem, KGEM_BLT, bo); assert(kgem_bo_can_blt(&sna->kgem, bo)); + kgem_bcs_set_tiling(&sna->kgem, NULL, bo); skip = h * BitmapBytePad(w + left); for (i = 1 << (gc->depth-1); i; i >>= 1, bits += skip) { @@ -5488,6 +5491,7 @@ sna_put_xypixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region, return false; _kgem_set_mode(&sna->kgem, KGEM_BLT); } + kgem_bcs_set_tiling(&sna->kgem, NULL, bo); upload = kgem_create_buffer(&sna->kgem, bstride*bh, @@ -8341,6 +8345,7 @@ sna_copy_bitmap_blt(DrawablePtr _bitmap, DrawablePtr drawable, GCPtr gc, return; /* XXX fallback? */ _kgem_set_mode(&sna->kgem, KGEM_BLT); } + kgem_bcs_set_tiling(&sna->kgem, NULL, arg->bo); assert(sna->kgem.mode == KGEM_BLT); if (sna->kgem.gen >= 0100) { @@ -8408,6 +8413,7 @@ sna_copy_bitmap_blt(DrawablePtr _bitmap, DrawablePtr drawable, GCPtr gc, return; /* XXX fallback? */ _kgem_set_mode(&sna->kgem, KGEM_BLT); } + kgem_bcs_set_tiling(&sna->kgem, NULL, arg->bo); upload = kgem_create_buffer(&sna->kgem, bstride*bh, @@ -8558,6 +8564,7 @@ sna_copy_plane_blt(DrawablePtr source, DrawablePtr drawable, GCPtr gc, return; /* XXX fallback? */ _kgem_set_mode(&sna->kgem, KGEM_BLT); } + kgem_bcs_set_tiling(&sna->kgem, NULL, arg->bo); upload = kgem_create_buffer(&sna->kgem, bstride*bh, @@ -8674,6 +8681,8 @@ sna_copy_plane_blt(DrawablePtr source, DrawablePtr drawable, GCPtr gc, } } + kgem_bcs_set_tiling(&sna->kgem, upload, arg->bo); + assert(sna->kgem.mode == KGEM_BLT); b = sna->kgem.batch + sna->kgem.nbatch; if (sna->kgem.gen >= 0100) { @@ -12283,6 +12292,7 @@ sna_poly_fill_rect_tiled_8x8_blt(DrawablePtr drawable, return false; _kgem_set_mode(&sna->kgem, KGEM_BLT); } + kgem_bcs_set_tiling(&sna->kgem, tile_bo, bo); get_drawable_deltas(drawable, pixmap, &dx, &dy); assert(extents->x1 + dx >= 0); @@ -12426,6 +12436,7 @@ sna_poly_fill_rect_tiled_8x8_blt(DrawablePtr drawable, _kgem_submit(&sna->kgem); _kgem_set_mode(&sna->kgem, KGEM_BLT); + kgem_bcs_set_tiling(&sna->kgem, tile_bo, bo); } while (1); } else { RegionRec clip; @@ -12494,6 +12505,7 @@ sna_poly_fill_rect_tiled_8x8_blt(DrawablePtr drawable, if (!kgem_check_batch(&sna->kgem, 3)) { _kgem_submit(&sna->kgem); _kgem_set_mode(&sna->kgem, KGEM_BLT); + kgem_bcs_set_tiling(&sna->kgem, tile_bo, bo); unwind_batch = sna->kgem.nbatch; unwind_reloc = sna->kgem.nreloc; @@ -12590,6 +12602,7 @@ sna_poly_fill_rect_tiled_8x8_blt(DrawablePtr drawable, DBG(("%s: emitting split batch\n", __FUNCTION__)); _kgem_submit(&sna->kgem); _kgem_set_mode(&sna->kgem, KGEM_BLT); + kgem_bcs_set_tiling(&sna->kgem, tile_bo, bo); unwind_batch = sna->kgem.nbatch; unwind_reloc = sna->kgem.nreloc; @@ -13219,6 +13232,7 @@ sna_poly_fill_rect_stippled_8x8_blt(DrawablePtr drawable, return false; _kgem_set_mode(&sna->kgem, KGEM_BLT); } + kgem_bcs_set_tiling(&sna->kgem, NULL, bo); if (!clipped) { dx += drawable->x; @@ -13331,6 +13345,7 @@ sna_poly_fill_rect_stippled_8x8_blt(DrawablePtr drawable, _kgem_submit(&sna->kgem); _kgem_set_mode(&sna->kgem, KGEM_BLT); + kgem_bcs_set_tiling(&sna->kgem, NULL, bo); } while (1); } else { RegionRec clip; @@ -13388,6 +13403,7 @@ sna_poly_fill_rect_stippled_8x8_blt(DrawablePtr drawable, if (!kgem_check_batch(&sna->kgem, 3)) { _kgem_submit(&sna->kgem); _kgem_set_mode(&sna->kgem, KGEM_BLT); + kgem_bcs_set_tiling(&sna->kgem, NULL, bo); assert(sna->kgem.mode == KGEM_BLT); b = sna->kgem.batch + sna->kgem.nbatch; @@ -13460,6 +13476,7 @@ sna_poly_fill_rect_stippled_8x8_blt(DrawablePtr drawable, if (!kgem_check_batch(&sna->kgem, 3)) { _kgem_submit(&sna->kgem); _kgem_set_mode(&sna->kgem, KGEM_BLT); + kgem_bcs_set_tiling(&sna->kgem, NULL, bo); assert(sna->kgem.mode == KGEM_BLT); b = sna->kgem.batch + sna->kgem.nbatch; @@ -13590,6 +13607,7 @@ sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable, get_drawable_deltas(drawable, pixmap, &dx, &dy); kgem_set_mode(&sna->kgem, KGEM_BLT, bo); assert(kgem_bo_can_blt(&sna->kgem, bo)); + kgem_bcs_set_tiling(&sna->kgem, NULL, bo); br00 = 3 << 20; br13 = bo->pitch; @@ -13634,6 +13652,7 @@ sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable, return false; _kgem_set_mode(&sna->kgem, KGEM_BLT); } + kgem_bcs_set_tiling(&sna->kgem, NULL, bo); assert(sna->kgem.mode == KGEM_BLT); b = sna->kgem.batch + sna->kgem.nbatch; @@ -13697,6 +13716,7 @@ sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable, return false; _kgem_set_mode(&sna->kgem, KGEM_BLT); } + kgem_bcs_set_tiling(&sna->kgem, NULL, bo); upload = kgem_create_buffer(&sna->kgem, bstride*bh, @@ -13827,6 +13847,7 @@ sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable, return false; _kgem_set_mode(&sna->kgem, KGEM_BLT); } + kgem_bcs_set_tiling(&sna->kgem, NULL, bo); assert(sna->kgem.mode == KGEM_BLT); b = sna->kgem.batch + sna->kgem.nbatch; @@ -13888,6 +13909,7 @@ sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable, return false; _kgem_set_mode(&sna->kgem, KGEM_BLT); } + kgem_bcs_set_tiling(&sna->kgem, NULL, bo); upload = kgem_create_buffer(&sna->kgem, bstride*bh, @@ -14018,6 +14040,7 @@ sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable, return false; _kgem_set_mode(&sna->kgem, KGEM_BLT); } + kgem_bcs_set_tiling(&sna->kgem, NULL, bo); assert(sna->kgem.mode == KGEM_BLT); b = sna->kgem.batch + sna->kgem.nbatch; @@ -14078,6 +14101,7 @@ sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable, return false; _kgem_set_mode(&sna->kgem, KGEM_BLT); } + kgem_bcs_set_tiling(&sna->kgem, NULL, bo); upload = kgem_create_buffer(&sna->kgem, bstride*bh, @@ -14217,6 +14241,7 @@ sna_poly_fill_rect_stippled_n_box__imm(struct sna *sna, return; /* XXX fallback? */ _kgem_set_mode(&sna->kgem, KGEM_BLT); } + kgem_bcs_set_tiling(&sna->kgem, NULL, bo); assert(sna->kgem.mode == KGEM_BLT); b = sna->kgem.batch + sna->kgem.nbatch; @@ -14342,6 +14367,7 @@ sna_poly_fill_rect_stippled_n_box(struct sna *sna, return; /* XXX fallback? */ _kgem_set_mode(&sna->kgem, KGEM_BLT); } + kgem_bcs_set_tiling(&sna->kgem, NULL, bo); assert(sna->kgem.mode == KGEM_BLT); b = sna->kgem.batch + sna->kgem.nbatch; @@ -14505,6 +14531,7 @@ sna_poly_fill_rect_stippled_n_blt__imm(DrawablePtr drawable, get_drawable_deltas(drawable, pixmap, &dx, &dy); kgem_set_mode(&sna->kgem, KGEM_BLT, bo); assert(kgem_bo_can_blt(&sna->kgem, bo)); + kgem_bcs_set_tiling(&sna->kgem, NULL, bo); br00 = XY_MONO_SRC_COPY_IMM | 3 << 20; br13 = bo->pitch; @@ -14650,6 +14677,7 @@ sna_poly_fill_rect_stippled_n_blt(DrawablePtr drawable, get_drawable_deltas(drawable, pixmap, &dx, &dy); kgem_set_mode(&sna->kgem, KGEM_BLT, bo); assert(kgem_bo_can_blt(&sna->kgem, bo)); + kgem_bcs_set_tiling(&sna->kgem, NULL, bo); br00 = XY_MONO_SRC_COPY | 3 << 20; br13 = bo->pitch; @@ -15372,6 +15400,7 @@ sna_glyph_blt(DrawablePtr drawable, GCPtr gc, } _kgem_set_mode(&sna->kgem, KGEM_BLT); } + kgem_bcs_set_tiling(&sna->kgem, NULL, bo); DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n", __FUNCTION__, @@ -15459,6 +15488,7 @@ sna_glyph_blt(DrawablePtr drawable, GCPtr gc, if (!kgem_check_batch(&sna->kgem, 3+len)) { _kgem_submit(&sna->kgem); _kgem_set_mode(&sna->kgem, KGEM_BLT); + kgem_bcs_set_tiling(&sna->kgem, NULL, bo); DBG(("%s: new batch, glyph clip box (%d, %d), (%d, %d)\n", __FUNCTION__, @@ -16093,6 +16123,7 @@ sna_reversed_glyph_blt(DrawablePtr drawable, GCPtr gc, } _kgem_set_mode(&sna->kgem, KGEM_BLT); } + kgem_bcs_set_tiling(&sna->kgem, NULL, bo); unwind_batch = sna->kgem.nbatch; unwind_reloc = sna->kgem.nreloc; @@ -16202,6 +16233,7 @@ sna_reversed_glyph_blt(DrawablePtr drawable, GCPtr gc, if (!kgem_check_batch(&sna->kgem, 3+len)) { _kgem_submit(&sna->kgem); _kgem_set_mode(&sna->kgem, KGEM_BLT); + kgem_bcs_set_tiling(&sna->kgem, NULL, bo); unwind_batch = sna->kgem.nbatch; unwind_reloc = sna->kgem.nreloc; @@ -16541,6 +16573,7 @@ sna_push_pixels_solid_blt(GCPtr gc, kgem_set_mode(&sna->kgem, KGEM_BLT, bo); assert(kgem_bo_can_blt(&sna->kgem, bo)); + kgem_bcs_set_tiling(&sna->kgem, NULL, bo); /* Region is pre-clipped and translated into pixmap space */ box = region_rects(region); @@ -16562,6 +16595,7 @@ sna_push_pixels_solid_blt(GCPtr gc, return false; _kgem_set_mode(&sna->kgem, KGEM_BLT); } + kgem_bcs_set_tiling(&sna->kgem, NULL, bo); upload = kgem_create_buffer(&sna->kgem, bstride*bh, diff --git a/src/sna/sna_blt.c b/src/sna/sna_blt.c index b62d7fd7..9bb32674 100644 --- a/src/sna/sna_blt.c +++ b/src/sna/sna_blt.c @@ -129,7 +129,6 @@ static bool sna_blt_fill_init(struct sna *sna, struct kgem *kgem = &sna->kgem; assert(kgem_bo_can_blt (kgem, bo)); - assert(bo->tiling != I915_TILING_Y); blt->bo[0] = bo; blt->br13 = bo->pitch; @@ -183,6 +182,7 @@ static bool sna_blt_fill_init(struct sna *sna, return false; _kgem_set_mode(kgem, KGEM_BLT); } + kgem_bcs_set_tiling(kgem, NULL, bo); assert(sna->kgem.mode == KGEM_BLT); b = kgem->batch + kgem->nbatch; @@ -243,6 +243,8 @@ noinline static void __sna_blt_fill_begin(struct sna *sna, struct kgem *kgem = &sna->kgem; uint32_t *b; + kgem_bcs_set_tiling(&sna->kgem, NULL, blt->bo[0]); + assert(kgem->mode == KGEM_BLT); b = kgem->batch + kgem->nbatch; if (sna->kgem.gen >= 0100) { @@ -338,8 +340,8 @@ static bool sna_blt_copy_init(struct sna *sna, { struct kgem *kgem = &sna->kgem; - assert(kgem_bo_can_blt (kgem, src)); - assert(kgem_bo_can_blt (kgem, dst)); + assert(kgem_bo_can_blt(kgem, src)); + assert(kgem_bo_can_blt(kgem, dst)); blt->bo[0] = src; blt->bo[1] = dst; @@ -378,6 +380,7 @@ static bool sna_blt_copy_init(struct sna *sna, return false; _kgem_set_mode(kgem, KGEM_BLT); } + kgem_bcs_set_tiling(&sna->kgem, src, dst); sna->blt_state.fill_bo = 0; return true; @@ -432,6 +435,7 @@ static bool sna_blt_alpha_fixup_init(struct sna *sna, return false; _kgem_set_mode(kgem, KGEM_BLT); } + kgem_bcs_set_tiling(&sna->kgem, src, dst); sna->blt_state.fill_bo = 0; return true; @@ -463,6 +467,7 @@ static void sna_blt_alpha_fixup_one(struct sna *sna, _kgem_submit(kgem); _kgem_set_mode(kgem, KGEM_BLT); } + kgem_bcs_set_tiling(&sna->kgem, blt->bo[1], blt->bo[0]); assert(sna->kgem.mode == KGEM_BLT); b = kgem->batch + kgem->nbatch; @@ -591,6 +596,7 @@ static void sna_blt_copy_one(struct sna *sna, _kgem_submit(kgem); _kgem_set_mode(kgem, KGEM_BLT); } + kgem_bcs_set_tiling(&sna->kgem, blt->bo[1], blt->bo[0]); assert(sna->kgem.mode == KGEM_BLT); b = kgem->batch + kgem->nbatch; @@ -1432,6 +1438,7 @@ begin_blt(struct sna *sna, _kgem_set_mode(&sna->kgem, KGEM_BLT); } + kgem_bcs_set_tiling(&sna->kgem, NULL, op->dst.bo); return true; } @@ -1695,6 +1702,7 @@ static void blt_composite_copy_boxes__thread(struct sna *sna, _kgem_submit(kgem); _kgem_set_mode(kgem, KGEM_BLT); + kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo); } while (1); } else { do { @@ -1751,6 +1759,7 @@ static void blt_composite_copy_boxes__thread(struct sna *sna, _kgem_submit(kgem); _kgem_set_mode(kgem, KGEM_BLT); + kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo); } while (1); } sna_vertex_unlock(&sna->render); @@ -1833,6 +1842,7 @@ static void blt_composite_copy_boxes__thread64(struct sna *sna, _kgem_submit(kgem); _kgem_set_mode(kgem, KGEM_BLT); + kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo); } while (1); } else { do { @@ -1891,6 +1901,7 @@ static void blt_composite_copy_boxes__thread64(struct sna *sna, _kgem_submit(kgem); _kgem_set_mode(kgem, KGEM_BLT); + kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo); } while (1); } sna_vertex_unlock(&sna->render); @@ -2000,6 +2011,7 @@ prepare_blt_copy(struct sna *sna, } _kgem_set_mode(&sna->kgem, KGEM_BLT); } + kgem_bcs_set_tiling(&sna->kgem, bo, op->dst.bo); DBG(("%s\n", __FUNCTION__)); @@ -3046,6 +3058,7 @@ sna_blt_composite__convert(struct sna *sna, } _kgem_set_mode(&sna->kgem, KGEM_BLT); } + kgem_bcs_set_tiling(&sna->kgem, tmp->src.bo, tmp->dst.bo); if (alpha_fixup) { tmp->blt = blt_composite_copy_with_alpha; @@ -3387,6 +3400,7 @@ static bool sna_blt_fill_box(struct sna *sna, uint8_t alu, _kgem_set_mode(kgem, KGEM_BLT); } + kgem_bcs_set_tiling(&sna->kgem, NULL, bo); assert(kgem_check_batch(kgem, 6)); assert(kgem_check_reloc(kgem, 1)); @@ -3493,6 +3507,8 @@ bool sna_blt_fill_boxes(struct sna *sna, uint8_t alu, _kgem_set_mode(kgem, KGEM_BLT); } + kgem_bcs_set_tiling(&sna->kgem, NULL, bo); + assert(sna->kgem.mode == KGEM_BLT); b = kgem->batch + kgem->nbatch; if (kgem->gen >= 0100) { @@ -3581,6 +3597,7 @@ bool sna_blt_fill_boxes(struct sna *sna, uint8_t alu, _kgem_submit(kgem); _kgem_set_mode(kgem, KGEM_BLT); + kgem_bcs_set_tiling(&sna->kgem, NULL, bo); assert(sna->kgem.mode == KGEM_BLT); b = kgem->batch + kgem->nbatch; @@ -3727,6 +3744,7 @@ bool sna_blt_copy_boxes(struct sna *sna, uint8_t alu, } _kgem_set_mode(kgem, KGEM_BLT); } + kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo); if ((dst_dx | dst_dy) == 0) { if (kgem->gen >= 0100) { @@ -3787,6 +3805,7 @@ bool sna_blt_copy_boxes(struct sna *sna, uint8_t alu, _kgem_submit(kgem); _kgem_set_mode(kgem, KGEM_BLT); + kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo); } while (1); } else { uint64_t hdr = (uint64_t)br13 << 32 | cmd | 6; @@ -3844,6 +3863,7 @@ bool sna_blt_copy_boxes(struct sna *sna, uint8_t alu, _kgem_submit(kgem); _kgem_set_mode(kgem, KGEM_BLT); + kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo); } while (1); } } else { @@ -3905,6 +3925,7 @@ bool sna_blt_copy_boxes(struct sna *sna, uint8_t alu, _kgem_submit(kgem); _kgem_set_mode(kgem, KGEM_BLT); + kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo); } while (1); } else { cmd |= 6; @@ -3962,6 +3983,7 @@ bool sna_blt_copy_boxes(struct sna *sna, uint8_t alu, _kgem_submit(kgem); _kgem_set_mode(kgem, KGEM_BLT); + kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo); } while (1); } } @@ -4069,6 +4091,7 @@ bool sna_blt_copy_boxes__with_alpha(struct sna *sna, uint8_t alu, _kgem_submit(kgem); _kgem_set_mode(kgem, KGEM_BLT); } + kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo); assert(sna->kgem.mode == KGEM_BLT); b = kgem->batch + kgem->nbatch; diff --git a/src/sna/sna_io.c b/src/sna/sna_io.c index 4250f9ee..db317ee4 100644 --- a/src/sna/sna_io.c +++ b/src/sna/sna_io.c @@ -105,8 +105,10 @@ read_boxes_inplace__cpu(struct kgem *kgem, if (!download_inplace__cpu(kgem, dst, bo, box, n)) return false; + if (bo->tiling == I915_TILING_Y) + return false; + assert(kgem_bo_can_map__cpu(kgem, bo, false)); - assert(bo->tiling != I915_TILING_Y); src = kgem_bo_map__cpu(kgem, bo); if (src == NULL) @@ -480,6 +482,7 @@ fallback: goto fallback; _kgem_set_mode(kgem, KGEM_BLT); } + kgem_bcs_set_tiling(&sna->kgem, src_bo, NULL); tmp_nbox = nbox; tmp_box = box; @@ -542,6 +545,7 @@ fallback: break; _kgem_set_mode(kgem, KGEM_BLT); + kgem_bcs_set_tiling(&sna->kgem, src_bo, NULL); tmp_box += nbox_this_time; } while (1); } else { @@ -600,6 +604,7 @@ fallback: break; _kgem_set_mode(kgem, KGEM_BLT); + kgem_bcs_set_tiling(&sna->kgem, src_bo, NULL); tmp_box += nbox_this_time; } while (1); } @@ -669,8 +674,10 @@ write_boxes_inplace__tiled(struct kgem *kgem, { uint8_t *dst; + if (bo->tiling == I915_TILING_Y) + return false; + assert(kgem->has_wc_mmap || kgem_bo_can_map__cpu(kgem, bo, true)); - assert(bo->tiling != I915_TILING_Y); if (kgem_bo_can_map__cpu(kgem, bo, true)) { dst = kgem_bo_map__cpu(kgem, bo); @@ -1043,6 +1050,7 @@ tile: goto fallback; _kgem_set_mode(kgem, KGEM_BLT); } + kgem_bcs_set_tiling(&sna->kgem, NULL, dst_bo); if (kgem->gen >= 0100) { cmd |= 8; @@ -1134,6 +1142,7 @@ tile: if (nbox) { _kgem_submit(kgem); _kgem_set_mode(kgem, KGEM_BLT); + kgem_bcs_set_tiling(&sna->kgem, NULL, dst_bo); } kgem_bo_destroy(kgem, src_bo); @@ -1229,6 +1238,7 @@ tile: if (nbox) { _kgem_submit(kgem); _kgem_set_mode(kgem, KGEM_BLT); + kgem_bcs_set_tiling(&sna->kgem, NULL, dst_bo); } kgem_bo_destroy(kgem, src_bo); @@ -1546,6 +1556,7 @@ tile: goto fallback; _kgem_set_mode(kgem, KGEM_BLT); } + kgem_bcs_set_tiling(&sna->kgem, NULL, dst_bo); if (sna->kgem.gen >= 0100) { cmd |= 8; @@ -1641,6 +1652,7 @@ tile: if (nbox) { _kgem_submit(kgem); _kgem_set_mode(kgem, KGEM_BLT); + kgem_bcs_set_tiling(&sna->kgem, NULL, dst_bo); } kgem_bo_destroy(kgem, src_bo); @@ -1737,6 +1749,7 @@ tile: if (nbox) { _kgem_submit(kgem); _kgem_set_mode(kgem, KGEM_BLT); + kgem_bcs_set_tiling(&sna->kgem, NULL, dst_bo); } kgem_bo_destroy(kgem, src_bo); From 7eaf593640d4479f850227252fd793bcb55be8d3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 17 Apr 2015 23:45:20 +0100 Subject: [PATCH 10/61] sna/present: Reuse last cached swap msc/ust during a flip chain Querying the known swap values is much slower than not! Signed-off-by: Chris Wilson --- src/sna/sna.h | 46 ++++++- src/sna/sna_display.c | 239 ++++++++++++++++++------------------- src/sna/sna_dri2.c | 26 ++-- src/sna/sna_present.c | 77 ++++++++---- src/sna/sna_video_sprite.c | 18 +-- test/present-speed.c | 1 - 6 files changed, 232 insertions(+), 175 deletions(-) diff --git a/src/sna/sna.h b/src/sna/sna.h index 51533995..e51ee14f 100644 --- a/src/sna/sna.h +++ b/src/sna/sna.h @@ -591,13 +591,51 @@ static inline void sna_present_vblank_handler(struct drm_event_vblank *event) { #endif extern bool sna_crtc_set_sprite_rotation(xf86CrtcPtr crtc, uint32_t rotation); -extern int sna_crtc_to_pipe(xf86CrtcPtr crtc); -extern int sna_crtc_to_pipe__safe(xf86CrtcPtr crtc); extern uint32_t sna_crtc_to_sprite(xf86CrtcPtr crtc); -extern uint32_t sna_crtc_id(xf86CrtcPtr crtc); -extern bool sna_crtc_is_on(xf86CrtcPtr crtc); extern bool sna_crtc_is_transformed(xf86CrtcPtr crtc); +#define CRTC_VBLANK 0x3 +#define CRTC_ON 0x80000000 + +static inline unsigned long *sna_crtc_flags(xf86CrtcPtr crtc) +{ + unsigned long *flags = crtc->driver_private; + assert(flags); + return flags; +} + +static inline unsigned sna_crtc_pipe(xf86CrtcPtr crtc) +{ + return *sna_crtc_flags(crtc) >> 8 & 0xff; +} + +static inline unsigned sna_crtc_id(xf86CrtcPtr crtc) +{ + return *sna_crtc_flags(crtc) >> 16 & 0xff; +} + +static inline bool sna_crtc_is_on(xf86CrtcPtr crtc) +{ + return *sna_crtc_flags(crtc) & CRTC_ON; +} + +static inline void sna_crtc_set_vblank(xf86CrtcPtr crtc) +{ + assert((*sna_crtc_flags(crtc) & CRTC_VBLANK) < 2); + ++*sna_crtc_flags(crtc); +} + +static inline void sna_crtc_clear_vblank(xf86CrtcPtr crtc) +{ + assert(*sna_crtc_flags(crtc) & CRTC_VBLANK); + --*sna_crtc_flags(crtc); +} + +static inline bool sna_crtc_has_vblank(xf86CrtcPtr crtc) +{ + return *sna_crtc_flags(crtc) & CRTC_VBLANK; +} + CARD32 sna_format_for_depth(int depth); CARD32 sna_render_format_for_depth(int depth); diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c index 6b2c3ef2..0183246d 100644 --- a/src/sna/sna_display.c +++ b/src/sna/sna_display.c @@ -144,6 +144,7 @@ struct sna_cursor { }; struct sna_crtc { + unsigned long flags; xf86CrtcPtr base; struct drm_mode_modeinfo kmode; PixmapPtr slave_pixmap; @@ -158,8 +159,6 @@ struct sna_crtc { bool cursor_transform; bool hwcursor; bool flip_pending; - uint8_t id; - uint8_t pipe; RegionRec client_damage; /* XXX overlap with shadow damage? */ @@ -281,6 +280,16 @@ static inline struct sna_crtc *to_sna_crtc(xf86CrtcPtr crtc) return crtc->driver_private; } +static inline unsigned __sna_crtc_pipe(struct sna_crtc *crtc) +{ + return crtc->flags >> 8 & 0xff; +} + +static inline unsigned __sna_crtc_id(struct sna_crtc *crtc) +{ + return crtc->flags >> 16 & 0xff; +} + static inline bool event_pending(int fd) { struct pollfd pfd; @@ -302,39 +311,12 @@ static inline uint32_t fb_id(struct kgem_bo *bo) return bo->delta; } -uint32_t sna_crtc_id(xf86CrtcPtr crtc) -{ - if (to_sna_crtc(crtc) == NULL) - return 0; - return to_sna_crtc(crtc)->id; -} - -int sna_crtc_to_pipe(xf86CrtcPtr crtc) -{ - assert(to_sna_crtc(crtc)); - return to_sna_crtc(crtc)->pipe; -} - -int sna_crtc_to_pipe__safe(xf86CrtcPtr crtc) -{ - if (to_sna_crtc(crtc)) - return sna_crtc_to_pipe(crtc); - else - return sna_crtc_to_pipe(sna_primary_crtc(to_sna(crtc->scrn))); -} - uint32_t sna_crtc_to_sprite(xf86CrtcPtr crtc) { assert(to_sna_crtc(crtc)); return to_sna_crtc(crtc)->sprite.id; } -bool sna_crtc_is_on(xf86CrtcPtr crtc) -{ - assert(to_sna_crtc(crtc)); - return to_sna_crtc(crtc)->bo != NULL; -} - bool sna_crtc_is_transformed(xf86CrtcPtr crtc) { assert(to_sna_crtc(crtc)); @@ -348,11 +330,11 @@ static inline bool msc64(struct sna_crtc *sna_crtc, uint32_t seq, uint64_t *msc) if (sna_crtc->last_seq - seq > 0x40000000) { sna_crtc->wrap_seq++; DBG(("%s: pipe=%d wrapped; was %u, now %u, wraps=%u\n", - __FUNCTION__, sna_crtc->pipe, + __FUNCTION__, __sna_crtc_pipe(sna_crtc), sna_crtc->last_seq, seq, sna_crtc->wrap_seq)); } else { DBG(("%s: pipe=%d msc went backwards; was %u, now %u; ignoring for last_swap\n", - __FUNCTION__, sna_crtc->pipe, sna_crtc->last_seq, seq)); + __FUNCTION__, __sna_crtc_pipe(sna_crtc), sna_crtc->last_seq, seq)); record = false; } @@ -371,14 +353,14 @@ uint64_t sna_crtc_record_swap(xf86CrtcPtr crtc, if (msc64(sna_crtc, seq, &msc)) { DBG(("%s: recording last swap on pipe=%d, frame %d [%08llx], time %d.%06d\n", - __FUNCTION__, sna_crtc->pipe, seq, (long long)msc, + __FUNCTION__, __sna_crtc_pipe(sna_crtc), seq, (long long)msc, tv_sec, tv_usec)); sna_crtc->swap.tv_sec = tv_sec; sna_crtc->swap.tv_usec = tv_usec; sna_crtc->swap.msc = msc; } else { DBG(("%s: swap event on pipe=%d, frame %d [%08llx], time %d.%06d\n", - __FUNCTION__, sna_crtc->pipe, seq, (long long)msc, + __FUNCTION__, __sna_crtc_pipe(sna_crtc), seq, (long long)msc, tv_sec, tv_usec)); } @@ -939,7 +921,7 @@ sna_crtc_force_outputs_on(xf86CrtcPtr crtc) int i; assert(to_sna_crtc(crtc)); - DBG(("%s(pipe=%d)\n", __FUNCTION__, to_sna_crtc(crtc)->pipe)); + DBG(("%s(pipe=%d)\n", __FUNCTION__, sna_crtc_pipe(crtc))); /* DPMS handling by the kernel is inconsistent, so after setting a * mode on an output presume that we intend for it to be on, or that @@ -969,7 +951,7 @@ sna_crtc_force_outputs_off(xf86CrtcPtr crtc) int i; assert(to_sna_crtc(crtc)); - DBG(("%s(pipe=%d)\n", __FUNCTION__, to_sna_crtc(crtc)->pipe)); + DBG(("%s(pipe=%d)\n", __FUNCTION__, sna_crtc_pipe(crtc))); /* DPMS handling by the kernel is inconsistent, so after setting a * mode on an output presume that we intend for it to be on, or that @@ -1068,8 +1050,8 @@ bool sna_crtc_set_sprite_rotation(xf86CrtcPtr crtc, uint32_t rotation) assert(to_sna_crtc(crtc)); DBG(("%s: CRTC:%d [pipe=%d], sprite=%u set-rotation=%x\n", __FUNCTION__, - to_sna_crtc(crtc)->id, to_sna_crtc(crtc)->pipe, to_sna_crtc(crtc)->sprite.id, - rotation)); + sna_crtc_id(crtc), sna_crtc_pipe(crtc), + to_sna_crtc(crtc)->sprite.id, rotation)); return rotation_set(to_sna(crtc->scrn), &to_sna_crtc(crtc)->sprite, @@ -1087,10 +1069,12 @@ sna_crtc_apply(xf86CrtcPtr crtc) int output_count = 0; int i; - DBG(("%s CRTC:%d [pipe=%d], handle=%d\n", __FUNCTION__, sna_crtc->id, sna_crtc->pipe, sna_crtc->bo->handle)); + DBG(("%s CRTC:%d [pipe=%d], handle=%d\n", __FUNCTION__, + __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), + sna_crtc->bo->handle)); if (!sna_crtc->kmode.clock) { ERR(("%s(CRTC:%d [pipe=%d]): attempted to set an invalid mode\n", - __FUNCTION__, sna_crtc->id, sna_crtc->pipe)); + __FUNCTION__, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc))); return false; } @@ -1099,12 +1083,12 @@ sna_crtc_apply(xf86CrtcPtr crtc) if (!rotation_set(sna, &sna_crtc->primary, sna_crtc->rotation)) { ERR(("%s: set-primary-rotation failed (rotation-id=%d, rotation=%d) on CRTC:%d [pipe=%d], errno=%d\n", - __FUNCTION__, sna_crtc->primary.rotation.prop, sna_crtc->rotation, sna_crtc->id, sna_crtc->pipe, errno)); + __FUNCTION__, sna_crtc->primary.rotation.prop, sna_crtc->rotation, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), errno)); sna_crtc->primary.rotation.supported &= ~sna_crtc->rotation; return false; } DBG(("%s: CRTC:%d [pipe=%d] primary rotation set to %x\n", - __FUNCTION__, sna_crtc->id, sna_crtc->pipe, sna_crtc->rotation)); + __FUNCTION__, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), sna_crtc->rotation)); for (i = 0; i < sna->mode.num_real_output; i++) { xf86OutputPtr output = config->output[i]; @@ -1129,11 +1113,11 @@ sna_crtc_apply(xf86CrtcPtr crtc) DBG(("%s: attaching output '%s' %d [%d] to crtc:%d (pipe %d) (possible crtc:%x, possible clones:%x)\n", __FUNCTION__, output->name, i, to_connector_id(output), - sna_crtc->id, sna_crtc->pipe, + __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), (uint32_t)output->possible_crtcs, (uint32_t)output->possible_clones)); - assert(output->possible_crtcs & (1 << sna_crtc->pipe) || + assert(output->possible_crtcs & (1 << __sna_crtc_pipe(sna_crtc)) || is_zaphod(crtc->scrn)); output_ids[output_count] = to_connector_id(output); @@ -1151,7 +1135,7 @@ sna_crtc_apply(xf86CrtcPtr crtc) } VG_CLEAR(arg); - arg.crtc_id = sna_crtc->id; + arg.crtc_id = __sna_crtc_id(sna_crtc); arg.fb_id = fb_id(sna_crtc->bo); if (sna_crtc->transform || sna_crtc->slave_pixmap) { arg.x = 0; @@ -1168,7 +1152,7 @@ sna_crtc_apply(xf86CrtcPtr crtc) arg.mode_valid = 1; DBG(("%s: applying crtc [%d, pipe=%d] mode=%dx%d+%d+%d@%d, fb=%d%s%s update to %d outputs [%d...]\n", - __FUNCTION__, sna_crtc->id, sna_crtc->pipe, + __FUNCTION__, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), arg.mode.hdisplay, arg.mode.vdisplay, arg.x, arg.y, @@ -1535,7 +1519,7 @@ static void sna_crtc_slave_damage(DamagePtr damage, RegionPtr region, void *clos __FUNCTION__, region->extents.x1, region->extents.y1, region->extents.x2, region->extents.y2, region_num_rects(region), - crtc->pipe, crtc->base->x, crtc->base->y)); + __sna_crtc_pipe(crtc), crtc->base->x, crtc->base->y)); assert(crtc->slave_damage == damage); assert(sna->mode.shadow_damage); @@ -1553,7 +1537,7 @@ static bool sna_crtc_enable_shadow(struct sna *sna, struct sna_crtc *crtc) return true; } - DBG(("%s: enabling for crtc %d\n", __FUNCTION__, crtc->id)); + DBG(("%s: enabling for crtc %d\n", __FUNCTION__, __sna_crtc_id(crtc))); if (!sna->mode.shadow_active) { if (!sna_mode_enable_shadow(sna)) @@ -1566,7 +1550,7 @@ static bool sna_crtc_enable_shadow(struct sna *sna, struct sna_crtc *crtc) assert(crtc->slave_damage == NULL); DBG(("%s: enabling PRIME slave tracking on CRTC %d [pipe=%d], pixmap=%ld\n", - __FUNCTION__, crtc->id, crtc->pipe, crtc->slave_pixmap->drawable.serialNumber)); + __FUNCTION__, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), crtc->slave_pixmap->drawable.serialNumber)); crtc->slave_damage = DamageCreate(sna_crtc_slave_damage, NULL, DamageReportRawRegion, TRUE, to_screen_from_sna(sna), @@ -1616,7 +1600,7 @@ static void sna_crtc_disable_shadow(struct sna *sna, struct sna_crtc *crtc) if (!crtc->shadow) return; - DBG(("%s: disabling for crtc %d\n", __FUNCTION__, crtc->id)); + DBG(("%s: disabling for crtc %d\n", __FUNCTION__, __sna_crtc_id(crtc))); assert(sna->mode.shadow_active > 0); if (crtc->slave_damage) { @@ -1646,11 +1630,13 @@ __sna_crtc_disable(struct sna *sna, struct sna_crtc *sna_crtc) if (sna_crtc->bo) { DBG(("%s: releasing handle=%d from scanout, active=%d\n", __FUNCTION__,sna_crtc->bo->handle, sna_crtc->bo->active_scanout-1)); + assert(sna_crtc->flags & CRTC_ON); assert(sna_crtc->bo->active_scanout); assert(sna_crtc->bo->refcnt >= sna_crtc->bo->active_scanout); sna_crtc->bo->active_scanout--; kgem_bo_destroy(&sna->kgem, sna_crtc->bo); sna_crtc->bo = NULL; + sna_crtc->flags &= ~CRTC_ON; if (sna->mode.hidden) { sna->mode.hidden--; @@ -1692,12 +1678,12 @@ sna_crtc_disable(xf86CrtcPtr crtc, bool force) return; DBG(("%s: disabling crtc [%d, pipe=%d], force?=%d\n", __FUNCTION__, - sna_crtc->id, sna_crtc->pipe, force)); + __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), force)); sna_crtc_force_outputs_off(crtc); memset(&arg, 0, sizeof(arg)); - arg.crtc_id = sna_crtc->id; + arg.crtc_id = __sna_crtc_id(sna_crtc); (void)drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_SETCRTC, &arg); __sna_crtc_disable(sna, sna_crtc); @@ -1717,19 +1703,19 @@ static void update_flush_interval(struct sna *sna) if (!crtc->enabled) { DBG(("%s: CRTC:%d (pipe %d) disabled\n", - __FUNCTION__,i, to_sna_crtc(crtc)->pipe)); + __FUNCTION__,i, sna_crtc_pipe(crtc))); assert(to_sna_crtc(crtc)->bo == NULL); continue; } if (to_sna_crtc(crtc)->bo == NULL) { DBG(("%s: CRTC:%d (pipe %d) turned off\n", - __FUNCTION__,i, to_sna_crtc(crtc)->pipe)); + __FUNCTION__,i, sna_crtc_pipe(crtc))); continue; } DBG(("%s: CRTC:%d (pipe %d) vrefresh=%f\n", - __FUNCTION__, i, to_sna_crtc(crtc)->pipe, + __FUNCTION__, i, sna_crtc_pipe(crtc), xf86ModeVRefresh(&crtc->mode))); max_vrefresh = max(max_vrefresh, xf86ModeVRefresh(&crtc->mode)); } @@ -1805,7 +1791,7 @@ void sna_copy_fbcon(struct sna *sna) assert(crtc != NULL); VG_CLEAR(mode); - mode.crtc_id = crtc->id; + mode.crtc_id = __sna_crtc_id(crtc); if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode)) continue; if (!mode.fb_id) @@ -2445,7 +2431,7 @@ sna_crtc_damage(xf86CrtcPtr crtc) } DBG(("%s: marking crtc %d as completely damaged (%d, %d), (%d, %d)\n", - __FUNCTION__, to_sna_crtc(crtc)->id, + __FUNCTION__, sna_crtc_id(crtc), region.extents.x1, region.extents.y1, region.extents.x2, region.extents.y2)); to_sna_crtc(crtc)->client_damage = region; @@ -2516,7 +2502,7 @@ __sna_crtc_set_mode(xf86CrtcPtr crtc) bool saved_cursor_transform; DBG(("%s: CRTC=%d, pipe=%d, hidden?=%d\n", __FUNCTION__, - sna_crtc->id, sna_crtc->pipe, sna->mode.hidden)); + __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), sna->mode.hidden)); if (sna->mode.hidden) return TRUE; @@ -2555,6 +2541,7 @@ retry: /* Attach per-crtc pixmap or direct */ goto error; } + sna_crtc->flags |= CRTC_ON; bo->active_scanout++; DBG(("%s: marking handle=%d as active=%d (removing %d from scanout, active=%d)\n", __FUNCTION__, bo->handle, bo->active_scanout, @@ -2616,14 +2603,14 @@ sna_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, xf86DrvMsg(crtc->scrn->scrnIndex, X_INFO, "switch to mode %dx%d@%.1f on %s using pipe %d, position (%d, %d), rotation %s, reflection %s\n", mode->HDisplay, mode->VDisplay, xf86ModeVRefresh(mode), - outputs_for_crtc(crtc, outputs, sizeof(outputs)), sna_crtc->pipe, + outputs_for_crtc(crtc, outputs, sizeof(outputs)), __sna_crtc_pipe(sna_crtc), x, y, rotation_to_str(rotation), reflection_to_str(rotation)); assert(mode->HDisplay <= sna->mode.max_crtc_width && mode->VDisplay <= sna->mode.max_crtc_height); #if HAS_GAMMA - drmModeCrtcSetGamma(sna->kgem.fd, sna_crtc->id, + drmModeCrtcSetGamma(sna->kgem.fd, __sna_crtc_id(sna_crtc), crtc->gamma_size, crtc->gamma_red, crtc->gamma_green, @@ -2643,7 +2630,7 @@ static void sna_crtc_dpms(xf86CrtcPtr crtc, int mode) { DBG(("%s(pipe %d, dpms mode -> %d):= active=%d\n", - __FUNCTION__, to_sna_crtc(crtc)->pipe, mode, mode == DPMSModeOn)); + __FUNCTION__, sna_crtc_pipe(crtc), mode, mode == DPMSModeOn)); if (mode == DPMSModeOn && crtc->enabled) { if (__sna_crtc_set_mode(crtc)) @@ -2689,7 +2676,7 @@ sna_crtc_gamma_set(xf86CrtcPtr crtc, { assert(to_sna_crtc(crtc)); drmModeCrtcSetGamma(to_sna(crtc->scrn)->kgem.fd, - to_sna_crtc(crtc)->id, + sna_crtc_id(crtc), size, red, green, blue); } @@ -2718,7 +2705,7 @@ sna_crtc_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr pixmap) return TRUE; DBG(("%s: CRTC:%d, pipe=%d setting scanout pixmap=%ld\n", - __FUNCTION__, sna_crtc->id, sna_crtc->pipe, + __FUNCTION__, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), pixmap ? pixmap->drawable.serialNumber : 0)); /* Disable first so that we can unregister the damage tracking */ @@ -2912,11 +2899,11 @@ sna_crtc_find_planes(struct sna *sna, struct sna_crtc *crtc) if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_GETPLANE, &p)) continue; - if ((p.possible_crtcs & (1 << crtc->pipe)) == 0) + if ((p.possible_crtcs & (1 << __sna_crtc_pipe(crtc))) == 0) continue; DBG(("%s: plane %d is attached to our pipe=%d\n", - __FUNCTION__, planes[i], crtc->pipe)); + __FUNCTION__, planes[i], __sna_crtc_pipe(crtc))); details.id = p.plane_id; details.rotation.prop = 0; @@ -2961,7 +2948,7 @@ sna_crtc_init__cursor(struct sna *sna, struct sna_crtc *crtc) VG_CLEAR(arg); arg.flags = DRM_MODE_CURSOR_BO; - arg.crtc_id = crtc->id; + arg.crtc_id = __sna_crtc_id(crtc); arg.width = arg.height = 0; arg.handle = 0; @@ -2970,7 +2957,7 @@ sna_crtc_init__cursor(struct sna *sna, struct sna_crtc *crtc) } static bool -sna_crtc_add(ScrnInfoPtr scrn, int id) +sna_crtc_add(ScrnInfoPtr scrn, unsigned id) { struct sna *sna = to_sna(scrn); xf86CrtcPtr crtc; @@ -2983,21 +2970,23 @@ sna_crtc_add(ScrnInfoPtr scrn, int id) if (sna_crtc == NULL) return false; - sna_crtc->id = id; + assert(id < 256); + sna_crtc->flags = id << 16; VG_CLEAR(get_pipe); get_pipe.pipe = 0; - get_pipe.crtc_id = sna_crtc->id; + get_pipe.crtc_id = id; if (drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GET_PIPE_FROM_CRTC_ID, &get_pipe)) { free(sna_crtc); return false; } - sna_crtc->pipe = get_pipe.pipe; + assert((unsigned)get_pipe.pipe < 256); + sna_crtc->flags |= get_pipe.pipe << 8; if (is_zaphod(scrn) && - scrn->confScreen->device->screen != sna_crtc->pipe) { + scrn->confScreen->device->screen != get_pipe.pipe) { free(sna_crtc); return true; } @@ -3007,7 +2996,7 @@ sna_crtc_add(ScrnInfoPtr scrn, int id) sna_crtc_find_planes(sna, sna_crtc); DBG(("%s: CRTC:%d [pipe=%d], primary id=%x: supported-rotations=%x, current-rotation=%x, sprite id=%x: supported-rotations=%x, current-rotation=%x\n", - __FUNCTION__, sna_crtc->id, sna_crtc->pipe, + __FUNCTION__, id, get_pipe.pipe, sna_crtc->primary.id, sna_crtc->primary.rotation.supported, sna_crtc->primary.rotation.current, sna_crtc->sprite.id, sna_crtc->sprite.rotation.supported, sna_crtc->sprite.rotation.current)); @@ -3024,7 +3013,7 @@ sna_crtc_add(ScrnInfoPtr scrn, int id) crtc->driver_private = sna_crtc; sna_crtc->base = crtc; DBG(("%s: attached crtc[%d] pipe=%d\n", - __FUNCTION__, id, sna_crtc->pipe)); + __FUNCTION__, id, __sna_crtc_pipe(sna_crtc))); return true; } @@ -3486,12 +3475,12 @@ sna_output_get_modes(xf86OutputPtr output) VG_CLEAR(mode); assert(to_sna_crtc(output->crtc)); - mode.crtc_id = to_sna_crtc(output->crtc)->id; + mode.crtc_id = sna_crtc_id(output->crtc); if (drmIoctl(to_sna(output->scrn)->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode) == 0) { DBG(("%s: CRTC:%d, pipe=%d: has mode?=%d\n", __FUNCTION__, - to_sna_crtc(output->crtc)->id, - to_sna_crtc(output->crtc)->pipe, + sna_crtc_id(output->crtc), + sna_crtc_pipe(output->crtc), mode.mode_valid && mode.mode.clock)); if (mode.mode_valid && mode.mode.clock) { @@ -4600,7 +4589,7 @@ static bool disable_unused_crtc(struct sna *sna) if (o == sna->mode.num_real_output) { DBG(("%s: CRTC:%d was enabled with no outputs\n", - __FUNCTION__, to_sna_crtc(crtc)->id)); + __FUNCTION__, sna_crtc_id(crtc))); crtc->enabled = false; update = true; } @@ -5288,7 +5277,7 @@ sna_show_cursors(ScrnInfoPtr scrn) if (!crtc->cursor_in_range) { DBG(("%s: skipping cursor outside CRTC (pipe=%d)\n", - __FUNCTION__, sna_crtc->pipe)); + __FUNCTION__, sna_crtc_pipe(crtc))); continue; } @@ -5296,16 +5285,16 @@ sna_show_cursors(ScrnInfoPtr scrn) if (cursor == NULL || (sna_crtc->cursor == cursor && sna_crtc->last_cursor_size == cursor->size)) { DBG(("%s: skipping cursor already show on CRTC (pipe=%d)\n", - __FUNCTION__, sna_crtc->pipe)); + __FUNCTION__, sna_crtc_pipe(crtc))); continue; } DBG(("%s: CRTC pipe=%d, handle->%d\n", __FUNCTION__, - sna_crtc->pipe, cursor->handle)); + sna_crtc_pipe(crtc), cursor->handle)); VG_CLEAR(arg); arg.flags = DRM_MODE_CURSOR_BO; - arg.crtc_id = sna_crtc->id; + arg.crtc_id = __sna_crtc_id(sna_crtc); arg.width = arg.height = cursor->size; arg.handle = cursor->handle; @@ -5363,7 +5352,7 @@ sna_crtc_disable_cursor(struct sna *sna, struct sna_crtc *crtc) sigio = sigio_block(); if (crtc->cursor) { - DBG(("%s: CRTC:%d, handle=%d\n", __FUNCTION__, crtc->id, crtc->cursor->handle)); + DBG(("%s: CRTC:%d, handle=%d\n", __FUNCTION__, __sna_crtc_id(crtc), crtc->cursor->handle)); assert(crtc->cursor->ref > 0); crtc->cursor->ref--; crtc->cursor = NULL; @@ -5371,7 +5360,7 @@ sna_crtc_disable_cursor(struct sna *sna, struct sna_crtc *crtc) VG_CLEAR(arg); arg.flags = DRM_MODE_CURSOR_BO; - arg.crtc_id = crtc->id; + arg.crtc_id = __sna_crtc_id(crtc); arg.width = arg.height = 0; arg.handle = 0; @@ -5464,7 +5453,7 @@ sna_set_cursor_position(ScrnInfoPtr scrn, int x, int y) VG_CLEAR(arg); arg.flags = 0; - arg.crtc_id = sna_crtc->id; + arg.crtc_id = __sna_crtc_id(sna_crtc); arg.handle = 0; if (sna_crtc->bo == NULL) @@ -5520,7 +5509,7 @@ disable: } __DBG(("%s: CRTC:%d (%d, %d), handle=%d, flags=%x (old cursor handle=%d), move? %d, update handle? %d\n", - __FUNCTION__, sna_crtc->id, arg.x, arg.y, arg.handle, arg.flags, sna_crtc->cursor ? sna_crtc->cursor->handle : 0, + __FUNCTION__, __sna_crtc_id(sna_crtc), arg.x, arg.y, arg.handle, arg.flags, sna_crtc->cursor ? sna_crtc->cursor->handle : 0, arg.flags & DRM_MODE_CURSOR_MOVE, arg.flags & DRM_MODE_CURSOR_BO)); if (arg.flags && @@ -5596,7 +5585,7 @@ transformable_cursor(struct sna *sna, CursorPtr cursor) if (!to_sna_crtc(crtc)->hwcursor) { DBG(("%s: hwcursor disabled on CRTC:%d [pipe=%d]\n", - __FUNCTION__, to_sna_crtc(crtc)->id, to_sna_crtc(crtc)->pipe)); + __FUNCTION__, sna_crtc_id(crtc), sna_crtc_pipe(crtc))); return false; } @@ -5824,7 +5813,7 @@ sna_crtc_flip(struct sna *sna, struct sna_crtc *crtc, struct kgem_bo *bo, int x, int output_count = 0; int i; - DBG(("%s CRTC:%d [pipe=%d], handle=%d\n", __FUNCTION__, crtc->id, crtc->pipe, bo->handle)); + DBG(("%s CRTC:%d [pipe=%d], handle=%d\n", __FUNCTION__, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), bo->handle)); assert(sna->mode.num_real_output < ARRAY_SIZE(output_ids)); assert(crtc->bo); @@ -5838,11 +5827,11 @@ sna_crtc_flip(struct sna *sna, struct sna_crtc *crtc, struct kgem_bo *bo, int x, DBG(("%s: attaching output '%s' %d [%d] to crtc:%d (pipe %d) (possible crtc:%x, possible clones:%x)\n", __FUNCTION__, output->name, i, to_connector_id(output), - crtc->id, crtc->pipe, + __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), (uint32_t)output->possible_crtcs, (uint32_t)output->possible_clones)); - assert(output->possible_crtcs & (1 << crtc->pipe) || + assert(output->possible_crtcs & (1 << __sna_crtc_pipe(crtc)) || is_zaphod(sna->scrn)); output_ids[output_count] = to_connector_id(output); @@ -5852,7 +5841,7 @@ sna_crtc_flip(struct sna *sna, struct sna_crtc *crtc, struct kgem_bo *bo, int x, assert(output_count); VG_CLEAR(arg); - arg.crtc_id = crtc->id; + arg.crtc_id = __sna_crtc_id(crtc); arg.fb_id = fb_id(bo); assert(arg.fb_id); arg.x = x; @@ -5863,7 +5852,7 @@ sna_crtc_flip(struct sna *sna, struct sna_crtc *crtc, struct kgem_bo *bo, int x, arg.mode_valid = 1; DBG(("%s: applying crtc [%d, pipe=%d] mode=%dx%d+%d+%d@%d, fb=%d across %d outputs [%d...]\n", - __FUNCTION__, crtc->id, crtc->pipe, + __FUNCTION__, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), arg.mode.hdisplay, arg.mode.vdisplay, arg.x, arg.y, @@ -5941,7 +5930,7 @@ sna_page_flip(struct sna *sna, uint32_t crtc_offset; DBG(("%s: crtc %d id=%d, pipe=%d active? %d\n", - __FUNCTION__, i, crtc->id, crtc->pipe, crtc->bo != NULL)); + __FUNCTION__, i, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), crtc->bo != NULL)); if (crtc->bo == NULL) continue; assert(!crtc->transform); @@ -5953,7 +5942,7 @@ sna_page_flip(struct sna *sna, if (data == NULL && crtc->bo == bo) goto next_crtc; - arg.crtc_id = crtc->id; + arg.crtc_id = __sna_crtc_id(crtc); arg.fb_id = get_fb(sna, bo, width, height); if (arg.fb_id == 0) { assert(count == 0); @@ -6011,7 +6000,7 @@ update_scanout: retry_flip: DBG(("%s: crtc %d id=%d, pipe=%d --> fb %d\n", - __FUNCTION__, i, crtc->id, crtc->pipe, arg.fb_id)); + __FUNCTION__, i, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), arg.fb_id)); if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_PAGE_FLIP, &arg)) { ERR(("%s: pageflip failed with err=%d\n", __FUNCTION__, errno)); @@ -6019,7 +6008,7 @@ retry_flip: struct drm_mode_crtc mode; memset(&mode, 0, sizeof(mode)); - mode.crtc_id = crtc->id; + mode.crtc_id = __sna_crtc_id(crtc); drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode); DBG(("%s: crtc=%d, valid?=%d, fb attached?=%d, expected=%d\n", @@ -6043,7 +6032,7 @@ retry_flip: if (sna->flags & (data ? SNA_HAS_FLIP : SNA_HAS_ASYNC_FLIP)) { xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR, "page flipping failed, on CRTC:%d (pipe=%d), disabling %s page flips\n", - crtc->id, crtc->pipe, data ? "synchronous": "asynchronous"); + __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), data ? "synchronous": "asynchronous"); sna->flags &= ~(data ? SNA_HAS_FLIP : SNA_HAS_ASYNC_FLIP); goto fixup_flip; } @@ -6064,7 +6053,7 @@ retry_flip: sna->mode.flip_active++; DBG(("%s: recording flip on CRTC:%d handle=%d, active_scanout=%d, serial=%d\n", - __FUNCTION__, crtc->id, crtc->flip_bo->handle, crtc->flip_bo->active_scanout, crtc->flip_serial)); + __FUNCTION__, __sna_crtc_id(crtc), crtc->flip_bo->handle, crtc->flip_bo->active_scanout, crtc->flip_serial)); } else goto update_scanout; next_crtc: @@ -6145,7 +6134,7 @@ static void crtc_init_gamma(xf86CrtcPtr crtc) assert(sna_crtc); - lut.crtc_id = sna_crtc->id; + lut.crtc_id = __sna_crtc_id(sna_crtc); lut.gamma_size = 256; lut.red = (uintptr_t)(gamma); lut.green = (uintptr_t)(gamma + 256); @@ -6159,7 +6148,7 @@ static void crtc_init_gamma(xf86CrtcPtr crtc) } DBG(("%s: CRTC:%d, pipe=%d: gamma set?=%d\n", - __FUNCTION__, sna_crtc->id, sna_crtc->pipe, + __FUNCTION__, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), gamma_set)); if (!gamma_set) { int i; @@ -6251,12 +6240,12 @@ static bool sna_probe_initial_configuration(struct sna *sna) /* Retrieve the current mode */ VG_CLEAR(mode); - mode.crtc_id = sna_crtc->id; + mode.crtc_id = __sna_crtc_id(sna_crtc); if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode)) continue; DBG(("%s: CRTC:%d, pipe=%d: has mode?=%d\n", __FUNCTION__, - sna_crtc->id, sna_crtc->pipe, + __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), mode.mode_valid && mode.mode.clock)); if (!mode.mode_valid || mode.mode.clock == 0) @@ -6298,7 +6287,7 @@ static bool sna_probe_initial_configuration(struct sna *sna) xf86CrtcPtr crtc = config->crtc[j]; assert(to_sna_crtc(crtc)); - if (to_sna_crtc(crtc)->id != crtc_id) + if (sna_crtc_id(crtc) != crtc_id) continue; if (crtc->desiredMode.status == MODE_OK) { @@ -6316,7 +6305,7 @@ static bool sna_probe_initial_configuration(struct sna *sna) "Output %s using initial mode %s on pipe %d\n", output->name, crtc->desiredMode.name, - to_sna_crtc(crtc)->pipe); + sna_crtc_pipe(crtc)); output->crtc = crtc; output->status = XF86OutputStatusConnected; @@ -7154,7 +7143,7 @@ sna_wait_for_scanline(struct sna *sna, y2 /= 2; } - pipe = sna_crtc_to_pipe(crtc); + pipe = sna_crtc_pipe(crtc); DBG(("%s: pipe=%d, y1=%d, y2=%d, full_height?=%d\n", __FUNCTION__, pipe, y1, y2, full_height)); @@ -7206,7 +7195,7 @@ void sna_mode_check(struct sna *sna) expected[1] = sna_crtc->flip_bo ? fb_id(sna_crtc->flip_bo) : -1; VG_CLEAR(mode); - mode.crtc_id = sna_crtc->id; + mode.crtc_id = __sna_crtc_id(sna_crtc); if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode)) continue; @@ -7218,7 +7207,7 @@ void sna_mode_check(struct sna *sna) if (mode.fb_id != expected[0] && mode.fb_id != expected[1]) { xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, "%s: invalid state found on pipe %d, disabling CRTC:%d\n", - __FUNCTION__, sna_crtc->pipe, sna_crtc->id); + __FUNCTION__, __sna_crtc_pipe(sna_crtc), __sna_crtc_id(sna_crtc)); sna_crtc_disable(crtc, true); } } @@ -7604,7 +7593,7 @@ sna_crtc_redisplay(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo *bo) struct sna_pixmap *priv = sna_pixmap((PixmapPtr)draw); DBG(("%s: crtc %d [pipe=%d], damage (%d, %d), (%d, %d) x %d\n", - __FUNCTION__, to_sna_crtc(crtc)->id, to_sna_crtc(crtc)->pipe, + __FUNCTION__, sna_crtc_id(crtc), sna_crtc_pipe(crtc), region->extents.x1, region->extents.y1, region->extents.x2, region->extents.y2, region_num_rects(region))); @@ -7673,11 +7662,11 @@ void sna_shadow_set_crtc(struct sna *sna, struct sna_crtc *sna_crtc = to_sna_crtc(crtc); struct sna_pixmap *priv; + assert(sna_crtc); DBG(("%s: setting shadow override for CRTC:%d to handle=%d\n", - __FUNCTION__, sna_crtc->id, bo->handle)); + __FUNCTION__, __sna_crtc_id(sna_crtc), bo->handle)); assert(sna->flags & SNA_TEAR_FREE); - assert(sna_crtc); assert(!sna_crtc->transform); if (sna_crtc->client_bo != bo) { @@ -7737,7 +7726,7 @@ void sna_shadow_unset_crtc(struct sna *sna, struct sna_crtc *sna_crtc = to_sna_crtc(crtc); DBG(("%s: clearin shadow override for CRTC:%d\n", - __FUNCTION__, sna_crtc->id)); + __FUNCTION__, __sna_crtc_id(sna_crtc))); if (sna_crtc->client_bo == NULL) return; @@ -7771,7 +7760,7 @@ static bool move_crtc_to_gpu(struct sna *sna) continue; DBG(("%s: CRTC %d [pipe=%d] requires frontbuffer\n", - __FUNCTION__, crtc->id, crtc->pipe)); + __FUNCTION__, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc))); return sna_pixmap_move_to_gpu(sna->front, MOVE_READ | MOVE_ASYNC_HINT | __MOVE_SCANOUT); } @@ -7849,7 +7838,7 @@ void sna_mode_redisplay(struct sna *sna) struct kgem_bo *bo = NULL; DBG(("%s: fallback intersects pipe=%d [(%d, %d), (%d, %d)]\n", - __FUNCTION__, sna_crtc->pipe, + __FUNCTION__, __sna_crtc_pipe(sna_crtc), damage.extents.x1, damage.extents.y1, damage.extents.x2, damage.extents.y2)); @@ -7884,7 +7873,7 @@ void sna_mode_redisplay(struct sna *sna) if (bo != sna_crtc->bo) { struct drm_mode_crtc_page_flip arg; - arg.crtc_id = sna_crtc->id; + arg.crtc_id = __sna_crtc_id(sna_crtc); arg.fb_id = get_fb(sna, bo, crtc->mode.HDisplay, crtc->mode.VDisplay); @@ -7908,7 +7897,7 @@ void sna_mode_redisplay(struct sna *sna) sna_crtc->cache_bo = NULL; } else { DBG(("%s: flip [fb=%d] on crtc %d [%d, pipe=%d] failed - %d\n", - __FUNCTION__, arg.fb_id, i, sna_crtc->id, sna_crtc->pipe, errno)); + __FUNCTION__, arg.fb_id, i, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), errno)); xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR, "Page flipping failed, disabling TearFree\n"); sna->flags &= ~SNA_TEAR_FREE; @@ -7934,7 +7923,7 @@ void sna_mode_redisplay(struct sna *sna) sna_crtc->cache_bo = kgem_bo_reference(sna_crtc->bo); DBG(("%s: recording flip on CRTC:%d handle=%d, active_scanout=%d, serial=%d\n", - __FUNCTION__, sna_crtc->id, sna_crtc->flip_bo->handle, sna_crtc->flip_bo->active_scanout, sna_crtc->flip_serial)); + __FUNCTION__, __sna_crtc_id(sna_crtc), sna_crtc->flip_bo->handle, sna_crtc->flip_bo->active_scanout, sna_crtc->flip_serial)); } } } @@ -8021,7 +8010,7 @@ void sna_mode_redisplay(struct sna *sna) sna_crtc_redisplay(crtc, &damage, bo); kgem_bo_submit(&sna->kgem, bo); - arg.crtc_id = sna_crtc->id; + arg.crtc_id = __sna_crtc_id(sna_crtc); arg.fb_id = get_fb(sna, bo, crtc->mode.HDisplay, crtc->mode.VDisplay); @@ -8050,7 +8039,7 @@ void sna_mode_redisplay(struct sna *sna) DrawableRec tmp; DBG(("%s: flip [fb=%d] on crtc %d [%d, pipe=%d] failed - %d\n", - __FUNCTION__, arg.fb_id, i, sna_crtc->id, sna_crtc->pipe, errno)); + __FUNCTION__, arg.fb_id, i, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), errno)); xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR, "Page flipping failed, disabling TearFree\n"); sna->flags &= ~SNA_TEAR_FREE; @@ -8069,7 +8058,7 @@ disable1: &box, 1, COPY_LAST)) { xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, "%s: page flipping failed, disabling CRTC:%d (pipe=%d)\n", - __FUNCTION__, sna_crtc->id, sna_crtc->pipe); + __FUNCTION__, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc)); sna_crtc_disable(crtc, false); } @@ -8090,7 +8079,7 @@ disable1: sna_crtc->cache_bo = kgem_bo_reference(sna_crtc->bo); DBG(("%s: recording flip on CRTC:%d handle=%d, active_scanout=%d, serial=%d\n", - __FUNCTION__, sna_crtc->id, sna_crtc->flip_bo->handle, sna_crtc->flip_bo->active_scanout, sna_crtc->flip_serial)); + __FUNCTION__, __sna_crtc_id(sna_crtc), sna_crtc->flip_bo->handle, sna_crtc->flip_bo->active_scanout, sna_crtc->flip_serial)); } else { sna_crtc_redisplay(crtc, &damage, sna_crtc->bo); kgem_scanout_flush(&sna->kgem, sna_crtc->bo); @@ -8126,19 +8115,19 @@ disable1: assert(crtc != NULL); DBG(("%s: crtc %d [%d, pipe=%d] active? %d, transformed? %d\n", - __FUNCTION__, i, crtc->id, crtc->pipe, crtc->bo ? crtc->bo->handle : 0, crtc->transform)); + __FUNCTION__, i, __sna_crtc_id(crtc), crtc->bo ? crtc->bo->handle : 0, crtc->transform)); if (crtc->bo == NULL || crtc->transform) continue; assert(config->crtc[i]->enabled); assert(crtc->flip_bo == NULL); - arg.crtc_id = crtc->id; + arg.crtc_id = __sna_crtc_id(crtc); arg.user_data = (uintptr_t)crtc; if (crtc->client_bo) { DBG(("%s: apply shadow override bo for CRTC:%d on pipe=%d, handle=%d\n", - __FUNCTION__, crtc->id, crtc->pipe, crtc->client_bo->handle)); + __FUNCTION__, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), crtc->client_bo->handle)); arg.fb_id = get_fb(sna, crtc->client_bo, crtc->base->mode.HDisplay, crtc->base->mode.VDisplay); @@ -8215,7 +8204,7 @@ fixup_flip: xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR, "%s: page flipping failed, disabling CRTC:%d (pipe=%d)\n", - __FUNCTION__, crtc->id, crtc->pipe); + __FUNCTION__, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc)); sna_crtc_disable(crtc->base, false); } continue; @@ -8223,7 +8212,7 @@ fixup_flip: if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_PAGE_FLIP, &arg)) { ERR(("%s: flip [fb=%d] on crtc %d [%d, pipe=%d] failed - %d\n", - __FUNCTION__, arg.fb_id, i, crtc->id, crtc->pipe, errno)); + __FUNCTION__, arg.fb_id, i, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), errno)); goto fixup_flip; } sna->mode.flip_active++; @@ -8237,7 +8226,7 @@ fixup_flip: crtc->flip_pending = true; DBG(("%s: recording flip on CRTC:%d handle=%d, active_scanout=%d, serial=%d\n", - __FUNCTION__, crtc->id, crtc->flip_bo->handle, crtc->flip_bo->active_scanout, crtc->flip_serial)); + __FUNCTION__, __sna_crtc_id(crtc), crtc->flip_bo->handle, crtc->flip_bo->active_scanout, crtc->flip_serial)); { struct drm_i915_gem_busy busy = { flip_bo->handle }; @@ -8320,7 +8309,7 @@ again: if (msc64(crtc, vbl->sequence, &msc)) { DBG(("%s: recording last swap on pipe=%d, frame %d [%08llx], time %d.%06d\n", - __FUNCTION__, crtc->pipe, vbl->sequence, (long long)msc, vbl->tv_sec, vbl->tv_usec)); + __FUNCTION__, __sna_crtc_pipe(crtc), vbl->sequence, (long long)msc, vbl->tv_sec, vbl->tv_usec)); crtc->swap.tv_sec = vbl->tv_sec; crtc->swap.tv_usec = vbl->tv_usec; crtc->swap.msc = msc; diff --git a/src/sna/sna_dri2.c b/src/sna/sna_dri2.c index 43d47015..9ee7e998 100644 --- a/src/sna/sna_dri2.c +++ b/src/sna/sna_dri2.c @@ -1312,8 +1312,8 @@ draw_current_msc(DrawablePtr draw, xf86CrtcPtr crtc, uint64_t msc) const struct ust_msc *this = sna_crtc_last_swap(crtc); DBG(("%s: Window transferring from pipe=%d [msc=%llu] to pipe=%d [msc=%llu], delta now %lld\n", __FUNCTION__, - sna_crtc_to_pipe(priv->crtc), (long long)last->msc, - sna_crtc_to_pipe(crtc), (long long)this->msc, + sna_crtc_pipe(priv->crtc), (long long)last->msc, + sna_crtc_pipe(crtc), (long long)this->msc, (long long)(priv->msc_delta + this->msc - last->msc))); priv->msc_delta += this->msc - last->msc; priv->crtc = crtc; @@ -1491,7 +1491,7 @@ sna_dri2_add_event(struct sna *sna, info->sna = sna; info->draw = draw; info->crtc = crtc; - info->pipe = sna_crtc_to_pipe(crtc); + info->pipe = sna_crtc_pipe(crtc); if (!add_event_to_client(info, sna, client)) { free(info); @@ -1685,7 +1685,7 @@ can_flip(struct sna * sna, } if (!sna_crtc_is_on(crtc)) { - DBG(("%s: ref-pipe=%d is disabled\n", __FUNCTION__, sna_crtc_to_pipe(crtc))); + DBG(("%s: ref-pipe=%d is disabled\n", __FUNCTION__, sna_crtc_pipe(crtc))); return false; } @@ -2137,7 +2137,7 @@ static void fake_swap_complete(struct sna *sna, ClientPtr client, swap = sna_crtc_last_swap(crtc); DBG(("%s(type=%d): draw=%ld, pipe=%d, frame=%lld [msc %lld], tv=%d.%06d\n", - __FUNCTION__, type, (long)draw->id, crtc ? sna_crtc_to_pipe(crtc) : -1, + __FUNCTION__, type, (long)draw->id, crtc ? sna_crtc_pipe(crtc) : -1, (long long)swap->msc, (long long)draw_current_msc(draw, crtc, swap->msc), swap->tv_sec, swap->tv_usec)); @@ -2587,7 +2587,7 @@ get_current_msc(struct sna *sna, DrawablePtr draw, xf86CrtcPtr crtc) VG_CLEAR(vbl); vbl.request.type = _DRM_VBLANK_RELATIVE; vbl.request.sequence = 0; - if (sna_wait_vblank(sna, &vbl, sna_crtc_to_pipe(crtc)) == 0) + if (sna_wait_vblank(sna, &vbl, sna_crtc_pipe(crtc)) == 0) ret = sna_crtc_record_vblank(crtc, &vbl); else ret = sna_crtc_last_swap(crtc)->msc; @@ -2704,7 +2704,7 @@ sna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc, if (immediate) { info = sna->dri2.flip_pending; DBG(("%s: performing immediate swap on pipe %d, pending? %d, mode: %d, continuation? %d\n", - __FUNCTION__, sna_crtc_to_pipe(crtc), + __FUNCTION__, sna_crtc_pipe(crtc), info != NULL, info ? info->flip_continue : 0, info && info->draw == draw)); @@ -2844,7 +2844,7 @@ sna_dri2_schedule_xchg(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc, DBG(("%s: synchronous?=%d, send-event?=%d\n", __FUNCTION__, sync, event)); if (!sync || event) { DBG(("%s: performing immediate xchg on pipe %d\n", - __FUNCTION__, sna_crtc_to_pipe(crtc))); + __FUNCTION__, sna_crtc_pipe(crtc))); sna_dri2_xchg(draw, front, back); } if (sync) { @@ -2906,7 +2906,7 @@ sna_dri2_schedule_xchg_crtc(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc DBG(("%s: synchronous?=%d, send-event?=%d\n", __FUNCTION__, sync, event)); if (!sync || event) { DBG(("%s: performing immediate xchg only on pipe %d\n", - __FUNCTION__, sna_crtc_to_pipe(crtc))); + __FUNCTION__, sna_crtc_pipe(crtc))); sna_dri2_xchg_crtc(sna, draw, crtc, front, back); } if (sync) { @@ -3173,7 +3173,7 @@ sna_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc) const struct ust_msc *swap; DBG(("%s(draw=%ld, pipe=%d)\n", __FUNCTION__, draw->id, - crtc ? sna_crtc_to_pipe(crtc) : -1)); + crtc ? sna_crtc_pipe(crtc) : -1)); if (crtc != NULL) { union drm_wait_vblank vbl; @@ -3181,7 +3181,7 @@ sna_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc) VG_CLEAR(vbl); vbl.request.type = _DRM_VBLANK_RELATIVE; vbl.request.sequence = 0; - if (sna_wait_vblank(sna, &vbl, sna_crtc_to_pipe(crtc)) == 0) + if (sna_wait_vblank(sna, &vbl, sna_crtc_pipe(crtc)) == 0) sna_crtc_record_vblank(crtc, &vbl); } else /* Drawable not displayed, make up a *monotonic* value */ @@ -3215,7 +3215,7 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc crtc = sna_dri2_get_crtc(draw); DBG(("%s(pipe=%d, target_msc=%llu, divisor=%llu, rem=%llu)\n", - __FUNCTION__, crtc ? sna_crtc_to_pipe(crtc) : -1, + __FUNCTION__, crtc ? sna_crtc_pipe(crtc) : -1, (long long)target_msc, (long long)divisor, (long long)remainder)); @@ -3224,7 +3224,7 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc if (crtc == NULL) goto out_complete; - pipe = sna_crtc_to_pipe(crtc); + pipe = sna_crtc_pipe(crtc); VG_CLEAR(vbl); diff --git a/src/sna/sna_present.c b/src/sna/sna_present.c index a344dac8..2b3468da 100644 --- a/src/sna/sna_present.c +++ b/src/sna/sna_present.c @@ -56,9 +56,24 @@ to_present_event(uintptr_t data) #define MARK_PRESENT(x) ((void *)((uintptr_t)(x) | 2)) -static int pipe_from_crtc(RRCrtcPtr crtc) +static inline xf86CrtcPtr unmask_crtc(xf86CrtcPtr crtc) { - return crtc ? sna_crtc_to_pipe__safe(crtc->devPrivate) : -1; + return (xf86CrtcPtr)((uintptr_t)crtc & ~1); +} + +static inline xf86CrtcPtr mark_crtc(xf86CrtcPtr crtc) +{ + return (xf86CrtcPtr)((uintptr_t)crtc | 1); +} + +static inline bool has_vblank(xf86CrtcPtr crtc) +{ + return (uintptr_t)crtc & 1; +} + +static inline int pipe_from_crtc(RRCrtcPtr crtc) +{ + return crtc ? sna_crtc_pipe(crtc->devPrivate) : -1; } static uint32_t pipe_select(int pipe) @@ -98,7 +113,7 @@ static void vblank_complete(struct sna_present_event *info, DBG(("%s: %d events complete\n", __FUNCTION__, info->n_event_id)); for (n = 0; n < info->n_event_id; n++) { DBG(("%s: pipe=%d tv=%d.%06d msc=%lld (target=%lld), event=%lld complete%s\n", __FUNCTION__, - sna_crtc_to_pipe(info->crtc), + sna_crtc_pipe(unmask_crtc(info->crtc)), (int)(ust / 1000000), (int)(ust % 1000000), (long long)msc, (long long)info->target_msc, (long long)info->event_id[n], @@ -142,7 +157,7 @@ static CARD32 sna_fake_vblank_handler(OsTimerPtr timer, CARD32 now, void *data) VG_CLEAR(vbl); vbl.request.type = DRM_VBLANK_RELATIVE; vbl.request.sequence = 0; - if (sna_wait_vblank(info->sna, &vbl, sna_crtc_to_pipe(info->crtc)) == 0) { + if (sna_wait_vblank(info->sna, &vbl, sna_crtc_pipe(info->crtc)) == 0) { ust = ust64(vbl.reply.tval_sec, vbl.reply.tval_usec); msc = sna_crtc_record_vblank(info->crtc, &vbl); DBG(("%s: event=%lld, target msc=%lld, now %lld\n", @@ -155,7 +170,7 @@ static CARD32 sna_fake_vblank_handler(OsTimerPtr timer, CARD32 now, void *data) vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; vbl.request.sequence = info->target_msc; vbl.request.signal = (uintptr_t)MARK_PRESENT(info); - if (sna_wait_vblank(info->sna, &vbl, sna_crtc_to_pipe(info->crtc)) == 0) { + if (sna_wait_vblank(info->sna, &vbl, sna_crtc_pipe(info->crtc)) == 0) { DBG(("%s: scheduled new vblank event for %lld\n", __FUNCTION__, (long long)info->target_msc)); free(timer); return 0; @@ -173,7 +188,7 @@ static CARD32 sna_fake_vblank_handler(OsTimerPtr timer, CARD32 now, void *data) DBG(("%s: blocking wait!\n", __FUNCTION__)); vbl.request.type = DRM_VBLANK_ABSOLUTE; vbl.request.sequence = info->target_msc; - (void)sna_wait_vblank(info->sna, &vbl, sna_crtc_to_pipe(info->crtc)); + (void)sna_wait_vblank(info->sna, &vbl, sna_crtc_pipe(info->crtc)); } } else { const struct ust_msc *swap = sna_crtc_last_swap(info->crtc); @@ -241,24 +256,31 @@ static int sna_present_get_ust_msc(RRCrtcPtr crtc, CARD64 *ust, CARD64 *msc) { struct sna *sna = to_sna_from_screen(crtc->pScreen); - int pipe = pipe_from_crtc(crtc); union drm_wait_vblank vbl; - DBG(("%s(pipe=%d)\n", __FUNCTION__, pipe)); + DBG(("%s(pipe=%d)\n", __FUNCTION__, sna_crtc_pipe(crtc->devPrivate))); + if (sna_crtc_has_vblank(crtc->devPrivate)) { + DBG(("%s: vblank active, reusing last swap msc/ust\n", + __FUNCTION__)); + goto last; + } VG_CLEAR(vbl); vbl.request.type = DRM_VBLANK_RELATIVE; vbl.request.sequence = 0; - if (sna_wait_vblank(sna, &vbl, pipe) == 0) { + if (sna_wait_vblank(sna, &vbl, sna_crtc_pipe(crtc->devPrivate)) == 0) { *ust = ust64(vbl.reply.tval_sec, vbl.reply.tval_usec); *msc = sna_crtc_record_vblank(crtc->devPrivate, &vbl); } else { - const struct ust_msc *swap = sna_crtc_last_swap(crtc->devPrivate); + const struct ust_msc *swap; +last: + swap = sna_crtc_last_swap(crtc->devPrivate); *ust = swap_ust(swap); *msc = swap->msc; } - DBG(("%s: pipe=%d, tv=%d.%06d msc=%lld\n", __FUNCTION__, pipe, + DBG(("%s: pipe=%d, tv=%d.%06d msc=%lld\n", __FUNCTION__, + sna_crtc_pipe(crtc->devPrivate), (int)(*ust / 1000000), (int)(*ust % 1000000), (long long)*msc)); @@ -269,10 +291,13 @@ void sna_present_vblank_handler(struct drm_event_vblank *event) { struct sna_present_event *info = to_present_event(event->user_data); + xf86CrtcPtr crtc = info->crtc; vblank_complete(info, ust64(event->tv_sec, event->tv_usec), - sna_crtc_record_event(info->crtc, event)); + sna_crtc_record_event(unmask_crtc(crtc), event)); + if (has_vblank(crtc)) + sna_crtc_clear_vblank(unmask_crtc(crtc)); } static int @@ -284,14 +309,14 @@ sna_present_queue_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc) union drm_wait_vblank vbl; DBG(("%s(pipe=%d, event=%lld, msc=%lld)\n", - __FUNCTION__, pipe_from_crtc(crtc), + __FUNCTION__, sna_crtc_pipe(crtc->devPrivate), (long long)event_id, (long long)msc)); swap = sna_crtc_last_swap(crtc->devPrivate); assert((int64_t)(msc - swap->msc) >= 0); if ((int64_t)(msc - swap->msc) <= 0) { DBG(("%s: pipe=%d tv=%d.%06d msc=%lld (target=%lld), event=%lld complete\n", __FUNCTION__, - pipe_from_crtc(crtc), + sna_crtc_pipe(crtc->devPrivate), swap->tv_sec, swap->tv_usec, (long long)swap->msc, (long long)msc, (long long)event_id)); @@ -300,13 +325,14 @@ sna_present_queue_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc) } list_for_each_entry(tmp, &sna->present.vblank_queue, link) { - if (tmp->target_msc == msc && tmp->crtc == crtc->devPrivate) { + if (tmp->target_msc == msc && + unmask_crtc(tmp->crtc) == crtc->devPrivate) { uint64_t *events = tmp->event_id; if (is_power_of_two(tmp->n_event_id)) { events = malloc(2*sizeof(uint64_t)*tmp->n_event_id); if (events == NULL) - goto fail; + return BadAlloc; memcpy(events, tmp->event_id, @@ -321,11 +347,13 @@ sna_present_queue_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc) events[tmp->n_event_id++] = event_id; return Success; } - if ((int64_t)(tmp->target_msc - msc) > 0) + if ((int64_t)(tmp->target_msc - msc) > 0) { + DBG(("%s: previous target_msc=%lld invalid for coalescing\n", + __FUNCTION__, (long long)tmp->target_msc)); break; + } } -fail: info = malloc(sizeof(struct sna_present_event) + sizeof(uint64_t)); if (info == NULL) return BadAlloc; @@ -342,13 +370,18 @@ fail: vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; vbl.request.sequence = msc; vbl.request.signal = (uintptr_t)MARK_PRESENT(info); - if (sna_wait_vblank(sna, &vbl, sna_crtc_to_pipe(info->crtc))) { + if (sna_wait_vblank(sna, &vbl, sna_crtc_pipe(info->crtc))) { DBG(("%s: vblank enqueue failed\n", __FUNCTION__)); if (!sna_fake_vblank(info)) { list_del(&info->link); free(info); return BadAlloc; } + } else { + if (msc - swap->msc == 1) { + sna_crtc_set_vblank(info->crtc); + info->crtc = mark_crtc(info->crtc); + } } return Success; @@ -510,12 +543,14 @@ present_flip_handler(struct drm_event_vblank *event, void *data) swap = *sna_crtc_last_swap(info->crtc); DBG(("%s: pipe=%d, tv=%d.%06d msc=%lld (target %lld), event=%lld complete%s\n", __FUNCTION__, - info->crtc ? sna_crtc_to_pipe(info->crtc) : -1, + info->crtc ? sna_crtc_pipe(info->crtc) : -1, swap.tv_sec, swap.tv_usec, (long long)swap.msc, (long long)info->target_msc, (long long)info->event_id[0], info->target_msc && info->target_msc == swap.msc ? "" : ": MISS")); present_event_notify(info->event_id[0], swap_ust(&swap), swap.msc); + if (info->crtc) + sna_crtc_clear_vblank(info->crtc); if (info->sna->present.unflip) { DBG(("%s: executing queued unflip (event=%lld)\n", __FUNCTION__, (long long)info->sna->present.unflip)); @@ -558,6 +593,8 @@ flip(struct sna *sna, return FALSE; } + if (info->crtc) + sna_crtc_set_vblank(info->crtc); return TRUE; } diff --git a/src/sna/sna_video_sprite.c b/src/sna/sna_video_sprite.c index 9ce98798..7c8a73f2 100644 --- a/src/sna/sna_video_sprite.c +++ b/src/sna/sna_video_sprite.c @@ -81,14 +81,11 @@ static int sna_video_sprite_stop(ddStopVideo_ARGS) xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(video->sna->scrn); int i; - for (i = 0; i < config->num_crtc; i++) { + for (i = 0; i < video->sna->mode.num_real_crtc; i++) { xf86CrtcPtr crtc = config->crtc[i]; int pipe; - if (sna_crtc_id(crtc) == 0) - break; - - pipe = sna_crtc_to_pipe(crtc); + pipe = sna_crtc_pipe(crtc); if (video->bo[pipe] == NULL) continue; @@ -221,7 +218,7 @@ sna_video_sprite_show(struct sna *sna, BoxPtr dstBox) { struct local_mode_set_plane s; - int pipe = sna_crtc_to_pipe(crtc); + int pipe = sna_crtc_pipe(crtc); /* XXX handle video spanning multiple CRTC */ @@ -402,7 +399,7 @@ static int sna_video_sprite_put_image(ddPutImage_ARGS) goto err; } - for (i = 0; i < config->num_crtc; i++) { + for (i = 0; i < video->sna->mode.num_real_crtc; i++) { xf86CrtcPtr crtc = config->crtc[i]; struct sna_video_frame frame; int pipe; @@ -411,10 +408,7 @@ static int sna_video_sprite_put_image(ddPutImage_ARGS) RegionRec reg; Rotation rotation; - if (sna_crtc_id(crtc) == 0) - break; - - pipe = sna_crtc_to_pipe(crtc); + pipe = sna_crtc_pipe(crtc); sna_video_frame_init(video, format->id, width, height, &frame); @@ -611,7 +605,7 @@ static bool sna_video_has_sprites(struct sna *sna) for (i = 0; i < sna->mode.num_real_crtc; i++) { if (!sna_crtc_to_sprite(config->crtc[i])) { - DBG(("%s: no sprite found on pipe %d\n", __FUNCTION__, sna_crtc_to_pipe(config->crtc[i]))); + DBG(("%s: no sprite found on pipe %d\n", __FUNCTION__, sna_crtc_pipe(config->crtc[i]))); return false; } } diff --git a/test/present-speed.c b/test/present-speed.c index ba062646..4d339041 100644 --- a/test/present-speed.c +++ b/test/present-speed.c @@ -249,7 +249,6 @@ static void run(Display *dpy, Window win, const char *name, unsigned options) free(ev); } while ((ev = (xcb_present_generic_event_t *)xcb_poll_for_special_event(c, Q))); } - assert(p); b->busy = (options & NOCOPY) == 0; if (b->fence.xid) { From 75037efcd75f6baa3b48dd818b3efca42087f1b9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 20 Apr 2015 14:54:50 +0100 Subject: [PATCH 11/61] test/dri3: Add an explicit DRI3 extension check first Signed-off-by: Chris Wilson --- test/dri3.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/test/dri3.c b/test/dri3.c index 45f3285c..e5644629 100644 --- a/test/dri3.c +++ b/test/dri3.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "dri3.h" @@ -109,12 +110,45 @@ void dri3_fence_free(Display *dpy, struct dri3_fence *fence) xcb_sync_destroy_fence(c, fence->xid); } +static void dri3_query_version(xcb_connection_t *c, int *major, int *minor) +{ + xcb_dri3_query_version_reply_t *reply; + + reply = xcb_dri3_query_version_reply(c, + xcb_dri3_query_version(c, + XCB_DRI3_MAJOR_VERSION, + XCB_DRI3_MINOR_VERSION), + NULL); + if (reply != NULL) { + *major = reply->major_version; + *minor = reply->minor_version; + free(reply); + } +} + +static int dri3_exists(xcb_connection_t *c) +{ + const xcb_query_extension_reply_t *ext; + int major, minor; + + major = minor = -1; + + ext = xcb_get_extension_data(c, &xcb_dri3_id); + if (ext != NULL && ext->present) + dri3_query_version(c, &major, &minor); + + return major >= 0; +} + int dri3_open__full(Display *dpy, Window root, unsigned provider) { xcb_connection_t *c = XGetXCBConnection(dpy); xcb_dri3_open_cookie_t cookie; xcb_dri3_open_reply_t *reply; + if (!dri3_exists(c)) + return -1; + cookie = xcb_dri3_open(c, root, provider); reply = xcb_dri3_open_reply(c, cookie, NULL); From 54770d46f10205b4a6d0bc7882d18ae00af47134 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 21 Apr 2015 10:16:27 +0100 Subject: [PATCH 12/61] tools/dri3info: Include compilation instructions for standalone building Let the read know how to compile dri3info without having to compile the whole of xf86-video-intel Signed-off-by: Chris Wilson --- tools/dri3info.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/dri3info.c b/tools/dri3info.c index 2c2ef95f..0c33fc5a 100644 --- a/tools/dri3info.c +++ b/tools/dri3info.c @@ -20,6 +20,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * + * To compile standalone: gcc -o dri3info dri3info.c `pkg-config --cflags --libs xcb-dri3 x11-xcb xrandr xxf86vm libdrm` */ #include From 37cf561fd2f26a51ef60078e2e31ed02e5380c41 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 21 Apr 2015 14:33:24 +0100 Subject: [PATCH 13/61] sna: Allow flips to continue after successfully fixing up the CRTC If we receive an error from the pageflip ioctl, we attempt to set the framebuffer using SETCRTC instead. This is so that we can transition between pitches and offsets for a CRTC. However, the kernel may reject a flip also for tiling changes, or for any reason, which we also want to transparently handle. Rearrange the error message and flip->blit fallback handling to only do so if we try to flip twice (i.e. after resetting the CRTC) and we still fail. Signed-off-by: Chris Wilson --- src/sna/sna_display.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c index 0183246d..3ba2df98 100644 --- a/src/sna/sna_display.c +++ b/src/sna/sna_display.c @@ -5928,6 +5928,7 @@ sna_page_flip(struct sna *sna, struct sna_crtc *crtc = config->crtc[i]->driver_private; struct drm_mode_crtc_page_flip arg; uint32_t crtc_offset; + int fixup; DBG(("%s: crtc %d id=%d, pipe=%d active? %d\n", __FUNCTION__, i, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), crtc->bo != NULL)); @@ -5949,6 +5950,7 @@ sna_page_flip(struct sna *sna, return 0; } + fixup = 0; crtc_offset = crtc->base->y << 16 | crtc->base->x; if (bo->pitch != crtc->bo->pitch || crtc_offset != crtc->offset) { @@ -5957,6 +5959,7 @@ sna_page_flip(struct sna *sna, bo->pitch, crtc->bo->pitch, crtc_offset, crtc->offset)); fixup_flip: + fixup = 1; if (crtc->bo != bo && sna_crtc_flip(sna, crtc, bo, crtc->base->x, crtc->base->y)) { update_scanout: DBG(("%s: removing handle=%d [active_scanout=%d] from scanout, installing handle=%d [active_scanout=%d]\n", @@ -5979,11 +5982,8 @@ update_scanout: goto next_crtc; /* queue a flip in order to send the event */ - } else { - if (count) - sna_mode_restore(sna); - return 0; - } + } else + goto error; } /* Only the reference crtc will finally deliver its page flip @@ -6029,16 +6029,18 @@ retry_flip: goto retry_flip; } - if (sna->flags & (data ? SNA_HAS_FLIP : SNA_HAS_ASYNC_FLIP)) { - xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR, - "page flipping failed, on CRTC:%d (pipe=%d), disabling %s page flips\n", - __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), data ? "synchronous": "asynchronous"); - sna->flags &= ~(data ? SNA_HAS_FLIP : SNA_HAS_ASYNC_FLIP); + if (!fixup) goto fixup_flip; - } + +error: + xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR, + "page flipping failed, on CRTC:%d (pipe=%d), disabling %s page flips\n", + __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), data ? "synchronous": "asynchronous"); if (count) sna_mode_restore(sna); + + sna->flags &= ~(data ? SNA_HAS_FLIP : SNA_HAS_ASYNC_FLIP); return 0; } From 65cc48757e00c81834d39fe90638255723eeb3c6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 21 Apr 2015 15:06:18 +0100 Subject: [PATCH 14/61] test/present: Do a double flip to test tiling changes Since the first flip may require a fixup, we will only really know with the second flip whether we can start a flip chain with different tiling. Signed-off-by: Chris Wilson --- test/present-test.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/test/present-test.c b/test/present-test.c index 3630241a..b33fd2e0 100644 --- a/test/present-test.c +++ b/test/present-test.c @@ -1564,6 +1564,7 @@ static int test_dri3_tiling(Display *dpy) unsigned int width, height; unsigned border, depth, bpp; unsigned stride, size; + void *Q; int x, y; int device; int line = -1; @@ -1594,8 +1595,10 @@ static int test_dri3_tiling(Display *dpy) width, height, stride, size); _x_error_occurred = 0; + Q = setup_msc(dpy, root); for (t = 0; t < sizeof(tiling)/sizeof(tiling[0]); t++) { + uint64_t msc; uint32_t src; int src_fd; Pixmap src_pix; @@ -1618,6 +1621,8 @@ static int test_dri3_tiling(Display *dpy) width, height, depth, src_fd, bpp, stride, size); + msc = wait_vblank(dpy, root, Q); + xcb_present_pixmap(XGetXCBConnection(dpy), win, src_pix, 0, /* sbc */ @@ -1629,10 +1634,27 @@ static int test_dri3_tiling(Display *dpy) None, /* wait fence */ None, XCB_PRESENT_OPTION_NONE, - 0, /* target msc */ - 0, /* divisor */ + msc + 2, /* target msc */ + 1, /* divisor */ 0, /* remainder */ 0, NULL); + + xcb_present_pixmap(XGetXCBConnection(dpy), + win, src_pix, + 0, /* sbc */ + 0, /* valid */ + 0, /* update */ + 0, /* x_off */ + 0, /* y_off */ + None, + None, /* wait fence */ + None, + XCB_PRESENT_OPTION_NONE, + msc + 3, /* target msc */ + 1, /* divisor */ + 0, /* remainder */ + 0, NULL); + XSync(dpy, True); if (_x_error_occurred) { line = __LINE__; @@ -1645,10 +1667,12 @@ static int test_dri3_tiling(Display *dpy) gem_close(device, src); } + teardown_msc(dpy, Q); return 0; fail: printf("%s failed with tiling %d, line %d\n", __func__, tiling[t], line); + teardown_msc(dpy, Q); return 1; } From 33374755c5462849cb0bb1d549328cd9b00ba1d5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 21 Apr 2015 15:02:13 +0100 Subject: [PATCH 15/61] sna: Add a define to change scanout tilings by default Just for testing, you hear? Signed-off-by: Chris Wilson --- src/sna/sna_accel.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c index ce096650..8e63b14e 100644 --- a/src/sna/sna_accel.c +++ b/src/sna/sna_accel.c @@ -67,7 +67,8 @@ #define FORCE_FLUSH 0 #define FORCE_FULL_SYNC 0 /* https://bugs.freedesktop.org/show_bug.cgi?id=61628 */ -#define DEFAULT_TILING I915_TILING_X +#define DEFAULT_PIXMAP_TILING I915_TILING_X +#define DEFAULT_SCANOUT_TILING I915_TILING_X #define USE_INPLACE 1 #define USE_SPANS 0 /* -1 force CPU, 1 force GPU */ @@ -613,9 +614,9 @@ static bool sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv, bool a static inline uint32_t default_tiling(struct sna *sna, PixmapPtr pixmap) { -#if DEFAULT_TILING == I915_TILING_NONE +#if DEFAULT_PIXMAP_TILING == I915_TILING_NONE return I915_TILING_NONE; -#elif DEFAULT_TILING == I915_TILING_X +#elif DEFAULT_PIXMAP_TILING == I915_TILING_X return I915_TILING_X; #else /* Try to avoid hitting the Y-tiling GTT mapping bug on 855GM */ @@ -1648,7 +1649,7 @@ static bool sna_pixmap_alloc_gpu(struct sna *sna, if (pixmap->usage_hint == SNA_CREATE_FB && (sna->flags & SNA_LINEAR_FB) == 0) { flags |= CREATE_SCANOUT; tiling = kgem_choose_tiling(&sna->kgem, - -I915_TILING_X, + -DEFAULT_SCANOUT_TILING, pixmap->drawable.width, pixmap->drawable.height, pixmap->drawable.bitsPerPixel); From d8401806b4c2dc41c6054c646080c8f79189b980 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 21 Apr 2015 15:17:38 +0100 Subject: [PATCH 16/61] sna/dri2: Don't convert from Y-to-X when exporting pixmaps If the pixmap's GPU bo is already allocated with Y, expect Mesa to deal with it rather than convert to X. Signed-off-by: Chris Wilson --- src/sna/sna_dri2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sna/sna_dri2.c b/src/sna/sna_dri2.c index 9ee7e998..dbdde32e 100644 --- a/src/sna/sna_dri2.c +++ b/src/sna/sna_dri2.c @@ -454,7 +454,7 @@ static struct kgem_bo *sna_pixmap_set_dri(struct sna *sna, tiling = color_tiling(sna, &pixmap->drawable); if (tiling < 0) tiling = -tiling; - if (priv->gpu_bo->tiling != tiling && !priv->gpu_bo->scanout) + if (priv->gpu_bo->tiling < tiling && !priv->gpu_bo->scanout) sna_pixmap_change_tiling(pixmap, tiling); return priv->gpu_bo; From 83b8528773a0b1e6655fa87c9645a0062cee1359 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 21 Apr 2015 15:28:54 +0100 Subject: [PATCH 17/61] sna: Fix ancient typo in DEFAULT_TILING == Y We could just fix the typo, but that whole if block is redundant. Signed-off-by: Chris Wilson --- src/sna/sna_accel.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c index 8e63b14e..4db011f3 100644 --- a/src/sna/sna_accel.c +++ b/src/sna/sna_accel.c @@ -632,15 +632,6 @@ static inline uint32_t default_tiling(struct sna *sna, PixmapPtr pixmap) pixmap->drawable.height > sna->render.max_3d_size)) return I915_TILING_X; - if (sna_damage_is_all(&sna_pixmap(pixmap)->cpu_damage, - pixmap->drawable.width, - pixmap->drawable.height)) { - DBG(("%s: entire source is damaged, using Y-tiling\n", - __FUNCTION__)); - sna_damage_destroy(&sna_pixmap(priv)->gpu_damage); - return I915_TILING_Y; - } - return I915_TILING_Y; #endif } From 4fdd3a714d380afd3d6425aedbbf2ae20180638b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 22 Apr 2015 14:08:17 +0100 Subject: [PATCH 18/61] sna/gen6+: Discourage use of the BLT with Y-tiling Somewhere, somehow the first glyph character upload into the Y-tiled glyph cache is corrupt since commit 75d87762471e195dddd73056fc6a06e17db1c8b0 Author: Chris Wilson Date: Fri Apr 17 10:29:28 2015 +0100 sna: Enable blitting with Y-tiled surfaces I have not spotted whether it is a missing magic bit or a bad GTT path, but ideally we don't want to switch to BLT along that path anyway (since we are in the middle of rendering with the other engine). Reported-by: Andy Furniss References: https://bugs.freedesktop.org/show_bug.cgi?id=90138 Signed-off-by: Chris Wilson --- src/sna/gen6_common.h | 3 ++ src/sna/gen6_render.c | 65 +++++++++++++++++++++++++++++-------------- src/sna/gen7_render.c | 65 +++++++++++++++++++++++++++++-------------- src/sna/gen8_render.c | 65 +++++++++++++++++++++++++++++-------------- src/sna/sna_blt.c | 8 ++++-- src/sna/sna_render.h | 5 ++-- 6 files changed, 144 insertions(+), 67 deletions(-) diff --git a/src/sna/gen6_common.h b/src/sna/gen6_common.h index 5da739e2..4bf69b11 100644 --- a/src/sna/gen6_common.h +++ b/src/sna/gen6_common.h @@ -52,6 +52,9 @@ inline static bool can_switch_to_blt(struct sna *sna, if (bo && RQ_IS_BLT(bo->rq)) return true; + if (bo && bo->tiling == I915_TILING_Y) + return false; + if (sna->render_state.gt < 2) return true; diff --git a/src/sna/gen6_render.c b/src/sna/gen6_render.c index 7878e7bc..312d6afd 100644 --- a/src/sna/gen6_render.c +++ b/src/sna/gen6_render.c @@ -1965,54 +1965,77 @@ gen6_composite_set_target(struct sna *sna, static bool try_blt(struct sna *sna, - PicturePtr dst, PicturePtr src, - int width, int height) + uint8_t op, + PicturePtr src, + PicturePtr mask, + PicturePtr dst, + int16_t src_x, int16_t src_y, + int16_t msk_x, int16_t msk_y, + int16_t dst_x, int16_t dst_y, + int16_t width, int16_t height, + unsigned flags, + struct sna_composite_op *tmp) { struct kgem_bo *bo; if (sna->kgem.mode == KGEM_BLT) { DBG(("%s: already performing BLT\n", __FUNCTION__)); - return true; + goto execute; } if (too_large(width, height)) { DBG(("%s: operation too large for 3D pipe (%d, %d)\n", __FUNCTION__, width, height)); - return true; + goto execute; } bo = __sna_drawable_peek_bo(dst->pDrawable); if (bo == NULL) - return true; + goto execute; if (untiled_tlb_miss(bo)) - return true; + goto execute; - if (bo->rq) - return RQ_IS_BLT(bo->rq); + if (bo->rq) { + if (RQ_IS_BLT(bo->rq)) + goto execute; + + return false; + } + + if (bo->tiling == I915_TILING_Y) + goto upload; if (src->pDrawable == dst->pDrawable && can_switch_to_blt(sna, bo, 0)) - return true; + goto execute; if (sna_picture_is_solid(src, NULL) && can_switch_to_blt(sna, bo, 0)) - return true; + goto execute; if (src->pDrawable) { struct kgem_bo *s = __sna_drawable_peek_bo(src->pDrawable); if (s == NULL) - return true; + goto execute; if (prefer_blt_bo(sna, s, bo)) - return true; + goto execute; } if (sna->kgem.ring == KGEM_BLT) { DBG(("%s: already performing BLT\n", __FUNCTION__)); - return true; + goto execute; } - return false; +upload: + flags |= COMPOSITE_UPLOAD; +execute: + return sna_blt_composite(sna, op, + src, dst, + src_x, src_y, + dst_x, dst_y, + width, height, + flags, tmp); } static bool @@ -2242,13 +2265,13 @@ gen6_render_composite(struct sna *sna, width, height, sna->kgem.ring)); if (mask == NULL && - try_blt(sna, dst, src, width, height) && - sna_blt_composite(sna, op, - src, dst, - src_x, src_y, - dst_x, dst_y, - width, height, - flags, tmp)) + try_blt(sna, op, + src, mask, dst, + src_x, src_y, + msk_x, msk_y, + dst_x, dst_y, + width, height, + flags, tmp)) return true; if (gen6_composite_fallback(sna, src, mask, dst)) diff --git a/src/sna/gen7_render.c b/src/sna/gen7_render.c index 39f0d385..d1de7522 100644 --- a/src/sna/gen7_render.c +++ b/src/sna/gen7_render.c @@ -2184,55 +2184,78 @@ gen7_composite_set_target(struct sna *sna, static bool try_blt(struct sna *sna, - PicturePtr dst, PicturePtr src, - int width, int height) + uint8_t op, + PicturePtr src, + PicturePtr mask, + PicturePtr dst, + int16_t src_x, int16_t src_y, + int16_t msk_x, int16_t msk_y, + int16_t dst_x, int16_t dst_y, + int16_t width, int16_t height, + unsigned flags, + struct sna_composite_op *tmp) { struct kgem_bo *bo; if (sna->kgem.mode == KGEM_BLT) { DBG(("%s: already performing BLT\n", __FUNCTION__)); - return true; + goto execute; } if (too_large(width, height)) { DBG(("%s: operation too large for 3D pipe (%d, %d)\n", __FUNCTION__, width, height)); - return true; + goto execute; } bo = __sna_drawable_peek_bo(dst->pDrawable); if (bo == NULL) - return true; + goto execute; if (untiled_tlb_miss(bo)) - return true; + goto execute; - if (bo->rq) - return RQ_IS_BLT(bo->rq); + if (bo->rq) { + if (RQ_IS_BLT(bo->rq)) + goto execute; + + return false; + } + + if (bo->tiling == I915_TILING_Y) + goto upload; if (src->pDrawable == dst->pDrawable && (sna->render_state.gt < 3 || width*height < 1024) && can_switch_to_blt(sna, bo, 0)) - return true; + goto execute; if (sna_picture_is_solid(src, NULL) && can_switch_to_blt(sna, bo, 0)) - return true; + goto execute; if (src->pDrawable) { struct kgem_bo *s = __sna_drawable_peek_bo(src->pDrawable); if (s == NULL) - return true; + goto upload; if (prefer_blt_bo(sna, s, bo)) - return true; + goto execute; } if (sna->kgem.ring == KGEM_BLT) { DBG(("%s: already performing BLT\n", __FUNCTION__)); - return true; + goto execute; } - return false; +upload: + flags |= COMPOSITE_UPLOAD; +execute: + return sna_blt_composite(sna, op, + src, dst, + src_x, src_y, + dst_x, dst_y, + width, height, + flags, tmp); } static bool @@ -2462,13 +2485,13 @@ gen7_render_composite(struct sna *sna, width, height, sna->kgem.mode, sna->kgem.ring)); if (mask == NULL && - try_blt(sna, dst, src, width, height) && - sna_blt_composite(sna, op, - src, dst, - src_x, src_y, - dst_x, dst_y, - width, height, - flags, tmp)) + try_blt(sna, op, + src, mask, dst, + src_x, src_y, + msk_x, msk_y, + dst_x, dst_y, + width, height, + flags, tmp)) return true; if (gen7_composite_fallback(sna, src, mask, dst)) diff --git a/src/sna/gen8_render.c b/src/sna/gen8_render.c index c0fe9f9c..b40c582a 100644 --- a/src/sna/gen8_render.c +++ b/src/sna/gen8_render.c @@ -2029,55 +2029,78 @@ gen8_composite_set_target(struct sna *sna, static bool try_blt(struct sna *sna, - PicturePtr dst, PicturePtr src, - int width, int height) + uint8_t op, + PicturePtr src, + PicturePtr mask, + PicturePtr dst, + int16_t src_x, int16_t src_y, + int16_t msk_x, int16_t msk_y, + int16_t dst_x, int16_t dst_y, + int16_t width, int16_t height, + unsigned flags, + struct sna_composite_op *tmp) { struct kgem_bo *bo; if (sna->kgem.mode == KGEM_BLT) { DBG(("%s: already performing BLT\n", __FUNCTION__)); - return true; + goto execute; } if (too_large(width, height)) { DBG(("%s: operation too large for 3D pipe (%d, %d)\n", __FUNCTION__, width, height)); - return true; + goto execute; } bo = __sna_drawable_peek_bo(dst->pDrawable); if (bo == NULL) - return true; + goto execute; if (untiled_tlb_miss(bo)) - return true; + goto execute; - if (bo->rq) - return RQ_IS_BLT(bo->rq); + if (bo->rq) { + if (RQ_IS_BLT(bo->rq)) + goto execute; + + return false; + } + + if (bo->tiling == I915_TILING_Y) + goto upload; if (sna_picture_is_solid(src, NULL) && can_switch_to_blt(sna, bo, 0)) - return true; + goto execute; if (src->pDrawable == dst->pDrawable && (sna->render_state.gt < 3 || width*height < 1024) && can_switch_to_blt(sna, bo, 0)) - return true; + goto execute; if (src->pDrawable) { struct kgem_bo *s = __sna_drawable_peek_bo(src->pDrawable); if (s == NULL) - return true; + goto upload; if (prefer_blt_bo(sna, s, bo)) - return true; + goto execute; } if (sna->kgem.ring == KGEM_BLT) { DBG(("%s: already performing BLT\n", __FUNCTION__)); - return true; + goto execute; } - return false; +upload: + flags |= COMPOSITE_UPLOAD; +execute: + return sna_blt_composite(sna, op, + src, dst, + src_x, src_y, + dst_x, dst_y, + width, height, + flags, tmp); } static bool @@ -2307,13 +2330,13 @@ gen8_render_composite(struct sna *sna, width, height, sna->kgem.mode, sna->kgem.ring)); if (mask == NULL && - try_blt(sna, dst, src, width, height) && - sna_blt_composite(sna, op, - src, dst, - src_x, src_y, - dst_x, dst_y, - width, height, - flags, tmp)) + try_blt(sna, op, + src, mask, dst, + src_x, src_y, + msk_x, msk_y, + dst_x, dst_y, + width, height, + flags, tmp)) return true; if (gen8_composite_fallback(sna, src, mask, dst)) diff --git a/src/sna/sna_blt.c b/src/sna/sna_blt.c index 9bb32674..1b82abcb 100644 --- a/src/sna/sna_blt.c +++ b/src/sna/sna_blt.c @@ -2606,6 +2606,8 @@ clear: } if (hint & REPLACES) kgem_bo_undo(&sna->kgem, tmp->dst.bo); + if (flags & COMPOSITE_UPLOAD) + return false; } else { RegionRec region; @@ -2692,6 +2694,8 @@ fill: } if (hint & REPLACES) kgem_bo_undo(&sna->kgem, tmp->dst.bo); + if (flags & COMPOSITE_UPLOAD) + return false; } else { RegionRec region; @@ -2830,7 +2834,7 @@ fill: if (src_pixmap->drawable.width <= sna->render.max_3d_size && src_pixmap->drawable.height <= sna->render.max_3d_size && bo->pitch <= sna->render.max_3d_pitch && - (flags & COMPOSITE_FALLBACK) == 0) + (flags & (COMPOSITE_UPLOAD | COMPOSITE_FALLBACK)) == 0) { return false; } @@ -2881,7 +2885,7 @@ fallback: DBG(("%s: fallback -- unaccelerated upload\n", __FUNCTION__)); goto fallback; - } else { + } else if ((flags & COMPOSITE_UPLOAD) == 0) { ret = prepare_blt_copy(sna, tmp, bo, alpha_fixup); if (!ret) goto fallback; diff --git a/src/sna/sna_render.h b/src/sna/sna_render.h index 723de80b..1baf9455 100644 --- a/src/sna/sna_render.h +++ b/src/sna/sna_render.h @@ -238,8 +238,9 @@ struct sna_render { int16_t w, int16_t h, unsigned flags, struct sna_composite_op *tmp); -#define COMPOSITE_PARTIAL 0x1 -#define COMPOSITE_FALLBACK 0x80000000 +#define COMPOSITE_PARTIAL 0x1 +#define COMPOSITE_UPLOAD 0x40000000 +#define COMPOSITE_FALLBACK 0x80000000 bool (*check_composite_spans)(struct sna *sna, uint8_t op, PicturePtr dst, PicturePtr src, From 45475fb7c9d84579c836b5893571c5185d568198 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 22 Apr 2015 19:17:19 +0100 Subject: [PATCH 19/61] sna: Update blt fallback to handle Y-tiled surfaces Signed-off-by: Chris Wilson --- src/sna/sna_blt.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sna/sna_blt.c b/src/sna/sna_blt.c index 1b82abcb..843466dc 100644 --- a/src/sna/sna_blt.c +++ b/src/sna/sna_blt.c @@ -4190,6 +4190,7 @@ bool sna_blt_copy_boxes_fallback(struct sna *sna, uint8_t alu, DBG(("%s: dst == src\n", __FUNCTION__)); if (src_bo->tiling == I915_TILING_Y && + !sna->kgem.can_blt_y && kgem_bo_blt_pitch_is_ok(&sna->kgem, src_bo)) { struct kgem_bo *bo; @@ -4237,6 +4238,7 @@ bool sna_blt_copy_boxes_fallback(struct sna *sna, uint8_t alu, } } else { if (src_bo->tiling == I915_TILING_Y && + !sna->kgem.can_blt_y && kgem_bo_blt_pitch_is_ok(&sna->kgem, src_bo)) { DBG(("%s: src is y-tiled\n", __FUNCTION__)); if (src->type != DRAWABLE_PIXMAP) @@ -4251,6 +4253,7 @@ bool sna_blt_copy_boxes_fallback(struct sna *sna, uint8_t alu, } if (dst_bo->tiling == I915_TILING_Y && + !sna->kgem.can_blt_y && kgem_bo_blt_pitch_is_ok(&sna->kgem, dst_bo)) { DBG(("%s: dst is y-tiled\n", __FUNCTION__)); if (dst->type != DRAWABLE_PIXMAP) From 52bc0b119cab977b82cbbd96f689b7376b83d6f2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 22 Apr 2015 19:45:16 +0100 Subject: [PATCH 20/61] sna/gen6: Do not force a blt switch onto a Y-tiled surface Signed-off-by: Chris Wilson --- src/sna/gen6_common.h | 11 +++++++---- src/sna/gen6_render.c | 2 +- src/sna/gen7_render.c | 2 +- src/sna/gen8_render.c | 2 +- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/sna/gen6_common.h b/src/sna/gen6_common.h index 4bf69b11..898cda80 100644 --- a/src/sna/gen6_common.h +++ b/src/sna/gen6_common.h @@ -110,7 +110,7 @@ static int prefer_blt_bo(struct sna *sna, return dst->tiling == I915_TILING_NONE || is_uncached(sna, dst); } -inline static bool force_blt_ring(struct sna *sna) +inline static bool force_blt_ring(struct sna *sna, struct kgem_bo *bo) { if (sna->kgem.mode == KGEM_RENDER) return false; @@ -118,6 +118,9 @@ inline static bool force_blt_ring(struct sna *sna) if (NO_RING_SWITCH(sna)) return sna->kgem.ring == KGEM_BLT; + if (bo->tiling == I915_TILING_Y) + return false; + if (sna->flags & SNA_POWERSAVE) return true; @@ -133,7 +136,7 @@ prefer_blt_ring(struct sna *sna, struct kgem_bo *bo, unsigned flags) if (PREFER_RENDER) return PREFER_RENDER < 0; - assert(!force_blt_ring(sna)); + assert(!force_blt_ring(sna, bo)); assert(!kgem_bo_is_render(bo) || NO_RING_SWITCH(sna)); if (kgem_bo_is_blt(bo)) @@ -173,7 +176,7 @@ prefer_blt_composite(struct sna *sna, struct sna_composite_op *tmp) untiled_tlb_miss(tmp->src.bo)) return true; - if (force_blt_ring(sna)) + if (force_blt_ring(sna, tmp->dst.bo)) return true; if (prefer_render_ring(sna, tmp->dst.bo)) @@ -194,7 +197,7 @@ prefer_blt_fill(struct sna *sna, struct kgem_bo *bo, unsigned flags) if (untiled_tlb_miss(bo)) return true; - if (force_blt_ring(sna)) + if (force_blt_ring(sna, bo)) return true; if ((flags & (FILL_POINTS | FILL_SPANS)) == 0) { diff --git a/src/sna/gen6_render.c b/src/sna/gen6_render.c index 312d6afd..ca1f9c58 100644 --- a/src/sna/gen6_render.c +++ b/src/sna/gen6_render.c @@ -2718,7 +2718,7 @@ static inline bool prefer_blt_copy(struct sna *sna, untiled_tlb_miss(dst_bo)) return true; - if (force_blt_ring(sna)) + if (force_blt_ring(sna, dst_bo)) return true; if (kgem_bo_is_render(dst_bo) || diff --git a/src/sna/gen7_render.c b/src/sna/gen7_render.c index d1de7522..6c0e7f4f 100644 --- a/src/sna/gen7_render.c +++ b/src/sna/gen7_render.c @@ -2916,7 +2916,7 @@ prefer_blt_copy(struct sna *sna, if (flags & COPY_DRI && !sna->kgem.has_semaphores) return false; - if (force_blt_ring(sna)) + if (force_blt_ring(sna, dst_bo)) return true; if ((flags & COPY_SMALL || diff --git a/src/sna/gen8_render.c b/src/sna/gen8_render.c index b40c582a..660fc5a2 100644 --- a/src/sna/gen8_render.c +++ b/src/sna/gen8_render.c @@ -2766,7 +2766,7 @@ prefer_blt_copy(struct sna *sna, if (flags & COPY_DRI && !sna->kgem.has_semaphores) return false; - if (force_blt_ring(sna)) + if (force_blt_ring(sna, dst_bo)) return true; if ((flags & COPY_SMALL || From 64e45993cf9d13b5900dc6b8afacffdfea14fa7f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 22 Apr 2015 20:15:38 +0100 Subject: [PATCH 21/61] sna: Fix interpretation of SWCTRL Bspec says it is an override for the source format, irrespective of the tiling bit supplied in the command packet. So we need to apply the FLUSH+LRI more often. Signed-off-by: Chris Wilson --- src/sna/kgem.c | 44 +++++++++++++++++--------------------------- 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/src/sna/kgem.c b/src/sna/kgem.c index 76e69135..d1902552 100644 --- a/src/sna/kgem.c +++ b/src/sna/kgem.c @@ -2209,7 +2209,9 @@ static void kgem_clear_swctrl(struct kgem *kgem) *b++ = MI_LOAD_REGISTER_IMM; *b++ = BCS_SWCTRL; - *b++ = kgem->bcs_state << 16; + *b++ = (BCS_SRC_Y | BCS_DST_Y) << 16; + + kgem->bcs_state = 0; } static uint32_t kgem_end_batch(struct kgem *kgem) @@ -3557,7 +3559,6 @@ void kgem_reset(struct kgem *kgem) kgem->needs_reservation = false; kgem->flush = 0; kgem->batch_flags = kgem->batch_flags_base; - kgem->bcs_state = 0; assert(kgem->batch); kgem->next_request = __kgem_request_alloc(kgem); @@ -6196,60 +6197,49 @@ void __kgem_bcs_set_tiling(struct kgem *kgem, struct kgem_bo *src, struct kgem_bo *dst) { - uint32_t state, mask, *b; + uint32_t state, *b; DBG(("%s: src handle=%d:tiling=%d, dst handle=%d:tiling=%d\n", __FUNCTION__, src ? src->handle : 0, src ? src->tiling : 0, dst ? dst->handle : 0, dst ? dst->tiling : 0)); assert(kgem->mode == KGEM_BLT); + assert(dst == NULL || kgem_bo_can_blt(kgem, dst)); + assert(src == NULL || kgem_bo_can_blt(kgem, src)); - mask = state = 0; - if (dst && dst->tiling) { - assert(kgem_bo_can_blt(kgem, dst)); - mask |= BCS_DST_Y; - if (dst->tiling == I915_TILING_Y) - state |= BCS_DST_Y; - } + state = 0; + if (dst && dst->tiling == I915_TILING_Y) + state |= BCS_DST_Y; + if (src && src->tiling == I915_TILING_Y) + state |= BCS_SRC_Y; - if (src && src->tiling) { - assert(kgem_bo_can_blt(kgem, src)); - mask |= BCS_SRC_Y; - if (src->tiling == I915_TILING_Y) - state |= BCS_SRC_Y; - } - - if ((kgem->bcs_state & mask) == state) + if (kgem->bcs_state == state) return; DBG(("%s: updating SWCTRL %x -> %x\n", __FUNCTION__, - kgem->bcs_state, (kgem->bcs_state & ~mask) | state)); + kgem->bcs_state, state)); /* Over-estimate space in case we need to re-emit the cmd packet */ if (!kgem_check_batch(kgem, 24)) { _kgem_submit(kgem); _kgem_set_mode(kgem, KGEM_BLT); + if (state == 0) + return; } b = kgem->batch + kgem->nbatch; if (kgem->nbatch) { - DBG(("%s: emitting flush before SWCTRL LRI\n", - __FUNCTION__)); *b++ = MI_FLUSH_DW; *b++ = 0; *b++ = 0; *b++ = 0; } - - DBG(("%s: emitting SWCTRL LRI to %x\n", - __FUNCTION__, mask << 16 | state)); *b++ = MI_LOAD_REGISTER_IMM; *b++ = BCS_SWCTRL; - *b++ = mask << 16 | state; + *b++ = (BCS_SRC_Y | BCS_DST_Y) << 16 | state; kgem->nbatch = b - kgem->batch; - kgem->bcs_state &= ~mask; - kgem->bcs_state |= state; + kgem->bcs_state = state; } uint32_t kgem_add_reloc(struct kgem *kgem, From 09d8e5e1b3215c0e58c2ce44048458152c523270 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 23 Apr 2015 08:35:52 +0100 Subject: [PATCH 22/61] sna/gen6+: Fix BLT src/dst tiling checks In a couple of the copy paths, src/dst parameters were reversed, inverting the direction of the tiling flags. Reported-by: Andy Furniss Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=90138 Signed-off-by: Chris Wilson --- src/sna/sna_blt.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/sna/sna_blt.c b/src/sna/sna_blt.c index 843466dc..3d8c040f 100644 --- a/src/sna/sna_blt.c +++ b/src/sna/sna_blt.c @@ -297,6 +297,7 @@ inline static void sna_blt_fill_begin(struct sna *sna, if (kgem->nreloc) { _kgem_submit(kgem); _kgem_set_mode(kgem, KGEM_BLT); + kgem_bcs_set_tiling(kgem, NULL, blt->bo[0]); assert(kgem->nbatch == 0); } @@ -466,8 +467,8 @@ static void sna_blt_alpha_fixup_one(struct sna *sna, !kgem_check_reloc(kgem, 2)) { _kgem_submit(kgem); _kgem_set_mode(kgem, KGEM_BLT); + kgem_bcs_set_tiling(&sna->kgem, blt->bo[0], blt->bo[1]); } - kgem_bcs_set_tiling(&sna->kgem, blt->bo[1], blt->bo[0]); assert(sna->kgem.mode == KGEM_BLT); b = kgem->batch + kgem->nbatch; @@ -595,8 +596,8 @@ static void sna_blt_copy_one(struct sna *sna, !kgem_check_reloc(kgem, 2)) { _kgem_submit(kgem); _kgem_set_mode(kgem, KGEM_BLT); + kgem_bcs_set_tiling(&sna->kgem, blt->bo[0], blt->bo[1]); } - kgem_bcs_set_tiling(&sna->kgem, blt->bo[1], blt->bo[0]); assert(sna->kgem.mode == KGEM_BLT); b = kgem->batch + kgem->nbatch; @@ -1437,8 +1438,8 @@ begin_blt(struct sna *sna, return false; _kgem_set_mode(&sna->kgem, KGEM_BLT); + kgem_bcs_set_tiling(&sna->kgem, NULL, op->dst.bo); } - kgem_bcs_set_tiling(&sna->kgem, NULL, op->dst.bo); return true; } @@ -4094,8 +4095,8 @@ bool sna_blt_copy_boxes__with_alpha(struct sna *sna, uint8_t alu, !kgem_check_reloc(kgem, 2)) { _kgem_submit(kgem); _kgem_set_mode(kgem, KGEM_BLT); + kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo); } - kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo); assert(sna->kgem.mode == KGEM_BLT); b = kgem->batch + kgem->nbatch; From 9b9643171359194478ab9f7126012b659d2ae7a1 Mon Sep 17 00:00:00 2001 From: Olivier Fourdan Date: Fri, 24 Apr 2015 09:43:37 +0200 Subject: [PATCH 23/61] sna: Fix build with gcc 5.0 gcc generates an error at build time because it fails to inline some functions: blt.c: In function 'affine_blt': blt.c:980:1: error: inlining failed in call to always_inline 'bilinear_weight': optimization level attribute mismatch bilinear_weight(pixman_fixed_t x) blt.c:1164:7: error: called from here fy = bilinear_weight(y1); ^ blt.c:980:1: error: inlining failed in call to always_inline 'bilinear_weight': optimization level attribute mismatch bilinear_weight(pixman_fixed_t x) blt.c:1163:7: error: called from here fx = bilinear_weight(x1); ^ blt.c:989:1: error: inlining failed in call to always_inline 'bilinear_interpolation': optimization level attribute mismatch bilinear_interpolation(uint32_t tl, uint32_t tr, ^ blt.c:1207:11: error: called from here b[i] = bilinear_interpolation(tl, tr, bl, br, fx, fy); ^ Do not force inlining of these functions and let the compiler decide to avoid the compilation failure. v2: fix up the other two force_inlines whilst we are here Signed-off-by: Olivier Fourdan --- src/sna/blt.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sna/blt.c b/src/sna/blt.c index a2472c1c..2dae9c2b 100644 --- a/src/sna/blt.c +++ b/src/sna/blt.c @@ -976,7 +976,7 @@ memcpy_xor(const void *src, void *dst, int bpp, } #define BILINEAR_INTERPOLATION_BITS 4 -static force_inline int +static inline int bilinear_weight(pixman_fixed_t x) { return (x >> (16 - BILINEAR_INTERPOLATION_BITS)) & @@ -985,7 +985,7 @@ bilinear_weight(pixman_fixed_t x) #if BILINEAR_INTERPOLATION_BITS <= 4 /* Inspired by Filter_32_opaque from Skia */ -static force_inline uint32_t +static inline uint32_t bilinear_interpolation(uint32_t tl, uint32_t tr, uint32_t bl, uint32_t br, int distx, int disty) @@ -1018,7 +1018,7 @@ bilinear_interpolation(uint32_t tl, uint32_t tr, return ((lo >> 8) & 0xff00ff) | (hi & ~0xff00ff); } #elif SIZEOF_LONG > 4 -static force_inline uint32_t +static inline uint32_t bilinear_interpolation(uint32_t tl, uint32_t tr, uint32_t bl, uint32_t br, int distx, int disty) @@ -1063,7 +1063,7 @@ bilinear_interpolation(uint32_t tl, uint32_t tr, return (uint32_t)(r >> 16); } #else -static force_inline uint32_t +static inline uint32_t bilinear_interpolation(uint32_t tl, uint32_t tr, uint32_t bl, uint32_t br, int distx, int disty) From 0bcc3ef02c48edbf838e2665c096cc5cf5cc50c0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 24 Apr 2015 12:32:19 +0100 Subject: [PATCH 24/61] sna: Mark avx as being a subset of avx2 optimisations Signed-off-by: Chris Wilson --- src/sna/compiler.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sna/compiler.h b/src/sna/compiler.h index 44d17dbd..eaabf833 100644 --- a/src/sna/compiler.h +++ b/src/sna/compiler.h @@ -63,16 +63,16 @@ #define sse4_2 __attribute__((target("sse4.2,sse2,fpmath=sse"))) #endif -#if HAS_GCC(4, 7) -#define avx2 __attribute__((target("avx2,sse4.2,sse2,fpmath=sse"))) -#endif - #if HAS_GCC(4, 6) && defined(__OPTIMIZE__) #define fast __attribute__((optimize("Ofast"))) #else #define fast #endif +#if HAS_GCC(4, 7) +#define avx2 fast __attribute__((target("avx2,avx,sse4.2,sse2,fpmath=sse"))) +#endif + #if HAS_GCC(4, 6) && defined(__OPTIMIZE__) #define fast_memcpy __attribute__((optimize("Ofast"))) __attribute__((target("inline-all-stringops"))) #elif HAS_GCC(4, 5) && defined(__OPTIMIZE__) From f2807d3b5ee3a3ab27ba8216fa02f979338fba87 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 24 Apr 2015 13:08:24 +0100 Subject: [PATCH 25/61] sna: Reuse compiler attribute fast to build fast_memcpy Signed-off-by: Chris Wilson --- src/sna/compiler.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sna/compiler.h b/src/sna/compiler.h index eaabf833..c7231370 100644 --- a/src/sna/compiler.h +++ b/src/sna/compiler.h @@ -73,10 +73,8 @@ #define avx2 fast __attribute__((target("avx2,avx,sse4.2,sse2,fpmath=sse"))) #endif -#if HAS_GCC(4, 6) && defined(__OPTIMIZE__) -#define fast_memcpy __attribute__((optimize("Ofast"))) __attribute__((target("inline-all-stringops"))) -#elif HAS_GCC(4, 5) && defined(__OPTIMIZE__) -#define fast_memcpy __attribute__((target("inline-all-stringops"))) +#if HAS_GCC(4, 5) && defined(__OPTIMIZE__) +#define fast_memcpy fast __attribute__((target("inline-all-stringops"))) #else #define fast_memcpy #endif From 73ae4197d6ebfa0fc1b7c2653b74667a51885a5e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 24 Apr 2015 14:36:50 +0100 Subject: [PATCH 26/61] sna: Defer marking cache objects purgeable Signed-off-by: Chris Wilson --- src/sna/kgem.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/src/sna/kgem.c b/src/sna/kgem.c index d1902552..62388129 100644 --- a/src/sna/kgem.c +++ b/src/sna/kgem.c @@ -2523,8 +2523,7 @@ static bool kgem_bo_move_to_cache(struct kgem *kgem, struct kgem_bo *bo) kgem_bo_move_to_snoop(kgem, bo); } else if (bo->scanout) { kgem_bo_move_to_scanout(kgem, bo); - } else if ((bo = kgem_bo_replace_io(bo))->reusable && - kgem_bo_set_purgeable(kgem, bo)) { + } else if ((bo = kgem_bo_replace_io(bo))->reusable) { kgem_bo_move_to_inactive(kgem, bo); retired = true; } else @@ -2728,9 +2727,6 @@ static void __kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo) assert(list_is_empty(&bo->request)); if (bo->map__cpu == NULL || bucket(bo) >= NUM_CACHE_BUCKETS) { - if (!kgem_bo_set_purgeable(kgem, bo)) - goto destroy; - if (!kgem->has_llc && bo->domain == DOMAIN_CPU) goto destroy; @@ -2902,14 +2898,8 @@ static bool __kgem_retire_rq(struct kgem *kgem, struct kgem_request *rq) assert(rq->bo->refcnt > 0); if (--rq->bo->refcnt == 0) { - if (kgem_bo_set_purgeable(kgem, rq->bo)) { - kgem_bo_move_to_inactive(kgem, rq->bo); - retired = true; - } else { - DBG(("%s: closing %d\n", - __FUNCTION__, rq->bo->handle)); - kgem_bo_free(kgem, rq->bo); - } + kgem_bo_move_to_inactive(kgem, rq->bo); + retired = true; } __kgem_request_free(rq); @@ -4093,6 +4083,7 @@ bool kgem_expire_cache(struct kgem *kgem) break; } + kgem_bo_set_purgeable(kgem, bo); bo->delta = now; } if (expire) { @@ -4138,6 +4129,7 @@ bool kgem_expire_cache(struct kgem *kgem) break; } + kgem_bo_set_purgeable(kgem, bo); bo->delta = now; } } From dafd181441f6cde71e6748adab230e851ca5a277 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 24 Apr 2015 20:48:14 +0100 Subject: [PATCH 27/61] uxa: Fix compilation for bool ../../../src/uxa/intel_driver.c: At top level: ../../../src/uxa/intel_driver.c:769:1: error: unknown type name 'bool' Signed-off-by: Chris Wilson --- src/uxa/intel_driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uxa/intel_driver.c b/src/uxa/intel_driver.c index 0fb86097..8e685bd6 100644 --- a/src/uxa/intel_driver.c +++ b/src/uxa/intel_driver.c @@ -766,7 +766,7 @@ I830HandleUEvents(int fd, void *closure) udev_device_unref(dev); } -static bool has_randr(void) +static int has_randr(void) { #if HAS_DIXREGISTERPRIVATEKEY return dixPrivateKeyRegistered(rrPrivKey); From 1a67dacd7514c3327ca0fd27e617309fd437e44f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 27 Apr 2015 09:27:52 +0100 Subject: [PATCH 28/61] sna: Remove conflicting set-purgeable A couple of stray set-purgeable points were causing eventual assertions that we didn't try and set-purgeable twice. Minor regression from commit 73ae4197d6ebfa0fc1b7c2653b74667a51885a5e Author: Chris Wilson Date: Fri Apr 24 14:36:50 2015 +0100 sna: Defer marking cache objects purgeable Signed-off-by: Chris Wilson --- src/intel_list.h | 28 ++++++++++++++++++++++++++++ src/sna/kgem.c | 33 +++++++++++++++++---------------- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/src/intel_list.h b/src/intel_list.h index 8a8b76f0..d0408bed 100644 --- a/src/intel_list.h +++ b/src/intel_list.h @@ -402,6 +402,34 @@ static inline void list_move_tail(struct list *list, struct list *head) #define container_of(ptr, type, member) \ ((type *)((char *)(ptr) - (char *) &((type *)0)->member)) +static inline void __list_splice(const struct list *list, + struct list *prev, + struct list *next) +{ + struct list *first = list->next; + struct list *last = list->prev; + + first->prev = prev; + prev->next = first; + + last->next = next; + next->prev = last; +} + +static inline void list_splice(const struct list *list, + struct list *head) +{ + if (!list_is_empty(list)) + __list_splice(list, head, head->next); +} + +static inline void list_splice_tail(const struct list *list, + struct list *head) +{ + if (!list_is_empty(list)) + __list_splice(list, head->prev, head); +} + static inline int list_is_singular(const struct list *list) { return list->next == list->prev; diff --git a/src/sna/kgem.c b/src/sna/kgem.c index 62388129..ca567fd2 100644 --- a/src/sna/kgem.c +++ b/src/sna/kgem.c @@ -750,7 +750,7 @@ kgem_bo_set_purgeable(struct kgem *kgem, struct kgem_bo *bo) madv.madv = I915_MADV_DONTNEED; if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_MADVISE, &madv) == 0) { bo->purged = 1; - kgem->need_purge |= !madv.retained && bo->domain == DOMAIN_GPU; + kgem->need_purge |= !madv.retained && bo->domain != DOMAIN_CPU; return madv.retained; } @@ -794,7 +794,7 @@ kgem_bo_clear_purgeable(struct kgem *kgem, struct kgem_bo *bo) madv.madv = I915_MADV_WILLNEED; if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_MADVISE, &madv) == 0) { bo->purged = !madv.retained; - kgem->need_purge |= !madv.retained && bo->domain == DOMAIN_GPU; + kgem->need_purge |= !madv.retained && bo->domain != DOMAIN_CPU; return madv.retained; } @@ -2322,6 +2322,7 @@ inline static void kgem_bo_move_to_inactive(struct kgem *kgem, assert(!bo->snoop); assert(!bo->flush); assert(!bo->needs_flush); + assert(!bo->delta); assert(list_is_empty(&bo->vma)); assert_tiling(kgem, bo); assert_cacheing(kgem, bo); @@ -2363,6 +2364,10 @@ static struct kgem_bo *kgem_bo_replace_io(struct kgem_bo *bo) return bo; assert(!bo->snoop); + assert(!bo->purged); + assert(!bo->scanout); + assert(!bo->delta); + if (__kgem_freed_bo) { base = __kgem_freed_bo; __kgem_freed_bo = *(struct kgem_bo **)base; @@ -2393,6 +2398,7 @@ inline static void kgem_bo_remove_from_inactive(struct kgem *kgem, list_del(&bo->list); assert(bo->rq == NULL); assert(bo->exec == NULL); + assert(!bo->purged); if (!list_is_empty(&bo->vma)) { assert(bo->map__gtt || bo->map__wc || bo->map__cpu); list_del(&bo->vma); @@ -2488,6 +2494,8 @@ static void kgem_bo_move_to_snoop(struct kgem *kgem, struct kgem_bo *bo) assert(!bo->needs_flush); assert(bo->refcnt == 0); assert(bo->exec == NULL); + assert(!bo->purged); + assert(!bo->delta); if (DBG_NO_SNOOP_CACHE) { kgem_bo_free(kgem, bo); @@ -4058,7 +4066,8 @@ bool kgem_expire_cache(struct kgem *kgem) bool idle; unsigned int i; - time(&now); + if (!time(&now)) + return false; while (__kgem_freed_bo) { bo = __kgem_freed_bo; @@ -4083,7 +4092,7 @@ bool kgem_expire_cache(struct kgem *kgem) break; } - kgem_bo_set_purgeable(kgem, bo); + assert(now); bo->delta = now; } if (expire) { @@ -4129,6 +4138,7 @@ bool kgem_expire_cache(struct kgem *kgem) break; } + assert(now); kgem_bo_set_purgeable(kgem, bo); bo->delta = now; } @@ -4164,12 +4174,7 @@ bool kgem_expire_cache(struct kgem *kgem) __FUNCTION__, bo->handle)); } } - if (!list_is_empty(&preserve)) { - preserve.prev->next = kgem->inactive[i].next; - kgem->inactive[i].next->prev = preserve.prev; - kgem->inactive[i].next = preserve.next; - preserve.next->prev = &kgem->inactive[i]; - } + list_splice_tail(&preserve, &kgem->inactive[i]); } #ifdef DEBUG_MEMORY @@ -4679,6 +4684,8 @@ struct kgem_bo *kgem_create_linear(struct kgem *kgem, int size, unsigned flags) if ((flags & CREATE_UNCACHED) == 0) { bo = search_linear_cache(kgem, size, CREATE_INACTIVE | flags); if (bo) { + assert(!bo->purged); + assert(!bo->delta); assert(bo->domain != DOMAIN_GPU); ASSERT_IDLE(kgem, bo->handle); bo->refcnt = 1; @@ -6447,12 +6454,6 @@ static void kgem_trim_vma_cache(struct kgem *kgem, int type, int bucket) list_del(&bo->vma); kgem->vma[type].count--; - - if (!bo->purged && !kgem_bo_set_purgeable(kgem, bo)) { - DBG(("%s: freeing unpurgeable old mapping\n", - __FUNCTION__)); - kgem_bo_free(kgem, bo); - } } } From e7016d30f3a0ae817c77ccbd962f776ac3e7e100 Mon Sep 17 00:00:00 2001 From: Olivier Fourdan Date: Wed, 29 Apr 2015 10:33:19 +0100 Subject: [PATCH 29/61] backlight: Do not hang forever if helper pid is -1 Backlight helper PID is set to -1 by default, if for some reason it's not set, we may end up with waitpid(-1, ...) which will hang forever. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=90230 Signed-off-by: Olivier Fourdan --- src/backlight.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backlight.c b/src/backlight.c index 84d8f761..c65e466b 100644 --- a/src/backlight.c +++ b/src/backlight.c @@ -523,7 +523,7 @@ void backlight_disable(struct backlight *b) void backlight_close(struct backlight *b) { backlight_disable(b); - if (b->pid) + if (b->pid > 0) waitpid(b->pid, NULL, 0); } From b400dd22c28a08d7644b4ede076be9d8c2b8ca9d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 3 May 2015 11:58:25 +0100 Subject: [PATCH 30/61] sna: Clear has-pinned-batches if we can no longer actually pin Insert rant about useful kernel interfaces being removed without justification. References: https://bugs.freedesktop.org/show_bug.cgi?id=88411 Signed-off-by: Chris Wilson --- src/sna/kgem.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sna/kgem.c b/src/sna/kgem.c index ca567fd2..d3925308 100644 --- a/src/sna/kgem.c +++ b/src/sna/kgem.c @@ -1459,6 +1459,8 @@ err: if (ret != -ENODEV && kgem->gen == 020) return false; + kgem->has_pinned_batches = false; + /* For simplicity populate the lists with a single unpinned bo */ for (n = 0; n < ARRAY_SIZE(count); n++) { struct kgem_bo *bo; From 5054e2271210a52bf88b0f12c35d687ce9e8210d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 4 May 2015 14:00:13 +0100 Subject: [PATCH 31/61] Remove the driver option to delete connectors on unplugging With a MST topology change, we can find outputs may disappear. We offered a choice as to whether to simply disable them or completely remove them from the listing of available outputs. However, clients never expected that their operation on any output could trigger a BadID XError (or that there is anyway to prevent race conditions). As such an option was made to disable by default, but allow testing complete removal. Now the RandR protocol has been clarified such that XID assigned to outputs are now permanent, as such the option breaks the spec, so drop it. See randrproto commit 895ee5264524c7c239ee4ef5e39c4e295323fb51 Author: Dave Airlie Date: Wed Apr 22 10:58:18 2015 +1000 randrproto: clarify output XID lifetimes. This just makes a note that randr won't make outputs disappear dynamically. Signed-off-by: Chris Wilson Cc: Dave Airlie --- src/intel_options.c | 1 - src/intel_options.h | 1 - src/sna/sna.h | 1 - src/sna/sna_display.c | 46 ++++------------------------------------- src/sna/sna_driver.c | 3 --- src/uxa/intel_display.c | 14 +------------ 6 files changed, 5 insertions(+), 61 deletions(-) diff --git a/src/intel_options.c b/src/intel_options.c index 034b591f..465f7392 100644 --- a/src/intel_options.c +++ b/src/intel_options.c @@ -25,7 +25,6 @@ const OptionInfoRec intel_options[] = { {OPTION_PREFER_OVERLAY, "XvPreferOverlay", OPTV_BOOLEAN, {0}, 0}, {OPTION_HOTPLUG, "HotPlug", OPTV_BOOLEAN, {0}, 1}, {OPTION_REPROBE, "ReprobeOutputs", OPTV_BOOLEAN, {0}, 0}, - {OPTION_DELETE_DP12, "DeleteUnusedDP12Displays", OPTV_BOOLEAN, {0}, 0}, #ifdef INTEL_XVMC {OPTION_XVMC, "XvMC", OPTV_BOOLEAN, {0}, 1}, #endif diff --git a/src/intel_options.h b/src/intel_options.h index 56ba279a..492e03fb 100644 --- a/src/intel_options.h +++ b/src/intel_options.h @@ -28,7 +28,6 @@ enum intel_options { OPTION_PREFER_OVERLAY, OPTION_HOTPLUG, OPTION_REPROBE, - OPTION_DELETE_DP12, #if defined(XvMCExtension) && defined(ENABLE_XVMC) OPTION_XVMC, #define INTEL_XVMC 1 diff --git a/src/sna/sna.h b/src/sna/sna.h index e51ee14f..374754b4 100644 --- a/src/sna/sna.h +++ b/src/sna/sna.h @@ -248,7 +248,6 @@ struct sna { #define SNA_FLUSH_GTT 0x400 #define SNA_PERFORMANCE 0x1000 #define SNA_POWERSAVE 0x2000 -#define SNA_REMOVE_OUTPUTS 0x4000 #define SNA_HAS_FLIP 0x10000 #define SNA_HAS_ASYNC_FLIP 0x20000 #define SNA_LINEAR_FB 0x40000 diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c index 3ba2df98..e96040d5 100644 --- a/src/sna/sna_display.c +++ b/src/sna/sna_display.c @@ -4502,38 +4502,6 @@ skip: return len; } -static void sna_output_del(xf86OutputPtr output) -{ - ScrnInfoPtr scrn = output->scrn; - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - int i; - - DBG(("%s(%s)\n", __FUNCTION__, output->name)); - assert(to_sna_output(output)); - - RROutputDestroy(output->randr_output); - sna_output_destroy(output); - - while (output->probed_modes) - xf86DeleteMode(&output->probed_modes, output->probed_modes); - - free(output); - - for (i = 0; i < config->num_output; i++) - if (config->output[i] == output) - break; - assert(i < to_sna(scrn)->mode.num_real_output); - DBG(("%s: removing output #%d of %d\n", - __FUNCTION__, i, to_sna(scrn)->mode.num_real_output)); - - for (; i < config->num_output; i++) { - config->output[i] = config->output[i+1]; - config->output[i]->possible_clones >>= 1; - } - config->num_output--; - to_sna(scrn)->mode.num_real_output--; -} - static int output_rank(const void *A, const void *B) { const xf86OutputPtr *a = A; @@ -4674,17 +4642,11 @@ void sna_mode_discover(struct sna *sna) sna_output->serial, serial)); xf86DrvMsg(sna->scrn->scrnIndex, X_INFO, - "%s output %s\n", - sna->flags & SNA_REMOVE_OUTPUTS ? "Removed" : "Disabled", + "Disabled output %s\n", output->name); - if (sna->flags & SNA_REMOVE_OUTPUTS) { - sna_output_del(output); - i--; - } else { - sna_output->id = 0; - output->crtc = NULL; - RROutputChanged(output->randr_output, TRUE); - } + sna_output->id = 0; + output->crtc = NULL; + RROutputChanged(output->randr_output, TRUE); changed |= 2; } diff --git a/src/sna/sna_driver.c b/src/sna/sna_driver.c index 488ca9b2..4e76fd0e 100644 --- a/src/sna/sna_driver.c +++ b/src/sna/sna_driver.c @@ -621,9 +621,6 @@ static Bool sna_pre_init(ScrnInfoPtr scrn, int probe) if (xf86ReturnOptValBool(sna->Options, OPTION_TILING_FB, FALSE)) sna->flags |= SNA_LINEAR_FB; - if (xf86ReturnOptValBool(sna->Options, OPTION_DELETE_DP12, FALSE)) - sna->flags |= SNA_REMOVE_OUTPUTS; - if (!xf86ReturnOptValBool(sna->Options, OPTION_SWAPBUFFERS_WAIT, TRUE)) sna->flags |= SNA_NO_WAIT; DBG(("%s: swapbuffer wait? %s\n", __FUNCTION__, sna->flags & SNA_NO_WAIT ? "disabled" : "enabled")); diff --git a/src/uxa/intel_display.c b/src/uxa/intel_display.c index a95b3de5..0cdc8d26 100644 --- a/src/uxa/intel_display.c +++ b/src/uxa/intel_display.c @@ -94,8 +94,6 @@ struct intel_mode { intel_pageflip_abort_proc abort; void *data; } pageflip; - - Bool delete_dp_12_displays; }; struct intel_pageflip { @@ -2248,10 +2246,6 @@ Bool intel_mode_pre_init(ScrnInfoPtr scrn, int fd, int cpp) intel->use_pageflipping = TRUE; } - if (xf86ReturnOptValBool(intel->Options, OPTION_DELETE_DP12, FALSE)) { - mode->delete_dp_12_displays = TRUE; - } - intel->modes = mode; drmModeFreeResources(mode_res); return TRUE; @@ -2515,12 +2509,11 @@ intel_mode_hotplug(struct intel_screen_private *intel) int i, j; Bool found; Bool changed = FALSE; - struct intel_mode *mode = intel->modes; + mode_res = drmModeGetResources(intel->drmSubFD); if (!mode_res) goto out; -restart_destroy: for (i = 0; i < config->num_output; i++) { xf86OutputPtr output = config->output[i]; struct intel_output *intel_output; @@ -2542,11 +2535,6 @@ restart_destroy: RROutputChanged(output->randr_output, TRUE); changed = TRUE; - if (mode->delete_dp_12_displays) { - RROutputDestroy(output->randr_output); - xf86OutputDestroy(output); - goto restart_destroy; - } } /* find new output ids we don't have outputs for */ From 63c43dfa63f4a5ecfa5a00f8b802c56f40d2908c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 13 May 2015 13:44:41 +0100 Subject: [PATCH 32/61] intel-virtual-output: Only store cursor image on reference display We only need a single copy of the cursor image, from which we can create all the cloned cursors. Signed-off-by: Chris Wilson --- tools/virtual.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/tools/virtual.c b/tools/virtual.c index 850eb929..75bd7015 100644 --- a/tools/virtual.c +++ b/tools/virtual.c @@ -111,7 +111,7 @@ struct display { Cursor invisible_cursor; Cursor visible_cursor; - XcursorImage cursor_image; + XcursorImage cursor_image; /* first only */ int cursor_serial; int cursor_x; int cursor_y; @@ -1614,14 +1614,17 @@ static Cursor display_load_invisible_cursor(struct display *display) static Cursor display_get_visible_cursor(struct display *display) { - if (display->cursor_serial != display->cursor_image.size) { - DBG(CURSOR, ("%s updating cursor\n", DisplayString(display->dpy))); + struct display *first = display->ctx->display; + + if (display->cursor_serial != first->cursor_serial) { + DBG(CURSOR, ("%s updating cursor %dx%d, serial %d\n", + DisplayString(display->dpy), first->cursor_image.width, first->cursor_image.height, first->cursor_serial)); if (display->visible_cursor) XFreeCursor(display->dpy, display->visible_cursor); - display->visible_cursor = XcursorImageLoadCursor(display->dpy, &display->cursor_image); - display->cursor_serial = display->cursor_image.size; + display->visible_cursor = XcursorImageLoadCursor(display->dpy, &first->cursor_image); + display->cursor_serial = first->cursor_serial; } return display->visible_cursor; @@ -1644,20 +1647,13 @@ static void display_load_visible_cursor(struct display *display, XFixesCursorIma display->cursor_image.height = cur->height; display->cursor_image.xhot = cur->xhot; display->cursor_image.yhot = cur->yhot; - display->cursor_image.size++; + display->cursor_serial++; n = cur->width*cur->height; src = cur->pixels; dst = display->cursor_image.pixels; while (n--) *dst++ = *src++; - - DBG(CURSOR, ("%s marking cursor changed\n", DisplayString(display->dpy))); - display->cursor_moved++; - if (display->cursor != display->invisible_cursor) { - display->cursor_visible++; - context_enable_timer(display->ctx); - } } static void display_cursor_move(struct display *display, int x, int y, int visible) @@ -1700,6 +1696,8 @@ static void display_flush_cursor(struct display *display) if (cursor == None) cursor = display->invisible_cursor; if (cursor != display->cursor) { + DBG(CURSOR, ("%s setting cursor shape %lx\n", + DisplayString(display->dpy), (long)cursor)); XDefineCursor(display->dpy, display->root, cursor); display->cursor = cursor; } @@ -3405,8 +3403,17 @@ int main(int argc, char **argv) if (cur == NULL) continue; - for (i = 1; i < ctx.ndisplay; i++) - display_load_visible_cursor(&ctx.display[i], cur); + display_load_visible_cursor(&ctx.display[0], cur); + for (i = 1; i < ctx.ndisplay; i++) { + struct display *display = &ctx.display[i]; + + DBG(CURSOR, ("%s marking cursor changed\n", DisplayString(display->dpy))); + display->cursor_moved++; + if (display->cursor != display->invisible_cursor) { + display->cursor_visible++; + context_enable_timer(display->ctx); + } + } XFree(cur); } else if (e.type == ctx.display->rr_event + RRScreenChangeNotify) { From f696867c897f1f879c4c03e19690e8217db4d81e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 13 May 2015 13:58:20 +0100 Subject: [PATCH 33/61] intel-virtual-output: Record the cursor shape in the DBG log Signed-off-by: Chris Wilson --- tools/virtual.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tools/virtual.c b/tools/virtual.c index 75bd7015..f5cba1a0 100644 --- a/tools/virtual.c +++ b/tools/virtual.c @@ -1654,6 +1654,26 @@ static void display_load_visible_cursor(struct display *display, XFixesCursorIma dst = display->cursor_image.pixels; while (n--) *dst++ = *src++; + + if (verbose & CURSOR) { + int x, y; + + printf("%s cursor image %dx%d, serial %d:\n", + DisplayString(display->dpy), + cur->width, cur->height, + display->cursor_serial); + dst = display->cursor_image.pixels; + for (y = 0; y < cur->height; y++) { + for (x = 0; x < cur->width; x++) { + if (x == cur->xhot && y == cur->yhot) + printf("+"); + else + printf("%c", *dst ? *dst >> 24 >= 127 ? 'x' : '.' : ' '); + dst++; + } + printf("\n"); + } + } } static void display_cursor_move(struct display *display, int x, int y, int visible) From aa44ba990a4c49fcfc5ed7dbf9968e3c622ffa0a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 16 May 2015 22:05:05 +0100 Subject: [PATCH 34/61] intel: Prevent crash with X -configure When run with -configure, xf86configptr is NULL, so be careful and do not dereference it. Signed-off-by: Chris Wilson --- src/intel_module.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/intel_module.c b/src/intel_module.c index 2a3b0166..689c0dda 100644 --- a/src/intel_module.c +++ b/src/intel_module.c @@ -514,6 +514,9 @@ static enum accel_method { NOACCEL, SNA, UXA } get_accel_method(void) if (hosted()) return SNA; + if (xf86configptr == NULL) /* X -configure */ + return SNA; + dev = _xf86findDriver("intel", xf86configptr->conf_device_lst); if (dev && dev->dev_option_lst) { const char *s; From a16a7e36ca3b22af2978695a57c2f2e9250529a7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 17 May 2015 08:51:57 +0100 Subject: [PATCH 35/61] sna: Only mark wedged checking inside operations as a WARN These are primarily to serve to detect when we expect to see corruption as a result of a badly timed EIO rather than fatal, so downgrade the assertion to a warn. Signed-off-by: Chris Wilson --- src/sna/kgem.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sna/kgem.h b/src/sna/kgem.h index adc777de..bdcb9f14 100644 --- a/src/sna/kgem.h +++ b/src/sna/kgem.h @@ -410,7 +410,7 @@ static inline void kgem_set_mode(struct kgem *kgem, enum kgem_mode mode, struct kgem_bo *bo) { - assert(!kgem->wedged); + warn_unless(!kgem->wedged); #if DEBUG_FLUSH_BATCH kgem_submit(kgem); @@ -432,7 +432,7 @@ static inline void _kgem_set_mode(struct kgem *kgem, enum kgem_mode mode) { assert(kgem->mode == KGEM_NONE); assert(kgem->nbatch == 0); - assert(!kgem->wedged); + warn_unless(!kgem->wedged); kgem->context_switch(kgem, mode); kgem->mode = mode; } From 335ac8742e9eadcdf8f087b24f84c7df0fda31c0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 17 May 2015 08:53:45 +0100 Subject: [PATCH 36/61] sna: Wrap CPU access for composite operations with sigtrap Anytime we access a mmap() we need to be prepared for the kernel to send us a SIGBUS, but we were missing a few sigtraps around calls to pixman_fill and pixman_blt. Signed-off-by: Chris Wilson --- src/sna/sna_accel.c | 38 ++++++++++++++++++------------ src/sna/sna_blt.c | 29 ++++++++++++++++------- src/sna/sna_trapezoids_boxes.c | 2 ++ src/sna/sna_trapezoids_imprecise.c | 1 + src/sna/sna_trapezoids_mono.c | 2 ++ src/sna/sna_trapezoids_precise.c | 1 + 6 files changed, 50 insertions(+), 23 deletions(-) diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c index 4db011f3..7cd9a0c4 100644 --- a/src/sna/sna_accel.c +++ b/src/sna/sna_accel.c @@ -2365,21 +2365,26 @@ skip_inplace_map: assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu)); } - assert(pixmap->devKind); - if (priv->clear_color == 0 || - pixmap->drawable.bitsPerPixel == 8 || - priv->clear_color == (1 << pixmap->drawable.depth) - 1) { - memset(pixmap->devPrivate.ptr, priv->clear_color, - (size_t)pixmap->devKind * pixmap->drawable.height); - } else { - pixman_fill(pixmap->devPrivate.ptr, - pixmap->devKind/sizeof(uint32_t), - pixmap->drawable.bitsPerPixel, - 0, 0, - pixmap->drawable.width, - pixmap->drawable.height, - priv->clear_color); - } + if (sigtrap_get() == 0) { + assert(pixmap->devKind); + sigtrap_assert_active(); + if (priv->clear_color == 0 || + pixmap->drawable.bitsPerPixel == 8 || + priv->clear_color == (1 << pixmap->drawable.depth) - 1) { + memset(pixmap->devPrivate.ptr, priv->clear_color, + (size_t)pixmap->devKind * pixmap->drawable.height); + } else { + pixman_fill(pixmap->devPrivate.ptr, + pixmap->devKind/sizeof(uint32_t), + pixmap->drawable.bitsPerPixel, + 0, 0, + pixmap->drawable.width, + pixmap->drawable.height, + priv->clear_color); + } + sigtrap_put(); + } else + return false; clear_done: sna_damage_all(&priv->cpu_damage, pixmap); @@ -2929,6 +2934,7 @@ move_to_cpu: } assert(pixmap->devKind); + sigtrap_assert_active(); do { pixman_fill(pixmap->devPrivate.ptr, pixmap->devKind/sizeof(uint32_t), @@ -6869,6 +6875,7 @@ fallback: assert(dst_pixmap->devPrivate.ptr); assert(dst_pixmap->devKind); + sigtrap_assert_active(); do { pixman_fill(dst_pixmap->devPrivate.ptr, dst_pixmap->devKind/sizeof(uint32_t), @@ -17064,6 +17071,7 @@ sna_get_image__fast(PixmapPtr pixmap, __FUNCTION__, priv->clear_color)); assert(DAMAGE_IS_ALL(priv->gpu_damage)); assert(priv->cpu_damage == NULL); + sigtrap_assert_active(); if (priv->clear_color == 0 || pixmap->drawable.bitsPerPixel == 8 || diff --git a/src/sna/sna_blt.c b/src/sna/sna_blt.c index 3d8c040f..38167ff2 100644 --- a/src/sna/sna_blt.c +++ b/src/sna/sna_blt.c @@ -86,6 +86,11 @@ static const uint8_t fill_ROP[] = { ROP_1 }; +static void sig_done(struct sna *sna, const struct sna_composite_op *op) +{ + sigtrap_put(); +} + static void nop_done(struct sna *sna, const struct sna_composite_op *op) { assert(sna->kgem.nbatch <= KGEM_BATCH_SIZE(&sna->kgem)); @@ -1005,6 +1010,7 @@ static void blt_composite_fill__cpu(struct sna *sna, assert(op->dst.pixmap->devPrivate.ptr); assert(op->dst.pixmap->devKind); + sigtrap_assert_active(); pixman_fill(op->dst.pixmap->devPrivate.ptr, op->dst.pixmap->devKind / sizeof(uint32_t), op->dst.pixmap->drawable.bitsPerPixel, @@ -1024,6 +1030,7 @@ blt_composite_fill_box_no_offset__cpu(struct sna *sna, assert(op->dst.pixmap->devPrivate.ptr); assert(op->dst.pixmap->devKind); + sigtrap_assert_active(); pixman_fill(op->dst.pixmap->devPrivate.ptr, op->dst.pixmap->devKind / sizeof(uint32_t), op->dst.pixmap->drawable.bitsPerPixel, @@ -1044,6 +1051,7 @@ blt_composite_fill_boxes_no_offset__cpu(struct sna *sna, assert(op->dst.pixmap->devPrivate.ptr); assert(op->dst.pixmap->devKind); + sigtrap_assert_active(); pixman_fill(op->dst.pixmap->devPrivate.ptr, op->dst.pixmap->devKind / sizeof(uint32_t), op->dst.pixmap->drawable.bitsPerPixel, @@ -1065,6 +1073,7 @@ blt_composite_fill_box__cpu(struct sna *sna, assert(op->dst.pixmap->devPrivate.ptr); assert(op->dst.pixmap->devKind); + sigtrap_assert_active(); pixman_fill(op->dst.pixmap->devPrivate.ptr, op->dst.pixmap->devKind / sizeof(uint32_t), op->dst.pixmap->drawable.bitsPerPixel, @@ -1086,6 +1095,7 @@ blt_composite_fill_boxes__cpu(struct sna *sna, assert(op->dst.pixmap->devPrivate.ptr); assert(op->dst.pixmap->devKind); + sigtrap_assert_active(); pixman_fill(op->dst.pixmap->devPrivate.ptr, op->dst.pixmap->devKind / sizeof(uint32_t), op->dst.pixmap->drawable.bitsPerPixel, @@ -1464,6 +1474,7 @@ prepare_blt_clear(struct sna *sna, DBG(("%s\n", __FUNCTION__)); if (op->dst.bo == NULL) { + op->u.blt.pixel = 0; op->blt = blt_composite_fill__cpu; if (op->dst.x|op->dst.y) { op->box = blt_composite_fill_box__cpu; @@ -1474,9 +1485,8 @@ prepare_blt_clear(struct sna *sna, op->boxes = blt_composite_fill_boxes_no_offset__cpu; op->thread_boxes = blt_composite_fill_boxes_no_offset__cpu; } - op->done = nop_done; - op->u.blt.pixel = 0; - return true; + op->done = sig_done; + return sigtrap_get() == 0; } op->blt = blt_composite_fill; @@ -1519,8 +1529,8 @@ prepare_blt_fill(struct sna *sna, op->boxes = blt_composite_fill_boxes_no_offset__cpu; op->thread_boxes = blt_composite_fill_boxes_no_offset__cpu; } - op->done = nop_done; - return true; + op->done = sig_done; + return sigtrap_get() == 0; } op->blt = blt_composite_fill; @@ -2436,6 +2446,9 @@ prepare_blt_put(struct sna *sna, op->box = blt_put_composite_box; op->boxes = blt_put_composite_boxes; } + + op->done = nop_done; + return true; } else { if (alpha_fixup) { op->u.blt.pixel = alpha_fixup; @@ -2447,10 +2460,10 @@ prepare_blt_put(struct sna *sna, op->box = blt_put_composite_box__cpu; op->boxes = blt_put_composite_boxes__cpu; } - } - op->done = nop_done; - return true; + op->done = sig_done; + return sigtrap_get() == 0; + } } static bool diff --git a/src/sna/sna_trapezoids_boxes.c b/src/sna/sna_trapezoids_boxes.c index 9900e3f0..b41121b4 100644 --- a/src/sna/sna_trapezoids_boxes.c +++ b/src/sna/sna_trapezoids_boxes.c @@ -592,6 +592,8 @@ lerp32_opacity(PixmapPtr scratch, uint32_t *ptr; int stride, i; + sigtrap_assert_active(); + ptr = (uint32_t*)((uint8_t *)scratch->devPrivate.ptr + scratch->devKind * y); ptr += x; stride = scratch->devKind / 4; diff --git a/src/sna/sna_trapezoids_imprecise.c b/src/sna/sna_trapezoids_imprecise.c index df22add5..4e90f9c4 100644 --- a/src/sna/sna_trapezoids_imprecise.c +++ b/src/sna/sna_trapezoids_imprecise.c @@ -2370,6 +2370,7 @@ tor_blt_lerp32(struct sna *sna, if (coverage == 0) return; + sigtrap_assert_active(); ptr += box->y1 * stride + box->x1; h = box->y2 - box->y1; diff --git a/src/sna/sna_trapezoids_mono.c b/src/sna/sna_trapezoids_mono.c index 29cb58ff..5b65fa45 100644 --- a/src/sna/sna_trapezoids_mono.c +++ b/src/sna/sna_trapezoids_mono.c @@ -1013,6 +1013,7 @@ mono_inplace_fill_box(struct sna *sna, box->x2 - box->x1, box->y2 - box->y1, fill->color)); + sigtrap_assert_active(); pixman_fill(fill->data, fill->stride, fill->bpp, box->x1, box->y1, box->x2 - box->x1, @@ -1034,6 +1035,7 @@ mono_inplace_fill_boxes(struct sna *sna, box->x2 - box->x1, box->y2 - box->y1, fill->color)); + sigtrap_assert_active(); pixman_fill(fill->data, fill->stride, fill->bpp, box->x1, box->y1, box->x2 - box->x1, diff --git a/src/sna/sna_trapezoids_precise.c b/src/sna/sna_trapezoids_precise.c index f1532d31..c9838528 100644 --- a/src/sna/sna_trapezoids_precise.c +++ b/src/sna/sna_trapezoids_precise.c @@ -2386,6 +2386,7 @@ tor_blt_lerp32(struct sna *sna, if (coverage == 0) return; + sigtrap_assert_active(); ptr += box->y1 * stride + box->x1; h = box->y2 - box->y1; From 959598cbff68f07d0412c848a857a4d02cf8da5b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 17 May 2015 13:01:04 +0100 Subject: [PATCH 37/61] sna: Check and warn if there exists a GPU error state When we mark the GPU as wedge and disable acceleration, always check if there is a GPU error state and warn if so - it is increasingly rare to get a pure EIO from throttling thereby circumventing the current error state checker. Signed-off-by: Chris Wilson --- src/sna/kgem.c | 192 +++++++++++++++++++++++++++---------------------- 1 file changed, 108 insertions(+), 84 deletions(-) diff --git a/src/sna/kgem.c b/src/sna/kgem.c index d3925308..f6b72d9e 100644 --- a/src/sna/kgem.c +++ b/src/sna/kgem.c @@ -223,6 +223,12 @@ static struct kgem_bo *__kgem_freed_bo; static struct kgem_request *__kgem_freed_request; static struct drm_i915_gem_exec_object2 _kgem_dummy_exec; +static inline struct sna *__to_sna(struct kgem *kgem) +{ + /* minor layering violations */ + return container_of(kgem, struct sna, kgem); +} + static inline int bytes(struct kgem_bo *bo) { return __kgem_bo_size(bo); @@ -316,16 +322,108 @@ static void assert_bo_retired(struct kgem_bo *bo) #define assert_bo_retired(bo) #endif +static int __find_debugfs(struct kgem *kgem) +{ + int i; + + for (i = 0; i < DRM_MAX_MINOR; i++) { + char path[80]; + + sprintf(path, "/sys/kernel/debug/dri/%d/i915_wedged", i); + if (access(path, R_OK) == 0) + return i; + + sprintf(path, "/debug/dri/%d/i915_wedged", i); + if (access(path, R_OK) == 0) + return i; + } + + return -1; +} + +static int kgem_get_minor(struct kgem *kgem) +{ + struct stat st; + + if (fstat(kgem->fd, &st)) + return __find_debugfs(kgem); + + if (!S_ISCHR(st.st_mode)) + return __find_debugfs(kgem); + + return st.st_rdev & 0x63; +} + +static bool find_hang_state(struct kgem *kgem, char *path, int maxlen) +{ + int minor = kgem_get_minor(kgem); + + /* Search for our hang state in a few canonical locations. + * In the unlikely event of having multiple devices, we + * will need to check which minor actually corresponds to ours. + */ + + snprintf(path, maxlen, "/sys/class/drm/card%d/error", minor); + if (access(path, R_OK) == 0) + return true; + + snprintf(path, maxlen, "/sys/kernel/debug/dri/%d/i915_error_state", minor); + if (access(path, R_OK) == 0) + return true; + + snprintf(path, maxlen, "/debug/dri/%d/i915_error_state", minor); + if (access(path, R_OK) == 0) + return true; + + path[0] = '\0'; + return false; +} + +static bool has_error_state(struct kgem *kgem, char *path) +{ + bool ret = false; + char no; + int fd; + + fd = open(path, O_RDONLY); + if (fd >= 0) { + ret = read(fd, &no, 1) == 1 && no != 'N'; + close(fd); + } + + return ret; +} + +static int kgem_get_screen_index(struct kgem *kgem) +{ + return __to_sna(kgem)->scrn->scrnIndex; +} + static void __kgem_set_wedged(struct kgem *kgem) { + static int once; + char path[256]; + + if (kgem->wedged) + return; + + if (!once && + find_hang_state(kgem, path, sizeof(path)) && + has_error_state(kgem, path)) { + xf86DrvMsg(kgem_get_screen_index(kgem), X_ERROR, + "When reporting this, please include %s and the full dmesg.\n", + path); + once = 1; + } + kgem->wedged = true; - sna_render_mark_wedged(container_of(kgem, struct sna, kgem)); + sna_render_mark_wedged(__to_sna(kgem)); } static void kgem_sna_reset(struct kgem *kgem) { - struct sna *sna = container_of(kgem, struct sna, kgem); + struct sna *sna = __to_sna(kgem); sna->render.reset(sna); sna->blt_state.fill_bo = 0; @@ -333,7 +431,7 @@ static void kgem_sna_reset(struct kgem *kgem) static void kgem_sna_flush(struct kgem *kgem) { - struct sna *sna = container_of(kgem, struct sna, kgem); + struct sna *sna = __to_sna(kgem); sna->render.flush(sna); @@ -1359,44 +1457,6 @@ static bool test_has_pinned_batches(struct kgem *kgem) return gem_param(kgem, LOCAL_I915_PARAM_HAS_PINNED_BATCHES) > 0; } -static int kgem_get_screen_index(struct kgem *kgem) -{ - struct sna *sna = container_of(kgem, struct sna, kgem); - return sna->scrn->scrnIndex; -} - -static int __find_debugfs(struct kgem *kgem) -{ - int i; - - for (i = 0; i < DRM_MAX_MINOR; i++) { - char path[80]; - - sprintf(path, "/sys/kernel/debug/dri/%d/i915_wedged", i); - if (access(path, R_OK) == 0) - return i; - - sprintf(path, "/debug/dri/%d/i915_wedged", i); - if (access(path, R_OK) == 0) - return i; - } - - return -1; -} - -static int kgem_get_minor(struct kgem *kgem) -{ - struct stat st; - - if (fstat(kgem->fd, &st)) - return __find_debugfs(kgem); - - if (!S_ISCHR(st.st_mode)) - return __find_debugfs(kgem); - - return st.st_rdev & 0x63; -} - static bool kgem_init_pinned_batches(struct kgem *kgem) { int count[2] = { 16, 4 }; @@ -3765,13 +3825,13 @@ retry: xf86DrvMsg(kgem_get_screen_index(kgem), X_WARNING, "Failed to submit rendering commands, trying again with outputs disabled.\n"); - if (sna_mode_disable(container_of(kgem, struct sna, kgem))) { + if (sna_mode_disable(__to_sna(kgem))) { kgem_cleanup_cache(kgem); ret = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, execbuf); DBG(("%s: last_gasp ret=%d\n", __FUNCTION__, ret)); - sna_mode_enable(container_of(kgem, struct sna, kgem)); + sna_mode_enable(__to_sna(kgem)); } return ret; @@ -3945,49 +4005,14 @@ void _kgem_submit(struct kgem *kgem) assert(kgem->next_request != NULL); } -static bool find_hang_state(struct kgem *kgem, char *path, int maxlen) -{ - int minor = kgem_get_minor(kgem); - - /* Search for our hang state in a few canonical locations. - * In the unlikely event of having multiple devices, we - * will need to check which minor actually corresponds to ours. - */ - - snprintf(path, maxlen, "/sys/class/drm/card%d/error", minor); - if (access(path, R_OK) == 0) - return true; - - snprintf(path, maxlen, "/sys/kernel/debug/dri/%d/i915_error_state", minor); - if (access(path, R_OK) == 0) - return true; - - snprintf(path, maxlen, "/debug/dri/%d/i915_error_state", minor); - if (access(path, R_OK) == 0) - return true; - - path[0] = '\0'; - return false; -} - void kgem_throttle(struct kgem *kgem) { if (kgem->wedged) return; if (__kgem_throttle(kgem, true)) { - static int once; - char path[128]; - xf86DrvMsg(kgem_get_screen_index(kgem), X_ERROR, "Detected a hung GPU, disabling acceleration.\n"); - if (!once && find_hang_state(kgem, path, sizeof(path))) { - xf86DrvMsg(kgem_get_screen_index(kgem), X_ERROR, - "When reporting this, please include %s and the full dmesg.\n", - path); - once = 1; - } - __kgem_set_wedged(kgem); kgem->need_throttle = false; } @@ -4084,7 +4109,7 @@ bool kgem_expire_cache(struct kgem *kgem) } kgem_clean_large_cache(kgem); - if (container_of(kgem, struct sna, kgem)->scrn->vtSema) + if (__to_sna(kgem)->scrn->vtSema) kgem_clean_scanout_cache(kgem); expire = 0; @@ -4969,8 +4994,7 @@ static void __kgem_bo_make_scanout(struct kgem *kgem, struct kgem_bo *bo, int width, int height) { - ScrnInfoPtr scrn = - container_of(kgem, struct sna, kgem)->scrn; + ScrnInfoPtr scrn = __to_sna(kgem)->scrn; struct drm_mode_fb_cmd arg; assert(bo->proxy == NULL); @@ -5101,8 +5125,8 @@ struct kgem_bo *kgem_create_2d(struct kgem *kgem, return last; } - if (container_of(kgem, struct sna, kgem)->scrn->vtSema) { - ScrnInfoPtr scrn = container_of(kgem, struct sna, kgem)->scrn; + if (__to_sna(kgem)->scrn->vtSema) { + ScrnInfoPtr scrn = __to_sna(kgem)->scrn; list_for_each_entry_reverse(bo, &kgem->scanout, list) { struct drm_mode_fb_cmd arg; @@ -5932,7 +5956,7 @@ static inline bool kgem_flush(struct kgem *kgem, bool flush) if (kgem->nreloc == 0) return true; - if (container_of(kgem, struct sna, kgem)->flags & SNA_POWERSAVE) + if (__to_sna(kgem)->flags & SNA_POWERSAVE) return true; if (kgem->flush == flush && kgem->aperture < kgem->aperture_low) From 6d64063750535f1c2b94e075d1d525ed289821aa Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 17 May 2015 21:36:50 +0100 Subject: [PATCH 38/61] sna: Markup a couple more potential mmap() accesses All pointer access into a mmap() arena should be wrapped by sigtrap, in case the kernel generates a SIGBUS (oom, eio, bugs, etc). Add a couple more missing annotations. Signed-off-by: Chris Wilson --- src/sna/sna_accel.c | 116 ++++++++++++++++++++++++-------------------- 1 file changed, 63 insertions(+), 53 deletions(-) diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c index 7cd9a0c4..af98301e 100644 --- a/src/sna/sna_accel.c +++ b/src/sna/sna_accel.c @@ -2933,18 +2933,22 @@ move_to_cpu: assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu)); } - assert(pixmap->devKind); - sigtrap_assert_active(); - do { - pixman_fill(pixmap->devPrivate.ptr, - pixmap->devKind/sizeof(uint32_t), - pixmap->drawable.bitsPerPixel, - box->x1, box->y1, - box->x2 - box->x1, - box->y2 - box->y1, - priv->clear_color); - box++; - } while (--n); + if (sigtrap_get() == 0) { + assert(pixmap->devKind); + sigtrap_assert_active(); + do { + pixman_fill(pixmap->devPrivate.ptr, + pixmap->devKind/sizeof(uint32_t), + pixmap->drawable.bitsPerPixel, + box->x1, box->y1, + box->x2 - box->x1, + box->y2 - box->y1, + priv->clear_color); + box++; + } while (--n); + sigtrap_put(); + } else + return false; clear_done: if (flags & MOVE_WRITE || @@ -6873,19 +6877,22 @@ fallback: return; } - assert(dst_pixmap->devPrivate.ptr); - assert(dst_pixmap->devKind); - sigtrap_assert_active(); - do { - pixman_fill(dst_pixmap->devPrivate.ptr, - dst_pixmap->devKind/sizeof(uint32_t), - dst_pixmap->drawable.bitsPerPixel, - box->x1, box->y1, - box->x2 - box->x1, - box->y2 - box->y1, - src_priv->clear_color); - box++; - } while (--n); + if (sigtrap_get() == 0) { + assert(dst_pixmap->devPrivate.ptr); + assert(dst_pixmap->devKind); + sigtrap_assert_active(); + do { + pixman_fill(dst_pixmap->devPrivate.ptr, + dst_pixmap->devKind/sizeof(uint32_t), + dst_pixmap->drawable.bitsPerPixel, + box->x1, box->y1, + box->x2 - box->x1, + box->y2 - box->y1, + src_priv->clear_color); + box++; + } while (--n); + sigtrap_put(); + } } else if (!sna_copy_boxes__inplace(sna, region, alu, src_pixmap, src_priv, src_dx, src_dy, @@ -6942,36 +6949,39 @@ fallback: ((char *)src_pixmap->devPrivate.ptr + src_dy * src_stride + src_dx * bpp / 8); - do { - DBG(("%s: memcpy_blt(box=(%d, %d), (%d, %d), src=(%d, %d), pitches=(%d, %d))\n", - __FUNCTION__, - box->x1, box->y1, - box->x2 - box->x1, - box->y2 - box->y1, - src_dx, src_dy, - src_stride, dst_stride)); + if (sigtrap_get() == 0) { + do { + DBG(("%s: memcpy_blt(box=(%d, %d), (%d, %d), src=(%d, %d), pitches=(%d, %d))\n", + __FUNCTION__, + box->x1, box->y1, + box->x2 - box->x1, + box->y2 - box->y1, + src_dx, src_dy, + src_stride, dst_stride)); - assert(box->x1 >= 0); - assert(box->y1 >= 0); - assert(box->x2 <= dst_pixmap->drawable.width); - assert(box->y2 <= dst_pixmap->drawable.height); + assert(box->x1 >= 0); + assert(box->y1 >= 0); + assert(box->x2 <= dst_pixmap->drawable.width); + assert(box->y2 <= dst_pixmap->drawable.height); - assert(box->x1 + src_dx >= 0); - assert(box->y1 + src_dy >= 0); - assert(box->x2 + src_dx <= src_pixmap->drawable.width); - assert(box->y2 + src_dy <= src_pixmap->drawable.height); - assert(has_coherent_ptr(sna, src_priv, MOVE_READ)); - assert(has_coherent_ptr(sna, dst_priv, MOVE_WRITE)); - assert(src_stride); - assert(dst_stride); - memcpy_blt(src_bits, dst_bits, bpp, - src_stride, dst_stride, - box->x1, box->y1, - box->x1, box->y1, - box->x2 - box->x1, - box->y2 - box->y1); - box++; - } while (--n); + assert(box->x1 + src_dx >= 0); + assert(box->y1 + src_dy >= 0); + assert(box->x2 + src_dx <= src_pixmap->drawable.width); + assert(box->y2 + src_dy <= src_pixmap->drawable.height); + assert(has_coherent_ptr(sna, src_priv, MOVE_READ)); + assert(has_coherent_ptr(sna, dst_priv, MOVE_WRITE)); + assert(src_stride); + assert(dst_stride); + memcpy_blt(src_bits, dst_bits, bpp, + src_stride, dst_stride, + box->x1, box->y1, + box->x1, box->y1, + box->x2 - box->x1, + box->y2 - box->y1); + box++; + } while (--n); + sigtrap_put(); + } } else { DBG(("%s: fallback -- miCopyRegion\n", __FUNCTION__)); From b10ef9cf5c9cc844f432e9024deeb78fa1034a8e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 17 May 2015 20:45:25 +0100 Subject: [PATCH 39/61] sna/glyphs: Improve handling of low bitdepth mask format conversions We shouldn't just discard the mask if the user requests that we render the glyphs through a low bitdepth mask - and in doing so we should also be careful not to improve the bitdepth of that mask (since we don't take into account the extra quantisation desired). Testcase: render-glyphs Signed-off-by: Chris Wilson --- src/sna/sna_accel.c | 6 +- src/sna/sna_glyphs.c | 91 +++++---- src/sna/sna_render.c | 2 +- test/.gitignore | 1 + test/Makefile.am | 1 + test/render-glyphs.c | 441 +++++++++++++++++++++++++++++++++++++++++++ test/test.h | 9 + 7 files changed, 515 insertions(+), 36 deletions(-) create mode 100644 test/render-glyphs.c diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c index af98301e..c79af6ac 100644 --- a/src/sna/sna_accel.c +++ b/src/sna/sna_accel.c @@ -817,8 +817,8 @@ create_pixmap(struct sna *sna, ScreenPtr screen, datasize += adjust; } - DBG(("%s: allocating pixmap %dx%d, depth=%d, size=%ld\n", - __FUNCTION__, width, height, depth, (long)datasize)); + DBG(("%s: allocating pixmap %dx%d, depth=%d/%d, size=%ld\n", + __FUNCTION__, width, height, depth, bpp, (long)datasize)); pixmap = AllocatePixmap(screen, datasize); if (!pixmap) return NullPixmap; @@ -4091,7 +4091,7 @@ sna_pixmap_create_upload(ScreenPtr screen, assert(width); assert(height); - if (depth == 1) + if (depth < 8) return create_pixmap(sna, screen, width, height, depth, CREATE_PIXMAP_USAGE_SCRATCH); diff --git a/src/sna/sna_glyphs.c b/src/sna/sna_glyphs.c index 6d57e8fd..9e945f01 100644 --- a/src/sna/sna_glyphs.c +++ b/src/sna/sna_glyphs.c @@ -74,7 +74,7 @@ #define NO_GLYPHS_VIA_MASK 0 #define FORCE_SMALL_MASK 0 /* -1 = never, 1 = always */ #define NO_GLYPHS_SLOW 0 -#define NO_DISCARD_MASK 0 +#define DISCARD_MASK 0 /* -1 = never, 1 = always */ #define CACHE_PICTURE_SIZE 1024 #define GLYPH_MIN_SIZE 8 @@ -1094,6 +1094,9 @@ sna_glyph_get_image(GlyphPtr g, ScreenPtr s) static inline bool use_small_mask(struct sna *sna, int16_t width, int16_t height, int depth) { + if (depth < 8) + return true; + if (FORCE_SMALL_MASK) return FORCE_SMALL_MASK > 0; @@ -1156,12 +1159,6 @@ glyphs_via_mask(struct sna *sna, src_x += box.x1 - list->xOff; src_y += box.y1 - list->yOff; - if (format->depth < 8) { - format = PictureMatchFormat(screen, 8, PICT_a8); - if (!format) - return false; - } - component_alpha = NeedsComponent(format->format); if (use_small_mask(sna, width, height, format->depth)) { pixman_image_t *mask_image; @@ -1179,7 +1176,7 @@ use_small_mask: return false; mask_image = - pixman_image_create_bits(format->depth << 24 | format->format, + pixman_image_create_bits(pixmap->drawable.bitsPerPixel << 24 | format->format, width, height, pixmap->devPrivate.ptr, pixmap->devKind); @@ -1386,10 +1383,11 @@ next_image: DBG(("%s: atlas format=%08x, mask format=%08x\n", __FUNCTION__, (int)p->atlas->format, - (int)(format->depth << 24 | format->format))); + (int)mask->format)); memset(&tmp, 0, sizeof(tmp)); - if (p->atlas->format == (format->depth << 24 | format->format)) { + if (p->atlas->format == mask->format || + alphaless(p->atlas->format) == mask->format) { ok = sna->render.composite(sna, PictOpAdd, p->atlas, NULL, mask, 0, 0, 0, 0, 0, 0, @@ -1564,6 +1562,8 @@ skip_glyph: out: if (list_extents != stack_extents) free(list_extents); + DBG(("%s: format=%08d, depth=%d\n", + __FUNCTION__, format->format, format->depth)); return format; } @@ -1573,24 +1573,34 @@ static bool can_discard_mask(uint8_t op, PicturePtr src, PictFormatPtr mask, PictFormatPtr g; uint32_t color; - if (NO_DISCARD_MASK) - return false; + if (DISCARD_MASK) + return DISCARD_MASK > 0; DBG(("%s: nlist=%d, mask=%08x, depth %d, op=%d (bounded? %d)\n", __FUNCTION__, nlist, mask ? (unsigned)mask->format : 0, mask ? mask->depth : 0, op, op_is_bounded(op))); - if (nlist == 1 && list->len == 1) - return true; + if (nlist == 1 && list->len == 1) { + if (mask == list->format) + return true; - if (!op_is_bounded(op)) + g = list->format; + goto skip; + } + + if (!op_is_bounded(op)) { + DBG(("%s: unbounded op, not discarding\n", __FUNCTION__)); return false; + } /* No glyphs overlap and we are not performing a mask conversion. */ g = glyphs_format(nlist, list, glyphs); - if (mask == g) + if (mask == g) { + DBG(("%s: mask matches glyphs format, no conversion, so discard mask\n", + __FUNCTION__)); return true; + } DBG(("%s: preferred mask format %08x, depth %d\n", __FUNCTION__, g ? (unsigned)g->format : 0, g ? g->depth : 0)); @@ -1605,18 +1615,41 @@ static bool can_discard_mask(uint8_t op, PicturePtr src, PictFormatPtr mask, list++; } + + if (!sna_picture_is_solid(src, &color)) + return false; + + return color >> 24 == 0xff; } else { - if (PICT_FORMAT_A(mask->format) >= PICT_FORMAT_A(g->format)) +skip: + if (mask->format == g->format) return true; - if (g->depth != 1) - return false; - } + if (mask->format == alphaless(g->format)) + return true; + + if (PICT_FORMAT_TYPE(g->format) == PICT_TYPE_A && + PICT_FORMAT_TYPE(mask->format) != PICT_TYPE_A) + return true; - if (!sna_picture_is_solid(src, &color)) return false; + } +} - return color >> 24 == 0xff; +static uint32_t pixman_format(PictFormatPtr short_format) +{ + uint32_t bpp; + + bpp = short_format->depth; + if (bpp <= 1) + bpp = 1; + else if (bpp <= 8) + bpp = 8; + else if (bpp <= 16) + bpp = 16; + else + bpp = 32; + return bpp << 24 | short_format->format; } static void @@ -1756,7 +1789,7 @@ next: if (sigtrap_get() == 0) { if (mask_format) { pixman_composite_glyphs(op, src_image, dst_image, - mask_format->format | (mask_format->depth << 24), + pixman_format(mask_format), src_x + src_dx + region.extents.x1 - dst_x, src_y + src_dy + region.extents.y1 - dst_y, region.extents.x1, region.extents.y1, @@ -1815,10 +1848,10 @@ out: x, y, mask_format->depth, (long)mask_format->format, - (long)(mask_format->depth << 24 | mask_format->format), + (long)pixman_format(mask_format), NeedsComponent(mask_format->format))); mask_image = - pixman_image_create_bits(mask_format->depth << 24 | mask_format->format, + pixman_image_create_bits(pixman_format(mask_format), region.extents.x2 - region.extents.x1, region.extents.y2 - region.extents.y1, NULL, 0); @@ -2086,12 +2119,6 @@ glyphs_via_image(struct sna *sna, src_x += box.x1 - list->xOff; src_y += box.y1 - list->yOff; - if (format->depth < 8) { - format = PictureMatchFormat(screen, 8, PICT_a8); - if (!format) - return false; - } - DBG(("%s: small mask [format=%lx, depth=%d, size=%d], rendering glyphs to upload buffer\n", __FUNCTION__, (unsigned long)format->format, format->depth, (uint32_t)width*height*format->depth)); @@ -2104,7 +2131,7 @@ glyphs_via_image(struct sna *sna, return false; mask_image = - pixman_image_create_bits(format->depth << 24 | format->format, + pixman_image_create_bits(pixmap->drawable.bitsPerPixel << 24 | format->format, width, height, pixmap->devPrivate.ptr, pixmap->devKind); diff --git a/src/sna/sna_render.c b/src/sna/sna_render.c index 8a9c7f4c..d95536ec 100644 --- a/src/sna/sna_render.c +++ b/src/sna/sna_render.c @@ -54,7 +54,7 @@ sna_format_for_depth(int depth) { switch (depth) { case 1: return PICT_a1; - case 4: return PICT_a4; + case 4: return PICT_x4a4; case 8: return PICT_a8; case 15: return PICT_x1r5g5b5; case 16: return PICT_r5g6b5; diff --git a/test/.gitignore b/test/.gitignore index da174be8..373ba15e 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -18,6 +18,7 @@ render-copyarea render-copyarea-mask render-copyarea-size render-copy-alphaless +render-glyphs mixed-stress lowlevel-blt-bench vsync.avi diff --git a/test/Makefile.am b/test/Makefile.am index 9b372228..aaa656af 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -12,6 +12,7 @@ stress_TESTS = \ DrawSegments \ cursor-test \ render-fill \ + render-glyphs \ render-trapezoid \ render-trapezoid-image \ render-fill-copy \ diff --git a/test/render-glyphs.c b/test/render-glyphs.c new file mode 100644 index 00000000..8822e36a --- /dev/null +++ b/test/render-glyphs.c @@ -0,0 +1,441 @@ +#include +#include +#include +#include +#include +#include + +#include /* for XDestroyImage */ +#include /* for pixman blt functions */ + +#include "test.h" + +static const XRenderColor colors[] = { + /* red, green, blue, alpha */ + { 0 }, + { 0, 0, 0, 0xffff }, + { 0xffff, 0, 0, 0xffff }, + { 0, 0xffff, 0, 0xffff }, + { 0, 0, 0xffff, 0xffff }, + { 0xffff, 0xffff, 0xffff, 0xffff }, +}; + +static struct clip { + void *func; +} clips[] = { + { NULL }, +}; + +static int _x_error_occurred; + +static int +_check_error_handler(Display *display, + XErrorEvent *event) +{ + _x_error_occurred = 1; + return False; /* ignored */ +} + +static void clear(struct test_display *dpy, + struct test_target *tt, + const XRenderColor *c) +{ + XRenderFillRectangle(dpy->dpy, PictOpClear, tt->picture, c, + 0, 0, tt->width, tt->height); +} + +static bool check_op(struct test_display *dpy, int op, struct test_target *tt) +{ + XRenderColor render_color = {0}; + + XSync(dpy->dpy, True); + _x_error_occurred = 0; + + XRenderFillRectangle(dpy->dpy, op, + tt->picture, &render_color, + 0, 0, 0, 0); + + XSync(dpy->dpy, True); + return _x_error_occurred == 0; +} + +struct glyph_iter { + enum { + GLYPHS, OP, DST, SRC, MASK, CLIP, + } stage; + + int glyph_format; + int op; + int dst_color; + int src_color; + int mask_format; + int clip; + + struct { + struct test_display *dpy; + struct test_target tt; + GlyphSet glyphset; + Picture src; + XRenderPictFormat *mask_format; + } ref, out; +}; + +static void glyph_iter_init(struct glyph_iter *gi, + struct test *t, enum target target) +{ + memset(gi, 0, sizeof(*gi)); + + gi->out.dpy = &t->out; + test_target_create_render(&t->out, target, &gi->out.tt); + + gi->ref.dpy = &t->ref; + test_target_create_render(&t->ref, target, &gi->ref.tt); + + gi->stage = GLYPHS; + gi->glyph_format = -1; + gi->op = -1; + gi->dst_color = -1; + gi->src_color = -1; + gi->mask_format = -1; + gi->clip = -1; +} + +static void render_clear(char *image, int image_size, int bpp) +{ + memset(image, 0, image_size); +} + +static void render_black(char *image, int image_size, int bpp) +{ + if (bpp == 4) { + uint32_t *p = (uint32_t *)image; + image_size /= 4; + while (image_size--) + *p++ = 0x000000ff; + } else + memset(image, 0x55, image_size); +} + +static void render_green(char *image, int image_size, int bpp) +{ + if (bpp == 4) { + uint32_t *p = (uint32_t *)image; + image_size /= 4; + while (image_size--) + *p++ = 0xffff0000; + } else + memset(image, 0xaa, image_size); +} + +static void render_white(char *image, int image_size, int bpp) +{ + memset(image, 0xff, image_size); +} + +static GlyphSet create_glyphs(Display *dpy, int format_id) +{ +#define N_GLYPHS 4 + XRenderPictFormat *format; + XGlyphInfo glyph = { 8, 8, 0, 0, 8, 0 }; + char image[4*8*8]; + GlyphSet glyphset; + Glyph gid; + int image_size; + int bpp; + int n; + + format = XRenderFindStandardFormat(dpy, format_id); + if (format == NULL) + return 0; + + switch (format_id) { + case PictStandardARGB32: + case PictStandardRGB24: + image_size = 4 * 8 * 8; + bpp = 4; + break; + case PictStandardA8: + case PictStandardA4: + image_size = 8 * 8; + bpp = 1; + break; + case PictStandardA1: + image_size = 8; + bpp = 0; + break; + default: + return 0; + } + + glyphset = XRenderCreateGlyphSet(dpy, format); + for (n = 0; n < N_GLYPHS; n++) { + gid = n; + + switch (n) { + case 0: render_clear(image, image_size, bpp); break; + case 1: render_black(image, image_size, bpp); break; + case 2: render_green(image, image_size, bpp); break; + case 3: render_white(image, image_size, bpp); break; + } + + XRenderAddGlyphs(dpy, glyphset, + &gid, &glyph, 1, image, image_size); + } + + return glyphset; +} + +static const char *glyph_name(int n) +{ + switch (n) { + case 0: return "clear"; + case 1: return "black"; + case 2: return "green"; + case 3: return "white"; + default: return "unknown"; + } +} + +static bool glyph_iter_next(struct glyph_iter *gi) +{ +restart: + if (gi->stage == GLYPHS) { + if (++gi->glyph_format == PictStandardNUM) + return false; + + if (gi->out.glyphset) + XRenderFreeGlyphSet(gi->out.dpy->dpy, + gi->out.glyphset); + gi->out.glyphset = create_glyphs(gi->out.dpy->dpy, + gi->glyph_format); + + if (gi->ref.glyphset) + XRenderFreeGlyphSet(gi->ref.dpy->dpy, + gi->ref.glyphset); + gi->ref.glyphset = create_glyphs(gi->ref.dpy->dpy, + gi->glyph_format); + + gi->stage++; + } + + if (gi->stage == OP) { + do { + if (++gi->op == 255) + goto reset_op; + } while (!check_op(gi->out.dpy, gi->op, &gi->out.tt) || + !check_op(gi->ref.dpy, gi->op, &gi->ref.tt)); + + gi->stage++; + } + + if (gi->stage == DST) { + if (++gi->dst_color == ARRAY_SIZE(colors)) + goto reset_dst; + + gi->stage++; + } + + if (gi->stage == SRC) { + if (++gi->src_color == ARRAY_SIZE(colors)) + goto reset_src; + + if (gi->ref.src) + XRenderFreePicture(gi->ref.dpy->dpy, gi->ref.src); + gi->ref.src = XRenderCreateSolidFill(gi->ref.dpy->dpy, + &colors[gi->src_color]); + + if (gi->out.src) + XRenderFreePicture(gi->out.dpy->dpy, gi->out.src); + gi->out.src = XRenderCreateSolidFill(gi->out.dpy->dpy, + &colors[gi->src_color]); + + gi->stage++; + } + + if (gi->stage == MASK) { + if (++gi->mask_format > PictStandardNUM) + goto reset_mask; + + if (gi->mask_format == PictStandardRGB24) + gi->mask_format++; + + if (gi->mask_format < PictStandardNUM) { + gi->out.mask_format = XRenderFindStandardFormat(gi->out.dpy->dpy, + gi->mask_format); + gi->ref.mask_format = XRenderFindStandardFormat(gi->ref.dpy->dpy, + gi->mask_format); + } else { + gi->out.mask_format = NULL; + gi->ref.mask_format = NULL; + } + + gi->stage++; + } + + if (gi->stage == CLIP) { + if (++gi->clip == ARRAY_SIZE(clips)) + goto reset_clip; + + gi->stage++; + } + + gi->stage--; + return true; + +reset_op: + gi->op = -1; +reset_dst: + gi->dst_color = -1; +reset_src: + gi->src_color = -1; +reset_mask: + gi->mask_format = -1; +reset_clip: + gi->clip = -1; + gi->stage--; + goto restart; +} + +static void glyph_iter_fini(struct glyph_iter *gi) +{ + if (gi->out.glyphset) + XRenderFreeGlyphSet (gi->out.dpy->dpy, gi->out.glyphset); + if (gi->ref.glyphset) + XRenderFreeGlyphSet (gi->ref.dpy->dpy, gi->ref.glyphset); + + test_target_destroy_render(gi->out.dpy, &gi->out.tt); + test_target_destroy_render(gi->ref.dpy, &gi->ref.tt); +} + +static const char *stdformat_to_str(int id) +{ + switch (id) { + case PictStandardARGB32: return "ARGB32"; + case PictStandardRGB24: return "RGB24"; + case PictStandardA8: return "A8"; + case PictStandardA4: return "A4"; + case PictStandardA1: return "A1"; + default: return "none"; + } +} + +static char *glyph_iter_to_string(struct glyph_iter *gi, + const char *format, + ...) +{ + static char buf[100]; + va_list ap; + int len; + + len = sprintf(buf, "glyphs=%s, op=%d, dst=%08x, src=%08x, mask=%s", + stdformat_to_str(gi->glyph_format), gi->op, + xrender_color(&colors[gi->dst_color]), + xrender_color(&colors[gi->src_color]), + stdformat_to_str(gi->mask_format)); + + if (format) { + buf[len++] = ' '; + va_start(ap, format); + vsprintf(buf+len, format, ap); + va_end(ap); + } + + return buf; +} + +static void single(struct test *t, enum target target) +{ + struct glyph_iter gi; + int n; + + printf("Testing single glyph (%s): ", test_target_name(target)); + fflush(stdout); + + glyph_iter_init(&gi, t, target); + while (glyph_iter_next(&gi)) { + XGlyphElt8 elt; + char id[N_GLYPHS]; + + for (n = 0; n < N_GLYPHS; n++) { + id[n] = n; + + elt.chars = &id[n]; + elt.nchars = 1; + elt.xOff = 0; + elt.yOff = 0; + + clear(gi.out.dpy, &gi.out.tt, &colors[gi.dst_color]); + elt.glyphset = gi.out.glyphset; + XRenderCompositeText8 (gi.out.dpy->dpy, gi.op, + gi.out.src, + gi.out.tt.picture, + gi.out.mask_format, + 0, 0, + 0, 8, + &elt, 1); + + clear(gi.ref.dpy, &gi.ref.tt, &colors[gi.dst_color]); + elt.glyphset = gi.ref.glyphset; + XRenderCompositeText8 (gi.ref.dpy->dpy, gi.op, + gi.ref.src, + gi.ref.tt.picture, + gi.ref.mask_format, + 0, 0, + 0, 8, + &elt, 1); + test_compare(t, + gi.out.tt.draw, gi.out.tt.format, + gi.ref.tt.draw, gi.ref.tt.format, + 0, 0, gi.out.tt.width, gi.out.tt.height, + glyph_iter_to_string(&gi, + "glyph=%s", + glyph_name(n))); + } + + elt.chars = &id[0]; + elt.nchars = n; + clear(gi.out.dpy, &gi.out.tt, &colors[gi.dst_color]); + elt.glyphset = gi.out.glyphset; + XRenderCompositeText8 (gi.out.dpy->dpy, gi.op, + gi.out.src, + gi.out.tt.picture, + gi.out.mask_format, + 0, 0, + 0, 8, + &elt, 1); + + clear(gi.ref.dpy, &gi.ref.tt, &colors[gi.dst_color]); + elt.glyphset = gi.ref.glyphset; + XRenderCompositeText8 (gi.ref.dpy->dpy, gi.op, + gi.ref.src, + gi.ref.tt.picture, + gi.ref.mask_format, + 0, 0, + 0, 8, + &elt, 1); + test_compare(t, + gi.out.tt.draw, gi.out.tt.format, + gi.ref.tt.draw, gi.ref.tt.format, + 0, 0, gi.out.tt.width, gi.out.tt.height, + glyph_iter_to_string(&gi, "all")); + } + glyph_iter_fini(&gi); +} + +int main(int argc, char **argv) +{ + struct test test; + int t; + + test_init(&test, argc, argv); + XSetErrorHandler(_check_error_handler); + + for (t = TARGET_FIRST; t <= TARGET_LAST; t++) { + single(&test, t); + //overlapping(&test, t); + //gap(&test, t); + //mixed(&test, t); + } + + return 0; +} diff --git a/test/test.h b/test/test.h index a3ef979d..9eec1cf9 100644 --- a/test/test.h +++ b/test/test.h @@ -107,6 +107,15 @@ static inline uint32_t color(uint8_t red, uint8_t green, uint8_t blue, uint8_t a return alpha << 24 | ra >> 8 << 16 | ga >> 8 << 8 | ba >> 8; } +static inline uint32_t xrender_color(const XRenderColor *c) +{ + uint32_t ra = c->red * c->alpha; + uint32_t ga = c->green * c->alpha; + uint32_t ba = c->blue * c->alpha; + + return c->alpha >> 8 << 24 | ra >> 24 << 16 | ga >> 24 << 8 | ba >> 24; +} + void test_timer_start(struct test_display *t, struct timespec *tv); double test_timer_stop(struct test_display *t, struct timespec *tv); From d4c82a16bc3ad89a9684c82cd1dd4bcef117ed8c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 18 May 2015 09:16:12 +0100 Subject: [PATCH 40/61] test: Remove the blit through a temporary Pixmap Originally this was inplace so that we wouldn't simply migrate the target away from the GPU whenever we inspected results. That is no longer a problem and so we can speed up the tests by skipping the temporary. Signed-off-by: Chris Wilson --- test/test_image.c | 36 ++++++++++-------------------------- 1 file changed, 10 insertions(+), 26 deletions(-) diff --git a/test/test_image.c b/test/test_image.c index d15a8af8..1c076990 100644 --- a/test/test_image.c +++ b/test/test_image.c @@ -197,13 +197,10 @@ void test_compare(struct test *t, const char *info) { XImage out_image, ref_image; - Pixmap tmp; - char *out, *ref; + uint32_t *out, *ref; char buf[600]; uint32_t mask; int i, j; - XGCValues gcv; - GC gc; if (w * h * 4 > t->out.max_shm_size) return test_compare_fallback(t, @@ -214,37 +211,24 @@ void test_compare(struct test *t, test_init_image(&out_image, &t->out.shm, out_format, w, h); test_init_image(&ref_image, &t->ref.shm, ref_format, w, h); - gcv.graphics_exposures = 0; - die_unless(out_image.depth == ref_image.depth); die_unless(out_image.bits_per_pixel == ref_image.bits_per_pixel); die_unless(out_image.bits_per_pixel == 32); - mask = depth_mask(out_image.depth); + XShmGetImage(t->out.dpy, out_draw, &out_image, x, y, AllPlanes); + out = (uint32_t *)out_image.data; - tmp = XCreatePixmap(t->out.dpy, out_draw, w, h, out_image.depth); - gc = XCreateGC(t->out.dpy, tmp, GCGraphicsExposures, &gcv); - XCopyArea(t->out.dpy, out_draw, tmp, gc, x, y, w, h, 0, 0); - XShmGetImage(t->out.dpy, tmp, &out_image, 0, 0, AllPlanes); - XFreeGC(t->out.dpy, gc); - XFreePixmap(t->out.dpy, tmp); - out = out_image.data; - - tmp = XCreatePixmap(t->ref.dpy, ref_draw, w, h, ref_image.depth); - gc = XCreateGC(t->ref.dpy, tmp, GCGraphicsExposures, &gcv); - XCopyArea(t->ref.dpy, ref_draw, tmp, gc, x, y, w, h, 0, 0); - XShmGetImage(t->ref.dpy, tmp, &ref_image, 0, 0, AllPlanes); - XFreeGC(t->ref.dpy, gc); - XFreePixmap(t->ref.dpy, tmp); - ref = ref_image.data; + XShmGetImage(t->ref.dpy, ref_draw, &ref_image, x, y, AllPlanes); + ref = (uint32_t *)ref_image.data; /* Start with an exact comparison. However, one quicky desires * a fuzzy comparator to hide hardware inaccuracies... */ + mask = depth_mask(out_image.depth); for (j = 0; j < h; j++) { for (i = 0; i < w; i++) { - uint32_t a = ((uint32_t *)out)[i] & mask; - uint32_t b = ((uint32_t *)ref)[i] & mask; + uint32_t a = out[i] & mask; + uint32_t b = ref[i] & mask; if (a != b && pixel_difference(a, b) > MAX_DELTA) { show_pixels(buf, &out_image, &ref_image, @@ -255,8 +239,8 @@ void test_compare(struct test *t, x,i, y,j, a, b, pixel_difference(a, b), buf, info); } } - out += out_image.bytes_per_line; - ref += ref_image.bytes_per_line; + out = (uint32_t *)((char *)out + out_image.bytes_per_line); + ref = (uint32_t *)((char *)ref + ref_image.bytes_per_line); } } From fe64672c83e75ccb3f7a1bf37e05df05d0c05392 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 18 May 2015 09:18:41 +0100 Subject: [PATCH 41/61] sna: Wrap GetImage with sigtrap Mostly for completeness, though it is still remotely possibly for the dst pointer to raise a SIGBUS (just less likely since it is not a i915 bo). Signed-off-by: Chris Wilson --- src/sna/sna_accel.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c index c79af6ac..9a5079f8 100644 --- a/src/sna/sna_accel.c +++ b/src/sna/sna_accel.c @@ -17072,7 +17072,7 @@ sna_get_image__fast(PixmapPtr pixmap, if (priv == NULL || priv->gpu_damage == NULL) return false; - if (priv->clear) { + if (priv->clear && sigtrap_get() == 0) { int w = region->extents.x2 - region->extents.x1; int h = region->extents.y2 - region->extents.y1; int pitch = PixmapBytePad(w, pixmap->drawable.depth); @@ -17098,6 +17098,7 @@ sna_get_image__fast(PixmapPtr pixmap, priv->clear_color); } + sigtrap_put(); return true; } From 3852977f14a00db770df7efab79207116aaecbf0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 18 May 2015 09:58:08 +0100 Subject: [PATCH 42/61] test: Add a fidelity test for triangle edge rendering Signed-off-by: Chris Wilson --- src/sna/sna_trapezoids_imprecise.c | 3 +- src/sna/sna_trapezoids_mono.c | 50 ++++++-- src/sna/sna_trapezoids_precise.c | 3 +- test/.gitignore | 1 + test/Makefile.am | 1 + test/render-triangle.c | 180 +++++++++++++++++++++++++++++ 6 files changed, 222 insertions(+), 16 deletions(-) create mode 100644 test/render-triangle.c diff --git a/src/sna/sna_trapezoids_imprecise.c b/src/sna/sna_trapezoids_imprecise.c index 4e90f9c4..8bc7c8a8 100644 --- a/src/sna/sna_trapezoids_imprecise.c +++ b/src/sna/sna_trapezoids_imprecise.c @@ -1707,8 +1707,7 @@ static void span_thread_add_box(struct sna *sna, void *data, { struct span_thread_boxes *b = data; - __DBG(("%s: adding %d boxes with alpha=%f\n", - __FUNCTION__, count, alpha)); + __DBG(("%s: adding box with alpha=%f\n", __FUNCTION__, alpha)); if (unlikely(b->num_boxes == SPAN_THREAD_MAX_BOXES)) { DBG(("%s: flushing %d boxes\n", __FUNCTION__, b->num_boxes)); diff --git a/src/sna/sna_trapezoids_mono.c b/src/sna/sna_trapezoids_mono.c index 5b65fa45..07a7867d 100644 --- a/src/sna/sna_trapezoids_mono.c +++ b/src/sna/sna_trapezoids_mono.c @@ -79,7 +79,7 @@ struct mono { struct mono_polygon polygon; }; -#define I(x) pixman_fixed_to_int ((x) + pixman_fixed_1_minus_e/2) +#define I(x) pixman_fixed_to_int((x) + pixman_fixed_1_minus_e/2) static struct quorem floored_muldivrem(int32_t x, int32_t a, int32_t b) @@ -250,22 +250,22 @@ mono_add_line(struct mono *mono, e->dxdy = floored_muldivrem(dx, pixman_fixed_1, dy); - e->x = floored_muldivrem((ytop - dst_y) * pixman_fixed_1 + pixman_fixed_1_minus_e/2 - p1->y, + e->x = floored_muldivrem((ytop - dst_y) * pixman_fixed_1 + pixman_fixed_1/2 - p1->y, dx, dy); e->x.quo += p1->x; e->x.rem -= dy; e->dy = dy; - - __DBG(("%s: initial x=%d [%d.%d/%d] + dxdy=%d.%d/%d\n", - __FUNCTION__, - I(e->x.quo), e->x.quo, e->x.rem, e->dy, - e->dxdy.quo, e->dxdy.rem, e->dy)); } e->x.quo += dst_x*pixman_fixed_1; + __DBG(("%s: initial x=%d [%d.%d/%d] + dxdy=%d.%d/%d\n", + __FUNCTION__, + I(e->x.quo), e->x.quo, e->x.rem, e->dy, + e->dxdy.quo, e->dxdy.rem, e->dy)); { struct mono_edge **ptail = &polygon->y_buckets[ytop - mono->clip.extents.y1]; + assert(ytop - mono->clip.extents.y1 < mono->clip.extents.y2 - mono->clip.extents.y1); if (*ptail) (*ptail)->prev = e; e->next = *ptail; @@ -369,6 +369,10 @@ static struct mono_edge *mono_filter(struct mono_edge *edges) e->x.rem == n->x.rem && e->dxdy.quo == n->dxdy.quo && e->dxdy.rem == n->dxdy.rem) { + assert(e->dy == n->dy); + __DBG(("%s: discarding cancellation pair (%d.%d) + (%d.%d)\n", + __FUNCTION__, e->x.quo, e->x.rem, e->dxdy.quo, e->dxdy.rem)); + if (e->prev) e->prev->next = n->next; else @@ -379,8 +383,11 @@ static struct mono_edge *mono_filter(struct mono_edge *edges) break; e = n->next; - } else + } else { + __DBG(("%s: adding edge (%d.%d) + (%d.%d)/%d, height=%d\n", + __FUNCTION__, n->x.quo, n->x.rem, n->dxdy.quo, n->dxdy.rem, n->dy, n->height_left)); e = n; + } } return edges; @@ -571,6 +578,8 @@ mono_row(struct mono *c, int16_t y, int16_t h) int winding = 0; BoxRec box; + __DBG(("%s: y=%d, h=%d\n", __FUNCTION__, y, h)); + DBG_MONO_EDGES(edge); VALIDATE_MONO_EDGES(&c->head); @@ -581,6 +590,8 @@ mono_row(struct mono *c, int16_t y, int16_t h) struct mono_edge *next = edge->next; int16_t xend = I(edge->x.quo); + __DBG(("%s: adding edge dir=%d [winding=%d], x=%d [%d]\n", + __FUNCTION__, edge->dir, winding + edge->dir, xend, edge->x.quo)); if (--edge->height_left) { if (edge->dy) { edge->x.quo += edge->dxdy.quo; @@ -589,6 +600,8 @@ mono_row(struct mono *c, int16_t y, int16_t h) ++edge->x.quo; edge->x.rem -= edge->dy; } + __DBG(("%s: stepped edge (%d.%d) + (%d.%d)/%d, height=%d, prev_x=%d\n", + __FUNCTION__, edge->x.quo, edge->x.rem, edge->dxdy.quo, edge->dxdy.rem, edge->dy, edge->height_left, edge->x.quo)); } if (edge->x.quo < prev_x) { @@ -612,17 +625,22 @@ mono_row(struct mono *c, int16_t y, int16_t h) winding += edge->dir; if (winding == 0) { assert(I(next->x.quo) >= xend); - if (I(next->x.quo) > xend + 1) { + if (I(next->x.quo) > xend) { + __DBG(("%s: end span: %d\n", __FUNCTION__, xend)); if (xstart < c->clip.extents.x1) xstart = c->clip.extents.x1; if (xend > c->clip.extents.x2) xend = c->clip.extents.x2; - if (xend > xstart) + if (xend > xstart) { + __DBG(("%s: emit span [%d, %d]\n", __FUNCTION__, xstart, xend)); c->span(c, xstart, xend, &box); + } xstart = INT16_MIN; } - } else if (xstart == INT16_MIN) + } else if (xstart == INT16_MIN) { + __DBG(("%s: starting new span: %d\n", __FUNCTION__, xend)); xstart = xend; + } edge = next; } @@ -684,9 +702,14 @@ mono_render(struct mono *mono) for (i = 0; i < h; i = j) { j = i + 1; + __DBG(("%s: row=%d, new edges? %d\n", __FUNCTION__, + i, polygon->y_buckets[i] != NULL)); + if (polygon->y_buckets[i]) mono_merge_edges(mono, polygon->y_buckets[i]); + __DBG(("%s: row=%d, vertical? %d\n", __FUNCTION__, + i, mono->is_vertical)); if (mono->is_vertical) { struct mono_edge *e = mono->head.next; int min_height = h - i; @@ -701,6 +724,7 @@ mono_render(struct mono *mono) j++; if (j != i + 1) mono_step_edges(mono, j - (i + 1)); + __DBG(("%s: %d vertical rows\n", __FUNCTION__, j-i)); } mono_row(mono, i, j-i); @@ -1423,10 +1447,13 @@ mono_triangles_span_converter(struct sna *sna, mono_render(&mono); mono.op.done(mono.sna, &mono.op); } + mono_fini(&mono); if (!was_clear && !operator_is_bounded(op)) { xPointFixed p1, p2; + DBG(("%s: performing unbounded clear\n", __FUNCTION__)); + if (!mono_init(&mono, 2+3*count)) return false; @@ -1472,7 +1499,6 @@ mono_triangles_span_converter(struct sna *sna, mono_fini(&mono); } - mono_fini(&mono); REGION_UNINIT(NULL, &mono.clip); return true; } diff --git a/src/sna/sna_trapezoids_precise.c b/src/sna/sna_trapezoids_precise.c index c9838528..242b4acb 100644 --- a/src/sna/sna_trapezoids_precise.c +++ b/src/sna/sna_trapezoids_precise.c @@ -1655,8 +1655,7 @@ static void span_thread_add_box(struct sna *sna, void *data, { struct span_thread_boxes *b = data; - __DBG(("%s: adding %d boxes with alpha=%f\n", - __FUNCTION__, count, alpha)); + __DBG(("%s: adding box with alpha=%f\n", __FUNCTION__, alpha)); if (unlikely(b->num_boxes == SPAN_THREAD_MAX_BOXES)) { DBG(("%s: flushing %d boxes\n", __FUNCTION__, b->num_boxes)); diff --git a/test/.gitignore b/test/.gitignore index 373ba15e..2a68c3dc 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -11,6 +11,7 @@ cursor-test render-fill render-trapezoid render-trapezoid-image +render-triangle render-fill-copy render-composite-solid render-composite-solid-mask diff --git a/test/Makefile.am b/test/Makefile.am index aaa656af..50f2126a 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -15,6 +15,7 @@ stress_TESTS = \ render-glyphs \ render-trapezoid \ render-trapezoid-image \ + render-triangle \ render-fill-copy \ render-composite-solid \ render-composite-solid-mask \ diff --git a/test/render-triangle.c b/test/render-triangle.c new file mode 100644 index 00000000..165834ce --- /dev/null +++ b/test/render-triangle.c @@ -0,0 +1,180 @@ +#include +#include +#include + +#include "test.h" + +enum edge { + EDGE_SHARP = PolyEdgeSharp, + EDGE_SMOOTH, +}; + +static void set_edge(Display *dpy, Picture p, enum edge edge) +{ + XRenderPictureAttributes a; + + a.poly_edge = edge; + XRenderChangePicture(dpy, p, CPPolyEdge, &a); +} + +static XRenderPictFormat *mask_format(Display *dpy, enum mask mask) +{ + switch (mask) { + default: + case MASK_NONE: return NULL; + case MASK_A1: return XRenderFindStandardFormat(dpy, PictStandardA1); + case MASK_A8: return XRenderFindStandardFormat(dpy, PictStandardA8); + } +} + +static const char *mask_name(enum mask mask) +{ + switch (mask) { + default: + case MASK_NONE: return "none"; + case MASK_A1: return "a1"; + case MASK_A8: return "a8"; + } +} + +static const char *edge_name(enum edge edge) +{ + switch (edge) { + default: + case EDGE_SHARP: return "sharp"; + case EDGE_SMOOTH: return "smooth"; + } +} + +static void clear(struct test_display *dpy, struct test_target *tt) +{ + XRenderColor render_color = {0}; + XRenderFillRectangle(dpy->dpy, PictOpClear, tt->picture, &render_color, + 0, 0, tt->width, tt->height); +} + +static void step_to_point(int step, int width, int height, XPointFixed *p) +{ + do { + p->x = (step - 64) << 16; + p->y = -64 << 16; + + step -= width - 128; + if (step <= 0) + return; + + p->x = (width + 64) << 16; + p->y = (step - 64) << 16; + step -= height - 128; + + if (step <= 0) + return; + + p->x = (width + 64 - step) << 16; + p->y = (height + 64) << 16; + step -= width - 128; + + if (step <= 0) + return; + + p->x = -64 << 16; + p->y = (height + 64 - step) << 16; + step -= height - 128; + } while (step > 0); +} + +static void edge_test(struct test *t, + enum mask mask, + enum edge edge, + enum target target) +{ + struct test_target out, ref; + XRenderColor white = { 0xffff, 0xffff, 0xffff, 0xffff }; + Picture src_ref, src_out; + XTriangle tri; + unsigned step, max; + + test_target_create_render(&t->out, target, &out); + set_edge(t->out.dpy, out.picture, edge); + src_out = XRenderCreateSolidFill(t->out.dpy, &white); + + test_target_create_render(&t->ref, target, &ref); + set_edge(t->ref.dpy, ref.picture, edge); + src_ref = XRenderCreateSolidFill(t->ref.dpy, &white); + + printf("Testing edges (with mask %s and %s edges) (%s): ", + mask_name(mask), + edge_name(edge), + test_target_name(target)); + fflush(stdout); + + max = 2*(out.width + 128 + out.height+128); + step = 0; + for (step = 0; step <= max; step++) { + char buf[80]; + + step_to_point(step, out.width, out.height, &tri.p1); + step_to_point(step + out.width + 128, + out.width, out.height, + &tri.p2); + step_to_point(step + out.height + 128 + 2*(out.width + 128), + out.width, out.height, + &tri.p3); + + sprintf(buf, + "tri=((%d, %d), (%d, %d), (%d, %d))\n", + tri.p1.x >> 16, tri.p1.y >> 16, + tri.p2.x >> 16, tri.p2.y >> 16, + tri.p3.x >> 16, tri.p3.y >> 16); + + clear(&t->out, &out); + XRenderCompositeTriangles(t->out.dpy, + PictOpSrc, + src_out, + out.picture, + mask_format(t->out.dpy, mask), + 0, 0, + &tri, 1); + + clear(&t->ref, &ref); + XRenderCompositeTriangles(t->ref.dpy, + PictOpSrc, + src_ref, + ref.picture, + mask_format(t->ref.dpy, mask), + 0, 0, + &tri, 1); + + test_compare(t, + out.draw, out.format, + ref.draw, ref.format, + 0, 0, out.width, out.height, + buf); + } + + XRenderFreePicture(t->out.dpy, src_out); + test_target_destroy_render(&t->out, &out); + + XRenderFreePicture(t->ref.dpy, src_ref); + test_target_destroy_render(&t->ref, &ref); + + printf("pass\n"); +} + +int main(int argc, char **argv) +{ + struct test test; + enum target target; + enum mask mask; + enum edge edge; + + test_init(&test, argc, argv); + + for (target = TARGET_FIRST; target <= TARGET_LAST; target++) { + for (mask = MASK_NONE; mask <= MASK_A8; mask++) + for (edge = EDGE_SHARP; edge <= EDGE_SMOOTH; edge++) + edge_test(&test, mask, edge, target); + } + + return 0; +} From 324ba96520998da3aebb284445e4fea1ea6af739 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 19 May 2015 10:44:49 +0100 Subject: [PATCH 43/61] tests/render-trapezoid: Add edge tests Check fidelity of edge rendering, just a variant of render-triangle Signed-off-by: Chris Wilson --- test/render-trapezoid.c | 125 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/test/render-trapezoid.c b/test/render-trapezoid.c index cd990143..f15a78e3 100644 --- a/test/render-trapezoid.c +++ b/test/render-trapezoid.c @@ -403,16 +403,141 @@ static void trap_tests(struct test *t, free(traps); } +enum edge { + EDGE_SHARP = PolyEdgeSharp, + EDGE_SMOOTH, +}; + +static const char *edge_name(enum edge edge) +{ + switch (edge) { + default: + case EDGE_SHARP: return "sharp"; + case EDGE_SMOOTH: return "smooth"; + } +} + +static void set_edge(Display *dpy, Picture p, enum edge edge) +{ + XRenderPictureAttributes a; + + a.poly_edge = edge; + XRenderChangePicture(dpy, p, CPPolyEdge, &a); +} + +static void edge_test(struct test *t, + enum mask mask, + enum edge edge, + enum target target) +{ + struct test_target out, ref; + XRenderColor white = { 0xffff, 0xffff, 0xffff, 0xffff }; + Picture src_ref, src_out; + XTrapezoid trap; + int left_or_right, p; + + test_target_create_render(&t->out, target, &out); + set_edge(t->out.dpy, out.picture, edge); + src_out = XRenderCreateSolidFill(t->out.dpy, &white); + + test_target_create_render(&t->ref, target, &ref); + set_edge(t->ref.dpy, ref.picture, edge); + src_ref = XRenderCreateSolidFill(t->ref.dpy, &white); + + printf("Testing edges (with mask %s and %s edges) (%s): ", + mask_name(mask), + edge_name(edge), + test_target_name(target)); + fflush(stdout); + + for (left_or_right = 0; left_or_right <= 1; left_or_right++) { + for (p = -64; p <= out.width + 64; p++) { + char buf[80]; + + if (left_or_right) { + trap.left.p1.x = 0; + trap.left.p1.y = 0; + trap.left.p2.x = 0; + trap.left.p2.y = out.height << 16; + + trap.right.p1.x = p << 16; + trap.right.p1.y = 0; + trap.right.p2.x = out.width << 16; + trap.right.p2.y = out.height << 16; + } else { + trap.right.p1.x = out.width << 16; + trap.right.p1.y = 0; + trap.right.p2.x = out.width << 16; + trap.right.p2.y = out.height << 16; + + trap.left.p1.x = 0; + trap.left.p1.y = 0; + trap.left.p2.x = p << 16; + trap.left.p2.y = out.height << 16; + } + + trap.top = 0; + trap.bottom = out.height << 16; + + sprintf(buf, + "trap=((%d, %d), (%d, %d)), ((%d, %d), (%d, %d))\n", + trap.left.p1.x >> 16, trap.left.p1.y >> 16, + trap.left.p2.x >> 16, trap.left.p2.y >> 16, + trap.right.p1.x >> 16, trap.right.p1.y >> 16, + trap.right.p2.x >> 16, trap.right.p2.y >> 16); + + clear(&t->out, &out); + XRenderCompositeTrapezoids(t->out.dpy, + PictOpSrc, + src_out, + out.picture, + mask_format(t->out.dpy, mask), + 0, 0, + &trap, 1); + + clear(&t->ref, &ref); + XRenderCompositeTrapezoids(t->ref.dpy, + PictOpSrc, + src_ref, + ref.picture, + mask_format(t->ref.dpy, mask), + 0, 0, + &trap, 1); + + test_compare(t, + out.draw, out.format, + ref.draw, ref.format, + 0, 0, out.width, out.height, + buf); + } + } + + XRenderFreePicture(t->out.dpy, src_out); + test_target_destroy_render(&t->out, &out); + + XRenderFreePicture(t->ref.dpy, src_ref); + test_target_destroy_render(&t->ref, &ref); + + printf("pass\n"); +} + int main(int argc, char **argv) { struct test test; int i, dx, dy; enum target target; enum mask mask; + enum edge edge; enum trapezoid trapezoid; test_init(&test, argc, argv); + for (target = TARGET_FIRST; target <= TARGET_LAST; target++) { + for (mask = MASK_NONE; mask <= MASK_A8; mask++) + for (edge = EDGE_SHARP; edge <= EDGE_SMOOTH; edge++) + edge_test(&test, mask, edge, target); + } + for (i = 0; i <= DEFAULT_ITERATIONS; i++) { int reps = REPS(i), sets = SETS(i); From 276a628827c126a36f66e5f1b572aff2ff61de04 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 19 May 2015 11:11:21 +0100 Subject: [PATCH 44/61] sna: Disable HW cursor if we fail to update it If we cannot control the HW cursor, flag it as invalid and enable the SW cursor next time. The flag will remain set until the next modeset and we then try the HW cursor again. Signed-off-by: Chris Wilson --- src/sna/sna_display.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c index e96040d5..e62c6bec 100644 --- a/src/sna/sna_display.c +++ b/src/sna/sna_display.c @@ -5474,8 +5474,10 @@ disable: __FUNCTION__, __sna_crtc_id(sna_crtc), arg.x, arg.y, arg.handle, arg.flags, sna_crtc->cursor ? sna_crtc->cursor->handle : 0, arg.flags & DRM_MODE_CURSOR_MOVE, arg.flags & DRM_MODE_CURSOR_BO)); - if (arg.flags && - drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_CURSOR, &arg) == 0) { + if (arg.flags == 0) + continue; + + if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_CURSOR, &arg) == 0) { if (arg.flags & DRM_MODE_CURSOR_BO) { if (sna_crtc->cursor) { assert(sna_crtc->cursor->ref > 0); @@ -5488,6 +5490,14 @@ disable: } else sna_crtc->last_cursor_size = 0; } + } else { + ERR(("%s: failed to update cursor on CRTC:%d [pipe=%d], disabling hwcursor\n", + __FUNCTION__, sna_crtc_id(crtc), sna_crtc_pipe(crtc))); + sna_crtc->hwcursor = false; + /* XXX How to force switch back to SW cursor? + * Right now we just want until the next cursor image + * change, which is fairly frequent. + */ } } sigio_unblock(sigio); From e617c1941c4e5ee90b69221013aab799eace925d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 19 May 2015 12:14:24 +0100 Subject: [PATCH 45/61] sna: Force restoration of SW cursor after HW cursor fails In order to reset the SW cursor, we need to call xf86CursorSetCursor. However, the parameters we need to call SetCursor with are not exposed we need to be a little tricky and call a pair of functions that will save and then restore the cursor. Signed-off-by: Chris Wilson --- src/sna/sna.h | 3 ++- src/sna/sna_display.c | 38 +++++++++++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/sna/sna.h b/src/sna/sna.h index 374754b4..8a405800 100644 --- a/src/sna/sna.h +++ b/src/sna/sna.h @@ -322,7 +322,8 @@ struct sna { uint32_t fg, bg; int size; - int active; + bool disable; + bool active; int last_x; int last_y; diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c index e62c6bec..daa14029 100644 --- a/src/sna/sna_display.c +++ b/src/sna/sna_display.c @@ -5215,6 +5215,28 @@ static inline void sigio_unblock(int was_blocked) } #endif +static void __restore_swcursor(ScrnInfoPtr scrn) +{ + DBG(("%s: attempting to restore SW cursor\n", __FUNCTION__)); + scrn->EnableDisableFBAccess(scrn, FALSE); + scrn->EnableDisableFBAccess(scrn, TRUE); + + RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr)__restore_swcursor, + (WakeupHandlerProcPtr)NoopDDA, + scrn); +} + +static void restore_swcursor(struct sna *sna) +{ + /* XXX Force the cursor to be restored (avoiding recursion) */ + FreeCursor(sna->cursor.ref, None); + sna->cursor.ref = NULL; + + RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)__restore_swcursor, + (WakeupHandlerProcPtr)NoopDDA, + sna->scrn); +} + static void sna_show_cursors(ScrnInfoPtr scrn) { @@ -5268,10 +5290,17 @@ sna_show_cursors(ScrnInfoPtr scrn) cursor->ref++; sna_crtc->cursor = cursor; sna_crtc->last_cursor_size = cursor->size; + } else { + ERR(("%s: failed to show cursor on CRTC:%d [pipe=%d], disabling hwcursor\n", + __FUNCTION__, sna_crtc_id(crtc), sna_crtc_pipe(crtc))); + sna->cursor.disable = true; } } sigio_unblock(sigio); sna->cursor.active = true; + + if (unlikely(sna->cursor.disable)) + restore_swcursor(sna); } static void @@ -5493,14 +5522,17 @@ disable: } else { ERR(("%s: failed to update cursor on CRTC:%d [pipe=%d], disabling hwcursor\n", __FUNCTION__, sna_crtc_id(crtc), sna_crtc_pipe(crtc))); - sna_crtc->hwcursor = false; /* XXX How to force switch back to SW cursor? * Right now we just want until the next cursor image * change, which is fairly frequent. */ + sna->cursor.disable = true; } } sigio_unblock(sigio); + + if (unlikely(sna->cursor.disable)) + restore_swcursor(sna); } #if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,902,2) @@ -5596,6 +5628,9 @@ sna_use_hw_cursor(ScreenPtr screen, CursorPtr cursor) DBG(("%s (%dx%d)?\n", __FUNCTION__, cursor->bits->width, cursor->bits->height)); + if (sna->cursor.disable) + return FALSE; + /* cursors are invariant */ if (cursor == sna->cursor.ref) return TRUE; @@ -6453,6 +6488,7 @@ sna_crtc_config_notify(ScreenPtr screen) } update_flush_interval(sna); + sna->cursor.disable = false; /* Reset HW cursor until the next fail */ sna_cursors_reload(sna); probe_capabilities(sna); From 8b7bdff750a98fc7644fc9ab17bedc79b03198b4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 25 May 2015 08:02:46 +0100 Subject: [PATCH 46/61] sna: Initialise no-op callbacks early In case of error, we try to free up memory before trying again. This involves callbacks into higher level code - but if we fail early, we will not have those hooks installed. Set no-ops stubs early to prevent untimely crashes. References: https://bugs.freedesktop.org/show_bug.cgi?id=90622#c1 Signed-off-by: Chris Wilson --- src/sna/kgem.c | 23 +++++++++++++++++++++++ src/sna/sna_render.c | 14 -------------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/sna/kgem.c b/src/sna/kgem.c index f6b72d9e..463f65fc 100644 --- a/src/sna/kgem.c +++ b/src/sna/kgem.c @@ -1692,6 +1692,25 @@ static struct kgem_bo *kgem_new_batch(struct kgem *kgem) return last; } +static void +no_retire(struct kgem *kgem) +{ + (void)kgem; +} + +static void +no_expire(struct kgem *kgem) +{ + (void)kgem; +} + +static void +no_context_switch(struct kgem *kgem, int new_mode) +{ + (void)kgem; + (void)new_mode; +} + void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen) { struct drm_i915_gem_get_aperture aperture; @@ -1704,6 +1723,10 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen) kgem->fd = fd; kgem->gen = gen; + kgem->retire = no_retire; + kgem->expire = no_expire; + kgem->context_switch = no_context_switch; + list_init(&kgem->requests[0]); list_init(&kgem->requests[1]); list_init(&kgem->batch_buffers); diff --git a/src/sna/sna_render.c b/src/sna/sna_render.c index d95536ec..a9945057 100644 --- a/src/sna/sna_render.c +++ b/src/sna/sna_render.c @@ -271,18 +271,6 @@ no_render_context_switch(struct kgem *kgem, (void)new_mode; } -static void -no_render_retire(struct kgem *kgem) -{ - (void)kgem; -} - -static void -no_render_expire(struct kgem *kgem) -{ - (void)kgem; -} - static void no_render_fini(struct sna *sna) { @@ -316,8 +304,6 @@ const char *no_render_init(struct sna *sna) render->fini = no_render_fini; sna->kgem.context_switch = no_render_context_switch; - sna->kgem.retire = no_render_retire; - sna->kgem.expire = no_render_expire; if (sna->kgem.has_blt) sna->kgem.ring = KGEM_BLT; From a6dd2655cb41000943e554ccea16e5781bcbf012 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 25 May 2015 08:25:31 +0100 Subject: [PATCH 47/61] sna: Clear encoders request field when updating properties Reported-by: Dave Airlie Signed-off-by: Chris Wilson --- src/sna/sna_display.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c index daa14029..c0c359cd 100644 --- a/src/sna/sna_display.c +++ b/src/sna/sna_display.c @@ -3860,6 +3860,7 @@ static void update_properties(struct sna *sna, struct sna_output *output) compat_conn.conn.prop_values_ptr = (uintptr_t)output->prop_values; compat_conn.conn.count_modes = 1; /* skip detect */ compat_conn.conn.modes_ptr = (uintptr_t)&dummy; + compat_conn.conn.count_encoders = 0; (void)drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCONNECTOR, From fb1643f0f904eb258da71cd0b8deb8d3ec6dafed Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 27 May 2015 07:37:35 +0100 Subject: [PATCH 48/61] sna/dri2: Refine ring selection with multiple active rings The preference given multiple rings is to the previous writer, or if none, to the render ring if active. References: https://bugs.freedesktop.org/show_bug.cgi?id=90671 Signed-off-by: Chris Wilson --- src/sna/sna_dri2.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/sna/sna_dri2.c b/src/sna/sna_dri2.c index dbdde32e..be33480a 100644 --- a/src/sna/sna_dri2.c +++ b/src/sna/sna_dri2.c @@ -870,6 +870,22 @@ static void set_bo(PixmapPtr pixmap, struct kgem_bo *bo) } } +#if defined(__GNUC__) +#define popcount(x) __builtin_popcount(x) +#else +static int popcount(unsigned int x) +{ + int count = 0; + + while (x) { + count += x&1; + x >>= 1; + } + + return count; +} +#endif + static void sna_dri2_select_mode(struct sna *sna, struct kgem_bo *dst, struct kgem_bo *src, bool sync) { struct drm_i915_gem_busy busy; @@ -940,9 +956,12 @@ static void sna_dri2_select_mode(struct sna *sna, struct kgem_bo *dst, struct kg * The ultimate question is whether preserving the ring outweighs * the cost of the query. */ - mode = KGEM_RENDER; - if (busy.busy & (0xfffe << 16)) + if (popcount(busy.busy >> 16) > 1) + mode = busy.busy & 0xffff ? KGEM_BLT : KGEM_RENDER; + else if (busy.busy & (0xfffe << 16)) mode = KGEM_BLT; + else + mode = KGEM_RENDER; kgem_bo_mark_busy(&sna->kgem, busy.handle == src->handle ? src : dst, mode); _kgem_set_mode(&sna->kgem, mode); } From 5fa114d945fc4ee5d9e89dc18d99584b02baa678 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 28 May 2015 11:23:35 +0100 Subject: [PATCH 49/61] sna: sna_set_desired_mode() always returns true, make it void Since sna_set_desired_mode() always returns true, we can make it void and remove some unreachable code. Signed-off-by: Chris Wilson --- src/sna/sna_driver.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/sna/sna_driver.c b/src/sna/sna_driver.c index 4e76fd0e..b1011b74 100644 --- a/src/sna/sna_driver.c +++ b/src/sna/sna_driver.c @@ -199,7 +199,7 @@ sna_set_fallback_mode(ScrnInfoPtr scrn) #endif } -static Bool sna_set_desired_mode(struct sna *sna) +static void sna_set_desired_mode(struct sna *sna) { ScrnInfoPtr scrn = sna->scrn; @@ -212,7 +212,6 @@ static Bool sna_set_desired_mode(struct sna *sna) } sna_mode_check(sna); - return TRUE; } /** @@ -282,7 +281,7 @@ static Bool sna_create_screen_resources(ScreenPtr screen) if (serverGeneration == 1 && (sna->flags & SNA_IS_HOSTED) == 0) sna_copy_fbcon(sna); - (void)sna_set_desired_mode(sna); + sna_set_desired_mode(sna); } return TRUE; @@ -1217,13 +1216,8 @@ static Bool sna_enter_vt(VT_FUNC_ARGS_DECL) sna_mode_discover(sna); sna->flags &= ~SNA_REPROBE; } - sna_mode_check(sna); - if (!sna_set_desired_mode(sna)) { - sna_accel_leave(sna); - intel_put_master(sna->dev); - return FALSE; - } + sna_set_desired_mode(sna); return TRUE; } From 401b9deef045aedbb60ac4fd3c3cc9efbd8339c1 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 28 May 2015 11:24:27 +0100 Subject: [PATCH 50/61] sna: Flag disabled CRTC to xrandr If we disable a CRTC, mark it as such and send an XRR event so that userspace can do any recovery, and so that hopefully xrandr remains consistent. Signed-off-by: Chris Wilson --- src/sna/sna_display.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c index c0c359cd..6ef07a97 100644 --- a/src/sna/sna_display.c +++ b/src/sna/sna_display.c @@ -7181,7 +7181,8 @@ sna_wait_for_scanline(struct sna *sna, void sna_mode_check(struct sna *sna) { xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn); - int i; + bool disabled = false; + int c, o; if (sna->flags & SNA_IS_HOSTED) return; @@ -7191,8 +7192,8 @@ void sna_mode_check(struct sna *sna) return; /* Validate CRTC attachments and force consistency upon the kernel */ - for (i = 0; i < sna->mode.num_real_crtc; i++) { - xf86CrtcPtr crtc = config->crtc[i]; + for (c = 0; c < sna->mode.num_real_crtc; c++) { + xf86CrtcPtr crtc = config->crtc[c]; struct sna_crtc *sna_crtc = to_sna_crtc(crtc); struct drm_mode_crtc mode; uint32_t expected[2]; @@ -7220,11 +7221,28 @@ void sna_mode_check(struct sna *sna) "%s: invalid state found on pipe %d, disabling CRTC:%d\n", __FUNCTION__, __sna_crtc_pipe(sna_crtc), __sna_crtc_id(sna_crtc)); sna_crtc_disable(crtc, true); +#if XF86_CRTC_VERSION >= 3 + crtc->active = FALSE; +#endif + if (crtc->enabled) { + crtc->enabled = FALSE; + disabled = true; + } + + for (o = 0; o < sna->mode.num_real_output; o++) { + xf86OutputPtr output = config->output[o]; + + if (output->crtc != crtc) + continue; + + output->funcs->dpms(output, DPMSModeOff); + output->crtc = NULL; + } } } - for (i = 0; i < config->num_output; i++) { - xf86OutputPtr output = config->output[i]; + for (o = 0; o < config->num_output; o++) { + xf86OutputPtr output = config->output[o]; struct sna_output *sna_output; if (output->crtc) @@ -7238,6 +7256,9 @@ void sna_mode_check(struct sna *sna) } update_flush_interval(sna); + + if (disabled) + xf86RandR12TellChanged(xf86ScrnToScreen(sna->scrn)); } static bool From ce4836b091bc10489ab876b2922ca3f004bc5bf4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 31 May 2015 08:58:02 +0100 Subject: [PATCH 51/61] sna: Detect when SET_TILING fails to change tiling If the swizzling is unknown, the SET_TILING ioctl silently converts the request back to I915_TILING_NONE. In order to detect this, we need to double check the ioctl parameters. References: https://bugs.freedesktop.org/show_bug.cgi?id=90725#c21 Signed-off-by: Chris Wilson --- src/sna/kgem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sna/kgem.c b/src/sna/kgem.c index 463f65fc..a28f9596 100644 --- a/src/sna/kgem.c +++ b/src/sna/kgem.c @@ -454,7 +454,7 @@ restart: set_tiling.stride = stride; if (ioctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling) == 0) - return true; + return set_tiling.tiling_mode == tiling; err = errno; if (err == EINTR) From 0cd01c04fab59e921e9390813d4014af116504ff Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 31 May 2015 09:16:36 +0100 Subject: [PATCH 52/61] sna: Always apply the SET_TILING results to the bo Since the kernel can silently change the tiling on the object irrespectie of the ioctl's request, we have to double check and remove any such invalid object from our lists. Signed-off-by: Chris Wilson --- src/sna/kgem.c | 110 ++++++++++++++++++++++--------------------------- 1 file changed, 50 insertions(+), 60 deletions(-) diff --git a/src/sna/kgem.c b/src/sna/kgem.c index a28f9596..b39bc15a 100644 --- a/src/sna/kgem.c +++ b/src/sna/kgem.c @@ -439,7 +439,8 @@ static void kgem_sna_flush(struct kgem *kgem) sna_render_flush_solid(sna); } -static bool gem_set_tiling(int fd, uint32_t handle, int tiling, int stride) +static bool kgem_set_tiling(struct kgem *kgem, struct kgem_bo *bo, + int tiling, int stride) { struct drm_i915_gem_set_tiling set_tiling; int err; @@ -449,12 +450,15 @@ static bool gem_set_tiling(int fd, uint32_t handle, int tiling, int stride) VG_CLEAR(set_tiling); restart: - set_tiling.handle = handle; + set_tiling.handle = bo->handle; set_tiling.tiling_mode = tiling; set_tiling.stride = stride; - if (ioctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling) == 0) + if (ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling) == 0) { + bo->tiling = set_tiling.tiling_mode; + bo->pitch = set_tiling.stride; return set_tiling.tiling_mode == tiling; + } err = errno; if (err == EINTR) @@ -1391,6 +1395,24 @@ static bool test_can_blt_y(struct kgem *kgem) return ret == 0; } +static bool gem_set_tiling(int fd, uint32_t handle, int tiling, int stride) +{ + struct drm_i915_gem_set_tiling set_tiling; + + if (DBG_NO_TILING) + return false; + + VG_CLEAR(set_tiling); + set_tiling.handle = handle; + set_tiling.tiling_mode = tiling; + set_tiling.stride = stride; + + if (ioctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling) == 0) + return set_tiling.tiling_mode == tiling; + + return false; +} + static bool test_can_scanout_y(struct kgem *kgem) { struct drm_mode_fb_cmd arg; @@ -4337,12 +4359,9 @@ retry_large: if (use_active) goto discard; - if (!gem_set_tiling(kgem->fd, bo->handle, + if (!kgem_set_tiling(kgem, bo, I915_TILING_NONE, 0)) goto discard; - - bo->tiling = I915_TILING_NONE; - bo->pitch = 0; } if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) @@ -4425,16 +4444,13 @@ discard: } if (I915_TILING_NONE != bo->tiling && - !gem_set_tiling(kgem->fd, bo->handle, - I915_TILING_NONE, 0)) + !kgem_set_tiling(kgem, bo, I915_TILING_NONE, 0)) continue; kgem_bo_remove_from_inactive(kgem, bo); assert(list_is_empty(&bo->vma)); assert(list_is_empty(&bo->list)); - bo->tiling = I915_TILING_NONE; - bo->pitch = 0; bo->delta = 0; DBG((" %s: found handle=%d (num_pages=%d) in linear vma cache\n", __FUNCTION__, bo->handle, num_pages(bo))); @@ -4480,12 +4496,8 @@ discard: if (first) continue; - if (!gem_set_tiling(kgem->fd, bo->handle, - I915_TILING_NONE, 0)) + if (!kgem_set_tiling(kgem, bo, I915_TILING_NONE, 0)) continue; - - bo->tiling = I915_TILING_NONE; - bo->pitch = 0; } if (bo->map__gtt || bo->map__wc || bo->map__cpu) { @@ -4524,7 +4536,7 @@ discard: kgem_bo_remove_from_inactive(kgem, bo); assert(bo->tiling == I915_TILING_NONE); - bo->pitch = 0; + assert(bo->pitch == 0); bo->delta = 0; DBG((" %s: found handle=%d (num_pages=%d) in linear %s cache\n", __FUNCTION__, bo->handle, num_pages(bo), @@ -5171,11 +5183,8 @@ struct kgem_bo *kgem_create_2d(struct kgem *kgem, bo->delta = 0; } - if (gem_set_tiling(kgem->fd, bo->handle, - tiling, pitch)) { - bo->tiling = tiling; - bo->pitch = pitch; - } else { + if (!kgem_set_tiling(kgem, bo, + tiling, pitch)) { kgem_bo_free(kgem, bo); break; } @@ -5247,12 +5256,9 @@ struct kgem_bo *kgem_create_2d(struct kgem *kgem, continue; if (bo->pitch != pitch || bo->tiling != tiling) { - if (!gem_set_tiling(kgem->fd, bo->handle, + if (!kgem_set_tiling(kgem, bo, tiling, pitch)) continue; - - bo->pitch = pitch; - bo->tiling = tiling; } } @@ -5281,12 +5287,8 @@ large_inactive: if (bo->tiling != tiling || (tiling != I915_TILING_NONE && bo->pitch != pitch)) { - if (!gem_set_tiling(kgem->fd, bo->handle, - tiling, pitch)) + if (!kgem_set_tiling(kgem, bo, tiling, pitch)) continue; - - bo->tiling = tiling; - bo->pitch = pitch; } if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) { @@ -5298,7 +5300,6 @@ large_inactive: assert(bo->domain != DOMAIN_GPU); bo->unique_id = kgem_get_unique_id(kgem); - bo->pitch = pitch; bo->delta = 0; DBG((" 1:from large inactive: pitch=%d, tiling=%d, handle=%d, id=%d\n", bo->pitch, bo->tiling, bo->handle, bo->unique_id)); @@ -5347,14 +5348,12 @@ large_inactive: if (bo->tiling != tiling || (tiling != I915_TILING_NONE && bo->pitch != pitch)) { if (bo->map__gtt || - !gem_set_tiling(kgem->fd, bo->handle, - tiling, pitch)) { + !kgem_set_tiling(kgem, bo, + tiling, pitch)) { DBG(("inactive GTT vma with wrong tiling: %d < %d\n", bo->tiling, tiling)); continue; } - bo->tiling = tiling; - bo->pitch = pitch; } if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) { @@ -5429,13 +5428,10 @@ search_active: if (num_pages(bo) < size) continue; - if (bo->pitch != pitch) { - if (!gem_set_tiling(kgem->fd, - bo->handle, - tiling, pitch)) - continue; - - bo->pitch = pitch; + if (bo->pitch != pitch && + !kgem_set_tiling(kgem, bo, tiling, pitch)) { + kgem_bo_free(kgem, bo); + break; } } @@ -5494,17 +5490,16 @@ search_active: if (bo->tiling != tiling || (tiling != I915_TILING_NONE && bo->pitch != pitch)) { - if (!gem_set_tiling(kgem->fd, - bo->handle, - tiling, pitch)) - continue; + if (!kgem_set_tiling(kgem, bo, + tiling, pitch)) { + kgem_bo_free(kgem, bo); + break; + } } kgem_bo_remove_from_active(kgem, bo); bo->unique_id = kgem_get_unique_id(kgem); - bo->pitch = pitch; - bo->tiling = tiling; bo->delta = 0; DBG((" 1:from active: pitch=%d, tiling=%d, handle=%d, id=%d\n", bo->pitch, bo->tiling, bo->handle, bo->unique_id)); @@ -5584,9 +5579,10 @@ search_inactive: if (bo->tiling != tiling || (tiling != I915_TILING_NONE && bo->pitch != pitch)) { - if (!gem_set_tiling(kgem->fd, bo->handle, - tiling, pitch)) - continue; + if (!kgem_set_tiling(kgem, bo, tiling, pitch)) { + kgem_bo_free(kgem, bo); + break; + } } if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) { @@ -5598,9 +5594,6 @@ search_inactive: assert(list_is_empty(&bo->list)); assert(list_is_empty(&bo->vma)); - bo->pitch = pitch; - bo->tiling = tiling; - bo->delta = 0; bo->unique_id = kgem_get_unique_id(kgem); assert(bo->pitch); @@ -5648,13 +5641,12 @@ search_inactive: __kgem_bo_clear_busy(bo); if (tiling != I915_TILING_NONE && bo->pitch != pitch) { - if (!gem_set_tiling(kgem->fd, bo->handle, tiling, pitch)) { + if (!kgem_set_tiling(kgem, bo, tiling, pitch)) { kgem_bo_free(kgem, bo); goto no_retire; } } - bo->pitch = pitch; bo->unique_id = kgem_get_unique_id(kgem); bo->delta = 0; DBG((" 2:from active: pitch=%d, tiling=%d, handle=%d, id=%d\n", @@ -5700,9 +5692,7 @@ create: bo->unique_id = kgem_get_unique_id(kgem); if (tiling == I915_TILING_NONE || - gem_set_tiling(kgem->fd, handle, tiling, pitch)) { - bo->tiling = tiling; - bo->pitch = pitch; + kgem_set_tiling(kgem, bo, tiling, pitch)) { if (flags & CREATE_SCANOUT) __kgem_bo_make_scanout(kgem, bo, width, height); } else { From 9a6c77d7ad9f605cd5af7656c425a1f63104f38f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 31 May 2015 12:10:32 +0100 Subject: [PATCH 53/61] sna: Add a few more asserts for clearing tiling Signed-off-by: Chris Wilson --- src/sna/kgem.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sna/kgem.c b/src/sna/kgem.c index b39bc15a..ef1c12d8 100644 --- a/src/sna/kgem.c +++ b/src/sna/kgem.c @@ -4363,6 +4363,8 @@ retry_large: I915_TILING_NONE, 0)) goto discard; } + assert(bo->tiling == I915_TILING_NONE); + assert(bo->pitch == 0); if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) goto discard; @@ -4451,6 +4453,8 @@ discard: assert(list_is_empty(&bo->vma)); assert(list_is_empty(&bo->list)); + assert(bo->tiling == I915_TILING_NONE); + assert(bo->pitch == 0); bo->delta = 0; DBG((" %s: found handle=%d (num_pages=%d) in linear vma cache\n", __FUNCTION__, bo->handle, num_pages(bo))); @@ -4499,6 +4503,8 @@ discard: if (!kgem_set_tiling(kgem, bo, I915_TILING_NONE, 0)) continue; } + assert(bo->tiling == I915_TILING_NONE); + assert(bo->pitch == 0); if (bo->map__gtt || bo->map__wc || bo->map__cpu) { if (flags & (CREATE_CPU_MAP | CREATE_GTT_MAP)) { From db78a3449cfba6cfa4760b2333bf7c083eb991d6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 31 May 2015 12:30:16 +0100 Subject: [PATCH 54/61] sna: Keep pitch even for I915_TILING_NONE surfaces We have to ignore the return value of the pitch for untiled 2D surfaces (since the kernel clears the tiling stride parameter). Signed-off-by: Chris Wilson --- src/sna/kgem.c | 85 ++++++++++++++++++++++++++------------------------ 1 file changed, 44 insertions(+), 41 deletions(-) diff --git a/src/sna/kgem.c b/src/sna/kgem.c index ef1c12d8..832ddb16 100644 --- a/src/sna/kgem.c +++ b/src/sna/kgem.c @@ -445,6 +445,15 @@ static bool kgem_set_tiling(struct kgem *kgem, struct kgem_bo *bo, struct drm_i915_gem_set_tiling set_tiling; int err; + if (tiling == bo->tiling) { + if (tiling == I915_TILING_NONE) { + bo->pitch = stride; + return true; + } + if (stride == bo->pitch) + return true; + } + if (DBG_NO_TILING) return false; @@ -452,11 +461,11 @@ static bool kgem_set_tiling(struct kgem *kgem, struct kgem_bo *bo, restart: set_tiling.handle = bo->handle; set_tiling.tiling_mode = tiling; - set_tiling.stride = stride; + set_tiling.stride = tiling ? stride : 0; if (ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling) == 0) { bo->tiling = set_tiling.tiling_mode; - bo->pitch = set_tiling.stride; + bo->pitch = set_tiling.tiling_mode ? set_tiling.stride : stride; return set_tiling.tiling_mode == tiling; } @@ -4356,7 +4365,7 @@ retry_large: goto discard; if (bo->tiling != I915_TILING_NONE) { - if (use_active) + if (use_active && kgem->gen < 040) goto discard; if (!kgem_set_tiling(kgem, bo, @@ -4445,9 +4454,10 @@ discard: break; } - if (I915_TILING_NONE != bo->tiling && - !kgem_set_tiling(kgem, bo, I915_TILING_NONE, 0)) - continue; + if (!kgem_set_tiling(kgem, bo, I915_TILING_NONE, 0)) { + kgem_bo_free(kgem, bo); + break; + } kgem_bo_remove_from_inactive(kgem, bo); assert(list_is_empty(&bo->vma)); @@ -4500,8 +4510,10 @@ discard: if (first) continue; - if (!kgem_set_tiling(kgem, bo, I915_TILING_NONE, 0)) - continue; + if (!kgem_set_tiling(kgem, bo, I915_TILING_NONE, 0)) { + kgem_bo_free(kgem, bo); + break; + } } assert(bo->tiling == I915_TILING_NONE); assert(bo->pitch == 0); @@ -5261,11 +5273,8 @@ struct kgem_bo *kgem_create_2d(struct kgem *kgem, if (num_pages(bo) < size) continue; - if (bo->pitch != pitch || bo->tiling != tiling) { - if (!kgem_set_tiling(kgem, bo, - tiling, pitch)) - continue; - } + if (!kgem_set_tiling(kgem, bo, tiling, pitch)) + continue; } kgem_bo_remove_from_active(kgem, bo); @@ -5291,11 +5300,8 @@ large_inactive: if (size > num_pages(bo)) continue; - if (bo->tiling != tiling || - (tiling != I915_TILING_NONE && bo->pitch != pitch)) { - if (!kgem_set_tiling(kgem, bo, tiling, pitch)) - continue; - } + if (!kgem_set_tiling(kgem, bo, tiling, pitch)) + continue; if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) { kgem_bo_free(kgem, bo); @@ -5368,7 +5374,7 @@ large_inactive: } assert(bo->tiling == tiling); - bo->pitch = pitch; + assert(bo->pitch >= pitch); bo->delta = 0; bo->unique_id = kgem_get_unique_id(kgem); @@ -5434,12 +5440,13 @@ search_active: if (num_pages(bo) < size) continue; - if (bo->pitch != pitch && - !kgem_set_tiling(kgem, bo, tiling, pitch)) { + if (!kgem_set_tiling(kgem, bo, tiling, pitch)) { kgem_bo_free(kgem, bo); break; } } + assert(bo->tiling == tiling); + assert(bo->pitch >= pitch); kgem_bo_remove_from_active(kgem, bo); @@ -5494,14 +5501,12 @@ search_active: if (num_pages(bo) < size) continue; - if (bo->tiling != tiling || - (tiling != I915_TILING_NONE && bo->pitch != pitch)) { - if (!kgem_set_tiling(kgem, bo, - tiling, pitch)) { - kgem_bo_free(kgem, bo); - break; - } + if (!kgem_set_tiling(kgem, bo, tiling, pitch)) { + kgem_bo_free(kgem, bo); + break; } + assert(bo->tiling == tiling); + assert(bo->pitch >= pitch); kgem_bo_remove_from_active(kgem, bo); @@ -5583,12 +5588,9 @@ search_inactive: continue; } - if (bo->tiling != tiling || - (tiling != I915_TILING_NONE && bo->pitch != pitch)) { - if (!kgem_set_tiling(kgem, bo, tiling, pitch)) { - kgem_bo_free(kgem, bo); - break; - } + if (!kgem_set_tiling(kgem, bo, tiling, pitch)) { + kgem_bo_free(kgem, bo); + break; } if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) { @@ -5599,6 +5601,8 @@ search_inactive: kgem_bo_remove_from_inactive(kgem, bo); assert(list_is_empty(&bo->list)); assert(list_is_empty(&bo->vma)); + assert(bo->tiling == tiling); + assert(bo->pitch >= pitch); bo->delta = 0; bo->unique_id = kgem_get_unique_id(kgem); @@ -5646,12 +5650,12 @@ search_inactive: kgem_bo_remove_from_active(kgem, bo); __kgem_bo_clear_busy(bo); - if (tiling != I915_TILING_NONE && bo->pitch != pitch) { - if (!kgem_set_tiling(kgem, bo, tiling, pitch)) { - kgem_bo_free(kgem, bo); - goto no_retire; - } + if (!kgem_set_tiling(kgem, bo, tiling, pitch)) { + kgem_bo_free(kgem, bo); + goto no_retire; } + assert(bo->tiling == tiling); + assert(bo->pitch >= pitch); bo->unique_id = kgem_get_unique_id(kgem); bo->delta = 0; @@ -5697,8 +5701,7 @@ create: } bo->unique_id = kgem_get_unique_id(kgem); - if (tiling == I915_TILING_NONE || - kgem_set_tiling(kgem, bo, tiling, pitch)) { + if (kgem_set_tiling(kgem, bo, tiling, pitch)) { if (flags & CREATE_SCANOUT) __kgem_bo_make_scanout(kgem, bo, width, height); } else { From 834bdb0344f1e71c3c0e8c31e47bd44cec28e584 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 31 May 2015 19:11:54 +0100 Subject: [PATCH 55/61] sna: Relax a couple of tiling assertions Along a couple of passes, we have to set pitch back to 0 when reusing a linear surface. Signed-off-by: Chris Wilson --- src/sna/kgem.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/sna/kgem.c b/src/sna/kgem.c index 832ddb16..59352634 100644 --- a/src/sna/kgem.c +++ b/src/sna/kgem.c @@ -4373,7 +4373,7 @@ retry_large: goto discard; } assert(bo->tiling == I915_TILING_NONE); - assert(bo->pitch == 0); + bo->pitch = 0; if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) goto discard; @@ -4516,7 +4516,7 @@ discard: } } assert(bo->tiling == I915_TILING_NONE); - assert(bo->pitch == 0); + bo->pitch = 0; if (bo->map__gtt || bo->map__wc || bo->map__cpu) { if (flags & (CREATE_CPU_MAP | CREATE_GTT_MAP)) { @@ -5373,6 +5373,9 @@ large_inactive: break; } + if (tiling == I915_TILING_NONE) + bo->pitch = pitch; + assert(bo->tiling == tiling); assert(bo->pitch >= pitch); bo->delta = 0; From 14b5ab3fef80afdb204fe399e0340f028ab7839c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 1 Jun 2015 08:25:12 +0100 Subject: [PATCH 56/61] sna: Enable use of GPU tiling even when SET_TILING fails On gen4+, we no longer need to setup a fence for tiled operations and so can program the GPU irrespective of the kernel tiled settings. However, this means that we then cannot access the object through a GTT mmapping (as we have no fence to do detiling) and nor can we use a WC mmap as the swizzle is unknown. Signed-off-by: Chris Wilson --- src/sna/kgem.c | 76 ++++++++++++++++++++++++++++++++++++++------------ src/sna/kgem.h | 1 + 2 files changed, 59 insertions(+), 18 deletions(-) diff --git a/src/sna/kgem.c b/src/sna/kgem.c index 59352634..e4960eac 100644 --- a/src/sna/kgem.c +++ b/src/sna/kgem.c @@ -562,6 +562,9 @@ static void *__kgem_bo_map__gtt(struct kgem *kgem, struct kgem_bo *bo) DBG(("%s(handle=%d, size=%d)\n", __FUNCTION__, bo->handle, bytes(bo))); + if (!kgem->can_fence) + return NULL; + VG_CLEAR(gtt); retry_gtt: gtt.handle = bo->handle; @@ -1599,6 +1602,8 @@ static void kgem_init_swizzling(struct kgem *kgem) if (!DBG_NO_DETILING) choose_memcpy_tiled_x(kgem, tiling.swizzle_mode); + + kgem->can_fence = tiling.swizzle_mode != I915_BIT_6_SWIZZLE_UNKNOWN; out: gem_close(kgem->fd, tiling.handle); } @@ -5273,8 +5278,11 @@ struct kgem_bo *kgem_create_2d(struct kgem *kgem, if (num_pages(bo) < size) continue; - if (!kgem_set_tiling(kgem, bo, tiling, pitch)) - continue; + if (!kgem_set_tiling(kgem, bo, tiling, pitch)) { + assert(!kgem->can_fence); + bo->tiling = tiling; + bo->pitch = pitch; + } } kgem_bo_remove_from_active(kgem, bo); @@ -5300,8 +5308,14 @@ large_inactive: if (size > num_pages(bo)) continue; - if (!kgem_set_tiling(kgem, bo, tiling, pitch)) - continue; + if (!kgem_set_tiling(kgem, bo, tiling, pitch)) { + if (kgem->gen >= 040) { + assert(!kgem->can_fence); + bo->tiling = tiling; + bo->pitch = pitch; + } else + continue; + } if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) { kgem_bo_free(kgem, bo); @@ -5364,7 +5378,8 @@ large_inactive: tiling, pitch)) { DBG(("inactive GTT vma with wrong tiling: %d < %d\n", bo->tiling, tiling)); - continue; + kgem_bo_free(kgem, bo); + break; } } @@ -5444,8 +5459,9 @@ search_active: continue; if (!kgem_set_tiling(kgem, bo, tiling, pitch)) { - kgem_bo_free(kgem, bo); - break; + assert(!kgem->can_fence); + bo->tiling = tiling; + bo->pitch = pitch; } } assert(bo->tiling == tiling); @@ -5505,8 +5521,14 @@ search_active: continue; if (!kgem_set_tiling(kgem, bo, tiling, pitch)) { - kgem_bo_free(kgem, bo); - break; + if (kgem->gen >= 040) { + assert(!kgem->can_fence); + bo->tiling = tiling; + bo->pitch = pitch; + } else { + kgem_bo_free(kgem, bo); + break; + } } assert(bo->tiling == tiling); assert(bo->pitch >= pitch); @@ -5592,8 +5614,14 @@ search_inactive: } if (!kgem_set_tiling(kgem, bo, tiling, pitch)) { - kgem_bo_free(kgem, bo); - break; + if (kgem->gen >= 040) { + assert(!kgem->can_fence); + bo->tiling = tiling; + bo->pitch = pitch; + } else { + kgem_bo_free(kgem, bo); + break; + } } if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) { @@ -5654,8 +5682,14 @@ search_inactive: __kgem_bo_clear_busy(bo); if (!kgem_set_tiling(kgem, bo, tiling, pitch)) { - kgem_bo_free(kgem, bo); - goto no_retire; + if (kgem->gen >= 040) { + assert(!kgem->can_fence); + bo->tiling = tiling; + bo->pitch = pitch; + } else { + kgem_bo_free(kgem, bo); + goto no_retire; + } } assert(bo->tiling == tiling); assert(bo->pitch >= pitch); @@ -5708,11 +5742,17 @@ create: if (flags & CREATE_SCANOUT) __kgem_bo_make_scanout(kgem, bo, width, height); } else { - if (flags & CREATE_EXACT) { - DBG(("%s: failed to set exact tiling (gem_set_tiling)\n", __FUNCTION__)); - gem_close(kgem->fd, handle); - free(bo); - return NULL; + if (kgem->gen >= 040) { + assert(!kgem->can_fence); + bo->tiling = tiling; + bo->pitch = pitch; + } else { + if (flags & CREATE_EXACT) { + DBG(("%s: failed to set exact tiling (gem_set_tiling)\n", __FUNCTION__)); + gem_close(kgem->fd, handle); + free(bo); + return NULL; + } } } diff --git a/src/sna/kgem.h b/src/sna/kgem.h index bdcb9f14..9e6db0f2 100644 --- a/src/sna/kgem.h +++ b/src/sna/kgem.h @@ -190,6 +190,7 @@ struct kgem { uint32_t has_handle_lut :1; uint32_t has_wc_mmap :1; + uint32_t can_fence :1; uint32_t can_blt_cpu :1; uint32_t can_blt_y :1; uint32_t can_render_y :1; From 67185f54ba07205d1df1e5eed30fb287dc2ed087 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 1 Jun 2015 08:35:10 +0100 Subject: [PATCH 57/61] sna: Disable existing GTT mmap when switching to unknown swizzle + tiling As a consequence of using GPU swizzling without telling the kernel is that we must disable GTT access -- especially if we already have a linear mmapping. Signed-off-by: Chris Wilson --- src/sna/kgem.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/sna/kgem.c b/src/sna/kgem.c index e4960eac..9fc14a4e 100644 --- a/src/sna/kgem.c +++ b/src/sna/kgem.c @@ -562,7 +562,7 @@ static void *__kgem_bo_map__gtt(struct kgem *kgem, struct kgem_bo *bo) DBG(("%s(handle=%d, size=%d)\n", __FUNCTION__, bo->handle, bytes(bo))); - if (!kgem->can_fence) + if (bo->tiling && !kgem->can_fence) return NULL; VG_CLEAR(gtt); @@ -5100,6 +5100,16 @@ static void __kgem_bo_make_scanout(struct kgem *kgem, } } +static void set_gpu_tiling(struct kgem_bo *bo, int tiling, int pitch) +{ + bo->tiling = tiling; + bo->pitch = pitch; + if (tiling && bo->map__gtt) { + munmap(bo->map__gtt, bytes(bo)); + bo->map__gtt = NULL; + } +} + struct kgem_bo *kgem_create_2d(struct kgem *kgem, int width, int height, @@ -5280,8 +5290,7 @@ struct kgem_bo *kgem_create_2d(struct kgem *kgem, if (!kgem_set_tiling(kgem, bo, tiling, pitch)) { assert(!kgem->can_fence); - bo->tiling = tiling; - bo->pitch = pitch; + set_gpu_tiling(bo, tiling, pitch); } } @@ -5311,8 +5320,7 @@ large_inactive: if (!kgem_set_tiling(kgem, bo, tiling, pitch)) { if (kgem->gen >= 040) { assert(!kgem->can_fence); - bo->tiling = tiling; - bo->pitch = pitch; + set_gpu_tiling(bo, tiling, pitch); } else continue; } @@ -5460,8 +5468,7 @@ search_active: if (!kgem_set_tiling(kgem, bo, tiling, pitch)) { assert(!kgem->can_fence); - bo->tiling = tiling; - bo->pitch = pitch; + set_gpu_tiling(bo, tiling, pitch); } } assert(bo->tiling == tiling); @@ -5523,8 +5530,7 @@ search_active: if (!kgem_set_tiling(kgem, bo, tiling, pitch)) { if (kgem->gen >= 040) { assert(!kgem->can_fence); - bo->tiling = tiling; - bo->pitch = pitch; + set_gpu_tiling(bo, tiling, pitch); } else { kgem_bo_free(kgem, bo); break; @@ -5616,8 +5622,7 @@ search_inactive: if (!kgem_set_tiling(kgem, bo, tiling, pitch)) { if (kgem->gen >= 040) { assert(!kgem->can_fence); - bo->tiling = tiling; - bo->pitch = pitch; + set_gpu_tiling(bo, tiling, pitch); } else { kgem_bo_free(kgem, bo); break; @@ -5684,8 +5689,7 @@ search_inactive: if (!kgem_set_tiling(kgem, bo, tiling, pitch)) { if (kgem->gen >= 040) { assert(!kgem->can_fence); - bo->tiling = tiling; - bo->pitch = pitch; + set_gpu_tiling(bo, tiling, pitch); } else { kgem_bo_free(kgem, bo); goto no_retire; From d1479d8d03f2a1f2c2f0f3f89c5341c65e27d2d5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 1 Jun 2015 08:42:28 +0100 Subject: [PATCH 58/61] sna: Double check that a tiling change request results in a change Signed-off-by: Chris Wilson --- src/sna/sna_accel.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c index 9a5079f8..8f0326b8 100644 --- a/src/sna/sna_accel.c +++ b/src/sna/sna_accel.c @@ -683,6 +683,12 @@ struct kgem_bo *sna_pixmap_change_tiling(PixmapPtr pixmap, uint32_t tiling) return NULL; } + if (bo->tiling == priv->gpu_bo->tiling) { + DBG(("%s: tiling request failed\n", __FUNCTION__)); + kgem_bo_destroy(&sna->kgem, bo); + return NULL; + } + box.x1 = box.y1 = 0; box.x2 = pixmap->drawable.width; box.y2 = pixmap->drawable.height; From e08589de09b2e27b86321473efd4f29e57a18371 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 1 Jun 2015 08:54:19 +0100 Subject: [PATCH 59/61] sna: Disable tiling assertion with unknown swizzling and white lies Signed-off-by: Chris Wilson --- src/sna/kgem.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sna/kgem.c b/src/sna/kgem.c index 9fc14a4e..c3b848df 100644 --- a/src/sna/kgem.c +++ b/src/sna/kgem.c @@ -285,6 +285,9 @@ static void assert_tiling(struct kgem *kgem, struct kgem_bo *bo) assert(bo); + if (!kgem->can_fence && kgem->gen >= 040 && bo->tiling) + return; /* lies */ + VG_CLEAR(tiling); tiling.handle = bo->handle; tiling.tiling_mode = bo->tiling; From 085efe68177e252af127a9e7f1186c51e9d68c80 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 1 Jun 2015 08:59:30 +0100 Subject: [PATCH 60/61] sna: Force Linear FB when swizzling is unknown and fencing disabled Signed-off-by: Chris Wilson --- src/sna/sna_driver.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sna/sna_driver.c b/src/sna/sna_driver.c index b1011b74..de2bb770 100644 --- a/src/sna/sna_driver.c +++ b/src/sna/sna_driver.c @@ -619,6 +619,8 @@ static Bool sna_pre_init(ScrnInfoPtr scrn, int probe) if (xf86ReturnOptValBool(sna->Options, OPTION_TILING_FB, FALSE)) sna->flags |= SNA_LINEAR_FB; + if (!sna->kgem.can_fence) + sna->flags |= SNA_LINEAR_FB; if (!xf86ReturnOptValBool(sna->Options, OPTION_SWAPBUFFERS_WAIT, TRUE)) sna->flags |= SNA_NO_WAIT; From b792b2c0b8e6984a5a45b60e6502cb959db92ba8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 1 Jun 2015 09:08:52 +0100 Subject: [PATCH 61/61] sna/dri2+: The DRI2/DRI3 protocol requires fenced tiling If we export a surface over DRI2/DRI3, we have to use explicit tiling via the kernel. :( Signed-off-by: Chris Wilson --- src/sna/sna_dri2.c | 21 +++++++++++++++------ src/sna/sna_dri3.c | 9 +++++++++ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/sna/sna_dri2.c b/src/sna/sna_dri2.c index be33480a..3611270c 100644 --- a/src/sna/sna_dri2.c +++ b/src/sna/sna_dri2.c @@ -400,6 +400,9 @@ static uint32_t color_tiling(struct sna *sna, DrawablePtr draw) { uint32_t tiling; + if (!sna->kgem.can_fence) + return I915_TILING_NONE; + if (COLOR_PREFER_TILING_Y && (draw->width != sna->front->drawable.width || draw->height != sna->front->drawable.height)) @@ -427,7 +430,6 @@ static struct kgem_bo *sna_pixmap_set_dri(struct sna *sna, PixmapPtr pixmap) { struct sna_pixmap *priv; - int tiling; DBG(("%s: attaching DRI client to pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber)); @@ -451,11 +453,18 @@ static struct kgem_bo *sna_pixmap_set_dri(struct sna *sna, assert(priv->gpu_bo->proxy == NULL); assert(priv->gpu_bo->flush == false); - tiling = color_tiling(sna, &pixmap->drawable); - if (tiling < 0) - tiling = -tiling; - if (priv->gpu_bo->tiling < tiling && !priv->gpu_bo->scanout) - sna_pixmap_change_tiling(pixmap, tiling); + if (!sna->kgem.can_fence) { + if (!sna_pixmap_change_tiling(pixmap, I915_TILING_NONE)) { + DBG(("%s: failed to discard tiling (%d) for DRI2 protocol\n", __FUNCTION__, priv->gpu_bo->tiling)); + return NULL; + } + } else { + int tiling = color_tiling(sna, &pixmap->drawable); + if (tiling < 0) + tiling = -tiling; + if (priv->gpu_bo->tiling < tiling && !priv->gpu_bo->scanout) + sna_pixmap_change_tiling(pixmap, tiling); + } return priv->gpu_bo; } diff --git a/src/sna/sna_dri3.c b/src/sna/sna_dri3.c index ecfb6f30..1a2ba5dd 100644 --- a/src/sna/sna_dri3.c +++ b/src/sna/sna_dri3.c @@ -327,6 +327,15 @@ static int sna_dri3_fd_from_pixmap(ScreenPtr screen, return -1; } + if (bo->tiling && !sna->kgem.can_fence) { + if (!sna_pixmap_change_tiling(pixmap, I915_TILING_NONE)) { + DBG(("%s: unable to discard GPU tiling (%d) for DRI3 protocol\n", + __FUNCTION__, bo->tiling)); + return -1; + } + bo = priv->gpu_bo; + } + fd = kgem_bo_export_to_prime(&sna->kgem, bo); if (fd == -1) { DBG(("%s: exporting handle=%d to fd failed\n", __FUNCTION__, bo->handle));