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); } 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/intel_module.c b/src/intel_module.c index bb744224..689c0dda 100644 --- a/src/intel_module.c +++ b/src/intel_module.c @@ -234,30 +234,36 @@ 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"}, + {0x22b1, "HD Graphics"}, + {0x22b2, "HD Graphics"}, + {0x22b3, "HD Graphics"}, /* When adding new identifiers, also update: * 1. intel_identify() @@ -508,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; 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/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 }, 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) diff --git a/src/sna/compiler.h b/src/sna/compiler.h index 44d17dbd..c7231370 100644 --- a/src/sna/compiler.h +++ b/src/sna/compiler.h @@ -63,20 +63,18 @@ #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, 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, 7) +#define avx2 fast __attribute__((target("avx2,avx,sse4.2,sse2,fpmath=sse"))) +#endif + +#if HAS_GCC(4, 5) && defined(__OPTIMIZE__) +#define fast_memcpy fast __attribute__((target("inline-all-stringops"))) #else #define fast_memcpy #endif diff --git a/src/sna/gen6_common.h b/src/sna/gen6_common.h index 409bab3b..898cda80 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; @@ -93,6 +96,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; @@ -104,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; @@ -112,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; @@ -127,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)) @@ -167,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)) @@ -188,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 7878e7bc..ca1f9c58 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)) @@ -2695,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 39f0d385..6c0e7f4f 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)) @@ -2893,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 ebabb2e5..660fc5a2 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); @@ -2002,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 @@ -2280,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)) @@ -2716,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 || @@ -3915,6 +3965,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 +4083,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/kgem.c b/src/sna/kgem.c index 05fe4070..c3b848df 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 @@ -222,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); @@ -278,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; @@ -315,16 +325,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; @@ -332,7 +434,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); @@ -340,22 +442,35 @@ 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; + 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; VG_CLEAR(set_tiling); restart: - set_tiling.handle = handle; + set_tiling.handle = bo->handle; set_tiling.tiling_mode = tiling; - set_tiling.stride = stride; + set_tiling.stride = tiling ? stride : 0; - if (ioctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling) == 0) - return true; + if (ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling) == 0) { + bo->tiling = set_tiling.tiling_mode; + bo->pitch = set_tiling.tiling_mode ? set_tiling.stride : stride; + return set_tiling.tiling_mode == tiling; + } err = errno; if (err == EINTR) @@ -450,6 +565,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 (bo->tiling && !kgem->can_fence) + return NULL; + VG_CLEAR(gtt); retry_gtt: gtt.handle = bo->handle; @@ -749,7 +867,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; } @@ -793,7 +911,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; } @@ -1244,6 +1362,72 @@ 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 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; @@ -1310,44 +1494,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 }; @@ -1410,6 +1556,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; @@ -1457,6 +1605,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); } @@ -1581,6 +1731,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; @@ -1593,6 +1762,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); @@ -1672,12 +1845,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 +2313,34 @@ 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++ = (BCS_SRC_Y | BCS_DST_Y) << 16; + + kgem->bcs_state = 0; +} + 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; @@ -2243,6 +2446,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); @@ -2284,6 +2488,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; @@ -2314,6 +2522,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); @@ -2409,6 +2618,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); @@ -2444,8 +2655,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 @@ -2649,9 +2859,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; @@ -2823,14 +3030,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); @@ -3686,13 +3887,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; @@ -3866,49 +4067,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; } @@ -3989,7 +4155,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; @@ -4004,7 +4171,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; @@ -4014,6 +4181,7 @@ bool kgem_expire_cache(struct kgem *kgem) break; } + assert(now); bo->delta = now; } if (expire) { @@ -4059,6 +4227,8 @@ bool kgem_expire_cache(struct kgem *kgem) break; } + assert(now); + kgem_bo_set_purgeable(kgem, bo); bo->delta = now; } } @@ -4093,12 +4263,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 @@ -4208,16 +4373,15 @@ retry_large: goto discard; if (bo->tiling != I915_TILING_NONE) { - if (use_active) + if (use_active && kgem->gen < 040) 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; } + assert(bo->tiling == I915_TILING_NONE); + bo->pitch = 0; if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) goto discard; @@ -4298,17 +4462,17 @@ discard: break; } - if (I915_TILING_NONE != bo->tiling && - !gem_set_tiling(kgem->fd, bo->handle, - 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)); assert(list_is_empty(&bo->list)); - bo->tiling = I915_TILING_NONE; - bo->pitch = 0; + 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))); @@ -4354,13 +4518,13 @@ discard: if (first) continue; - if (!gem_set_tiling(kgem->fd, bo->handle, - I915_TILING_NONE, 0)) - continue; - - bo->tiling = I915_TILING_NONE; - bo->pitch = 0; + if (!kgem_set_tiling(kgem, bo, I915_TILING_NONE, 0)) { + kgem_bo_free(kgem, bo); + break; + } } + assert(bo->tiling == I915_TILING_NONE); + bo->pitch = 0; if (bo->map__gtt || bo->map__wc || bo->map__cpu) { if (flags & (CREATE_CPU_MAP | CREATE_GTT_MAP)) { @@ -4398,7 +4562,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), @@ -4608,6 +4772,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; @@ -4889,8 +5055,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); @@ -4938,6 +5103,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, @@ -5021,8 +5196,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; @@ -5044,11 +5219,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; } @@ -5119,13 +5291,9 @@ struct kgem_bo *kgem_create_2d(struct kgem *kgem, if (num_pages(bo) < size) continue; - if (bo->pitch != pitch || bo->tiling != tiling) { - if (!gem_set_tiling(kgem->fd, bo->handle, - tiling, pitch)) - continue; - - bo->pitch = pitch; - bo->tiling = tiling; + if (!kgem_set_tiling(kgem, bo, tiling, pitch)) { + assert(!kgem->can_fence); + set_gpu_tiling(bo, tiling, pitch); } } @@ -5152,14 +5320,12 @@ large_inactive: if (size > num_pages(bo)) continue; - 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)) { + if (kgem->gen >= 040) { + assert(!kgem->can_fence); + set_gpu_tiling(bo, tiling, pitch); + } else continue; - - bo->tiling = tiling; - bo->pitch = pitch; } if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) { @@ -5171,7 +5337,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)); @@ -5220,14 +5385,13 @@ 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; + kgem_bo_free(kgem, bo); + break; } - bo->tiling = tiling; - bo->pitch = pitch; } if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) { @@ -5235,8 +5399,11 @@ large_inactive: break; } + if (tiling == I915_TILING_NONE) + bo->pitch = pitch; + assert(bo->tiling == tiling); - bo->pitch = pitch; + assert(bo->pitch >= pitch); bo->delta = 0; bo->unique_id = kgem_get_unique_id(kgem); @@ -5302,15 +5469,13 @@ 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 (!kgem_set_tiling(kgem, bo, tiling, pitch)) { + assert(!kgem->can_fence); + set_gpu_tiling(bo, tiling, pitch); } } + assert(bo->tiling == tiling); + assert(bo->pitch >= pitch); kgem_bo_remove_from_active(kgem, bo); @@ -5365,19 +5530,21 @@ search_active: if (num_pages(bo) < size) continue; - 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)) { + if (kgem->gen >= 040) { + assert(!kgem->can_fence); + set_gpu_tiling(bo, tiling, pitch); + } else { + kgem_bo_free(kgem, bo); + break; + } } + assert(bo->tiling == tiling); + assert(bo->pitch >= pitch); 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)); @@ -5455,11 +5622,14 @@ search_inactive: continue; } - 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)) { + if (kgem->gen >= 040) { + assert(!kgem->can_fence); + set_gpu_tiling(bo, tiling, pitch); + } else { + kgem_bo_free(kgem, bo); + break; + } } if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) { @@ -5470,9 +5640,8 @@ search_inactive: kgem_bo_remove_from_inactive(kgem, bo); assert(list_is_empty(&bo->list)); assert(list_is_empty(&bo->vma)); - - bo->pitch = pitch; - bo->tiling = tiling; + assert(bo->tiling == tiling); + assert(bo->pitch >= pitch); bo->delta = 0; bo->unique_id = kgem_get_unique_id(kgem); @@ -5520,14 +5689,18 @@ search_inactive: kgem_bo_remove_from_active(kgem, bo); __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)) { + if (kgem->gen >= 040) { + assert(!kgem->can_fence); + set_gpu_tiling(bo, tiling, pitch); + } else { kgem_bo_free(kgem, bo); goto no_retire; } } + assert(bo->tiling == tiling); + assert(bo->pitch >= pitch); - 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", @@ -5572,18 +5745,21 @@ 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; + if (kgem_set_tiling(kgem, bo, tiling, pitch)) { 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; + } } } @@ -5852,7 +6028,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) @@ -6114,6 +6290,55 @@ 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, *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)); + + 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 (kgem->bcs_state == state) + return; + + DBG(("%s: updating SWCTRL %x -> %x\n", __FUNCTION__, + 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) { + *b++ = MI_FLUSH_DW; + *b++ = 0; + *b++ = 0; + *b++ = 0; + } + *b++ = MI_LOAD_REGISTER_IMM; + *b++ = BCS_SWCTRL; + *b++ = (BCS_SRC_Y | BCS_DST_Y) << 16 | state; + kgem->nbatch = b - kgem->batch; + + kgem->bcs_state = state; +} + uint32_t kgem_add_reloc(struct kgem *kgem, uint32_t pos, struct kgem_bo *bo, @@ -6327,12 +6552,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); - } } } @@ -7619,6 +7838,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..9e6db0f2 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) @@ -188,7 +190,9 @@ 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; uint32_t can_scanout_y :1; @@ -232,7 +236,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) @@ -407,7 +411,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); @@ -429,7 +433,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; } @@ -573,7 +577,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 +592,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.h b/src/sna/sna.h index 51533995..8a405800 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 @@ -323,7 +322,8 @@ struct sna { uint32_t fg, bg; int size; - int active; + bool disable; + bool active; int last_x; int last_y; @@ -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_accel.c b/src/sna/sna_accel.c index f76447bd..8f0326b8 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 */ @@ -631,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 } @@ -691,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; @@ -825,8 +823,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; @@ -1648,7 +1646,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); @@ -2373,21 +2371,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); @@ -2936,17 +2939,22 @@ move_to_cpu: assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu)); } - assert(pixmap->devKind); - 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 || @@ -4089,7 +4097,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); @@ -5297,6 +5305,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 +5327,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 +5471,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 +5499,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, @@ -6871,18 +6883,22 @@ fallback: return; } - assert(dst_pixmap->devPrivate.ptr); - assert(dst_pixmap->devKind); - 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, @@ -6939,36 +6955,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__)); @@ -8341,6 +8360,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 +8428,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 +8579,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 +8696,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 +12307,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 +12451,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 +12520,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 +12617,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 +13247,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 +13360,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 +13418,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 +13491,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 +13622,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 +13667,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 +13731,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 +13862,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 +13924,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 +14055,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 +14116,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 +14256,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 +14382,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 +14546,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 +14692,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 +15415,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 +15503,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 +16138,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 +16248,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 +16588,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 +16610,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, @@ -17029,7 +17078,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); @@ -17038,6 +17087,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 || @@ -17054,6 +17104,7 @@ sna_get_image__fast(PixmapPtr pixmap, priv->clear_color); } + sigtrap_put(); return true; } diff --git a/src/sna/sna_blt.c b/src/sna/sna_blt.c index b62d7fd7..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)); @@ -129,7 +134,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 +187,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 +248,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) { @@ -295,6 +302,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); } @@ -338,8 +346,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 +386,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 +441,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; @@ -462,6 +472,7 @@ 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]); } assert(sna->kgem.mode == KGEM_BLT); @@ -590,6 +601,7 @@ 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]); } assert(sna->kgem.mode == KGEM_BLT); @@ -998,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, @@ -1017,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, @@ -1037,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, @@ -1058,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, @@ -1079,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, @@ -1431,6 +1448,7 @@ begin_blt(struct sna *sna, return false; _kgem_set_mode(&sna->kgem, KGEM_BLT); + kgem_bcs_set_tiling(&sna->kgem, NULL, op->dst.bo); } return true; @@ -1456,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; @@ -1466,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; @@ -1511,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; @@ -1695,6 +1713,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 +1770,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 +1853,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 +1912,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 +2022,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__)); @@ -2423,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; @@ -2434,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 @@ -2594,6 +2620,8 @@ clear: } if (hint & REPLACES) kgem_bo_undo(&sna->kgem, tmp->dst.bo); + if (flags & COMPOSITE_UPLOAD) + return false; } else { RegionRec region; @@ -2680,6 +2708,8 @@ fill: } if (hint & REPLACES) kgem_bo_undo(&sna->kgem, tmp->dst.bo); + if (flags & COMPOSITE_UPLOAD) + return false; } else { RegionRec region; @@ -2818,7 +2848,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; } @@ -2869,7 +2899,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; @@ -3046,6 +3076,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 +3418,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 +3525,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 +3615,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 +3762,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 +3823,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 +3881,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 +3943,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 +4001,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); } } @@ -4068,6 +4108,7 @@ 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); } assert(sna->kgem.mode == KGEM_BLT); @@ -4163,6 +4204,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; @@ -4210,6 +4252,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) @@ -4224,6 +4267,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) diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c index 6b2c3ef2..6ef07a97 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) { @@ -3871,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, @@ -4513,38 +4503,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; @@ -4600,7 +4558,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; } @@ -4685,17 +4643,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; } @@ -5264,6 +5216,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) { @@ -5288,7 +5262,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 +5270,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; @@ -5317,10 +5291,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 @@ -5363,7 +5344,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 +5352,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 +5445,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,11 +5501,13 @@ 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 && - 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); @@ -5537,9 +5520,20 @@ 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))); + /* 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,7 +5590,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; } @@ -5635,6 +5629,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; @@ -5824,7 +5821,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 +5835,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 +5849,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 +5860,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, @@ -5939,9 +5936,10 @@ 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, 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,13 +5951,14 @@ 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); return 0; } + fixup = 0; crtc_offset = crtc->base->y << 16 | crtc->base->x; if (bo->pitch != crtc->bo->pitch || crtc_offset != crtc->offset) { @@ -5968,6 +5967,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", @@ -5990,11 +5990,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 @@ -6011,7 +6008,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 +6016,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", @@ -6040,16 +6037,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", - crtc->id, crtc->pipe, 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; } @@ -6064,7 +6063,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 +6144,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 +6158,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 +6250,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 +6297,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 +6315,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; @@ -6490,6 +6489,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); @@ -7154,7 +7154,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)); @@ -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]; @@ -7206,7 +7207,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,13 +7219,30 @@ 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); +#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 @@ -7604,7 +7625,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 +7694,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 +7758,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 +7792,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 +7870,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 +7905,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 +7929,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 +7955,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 +8042,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 +8071,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 +8090,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 +8111,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 +8147,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 +8236,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 +8244,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 +8258,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 +8341,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..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; } @@ -870,6 +879,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 +965,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); } @@ -1312,8 +1340,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 +1519,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 +1713,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 +2165,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 +2615,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 +2732,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 +2872,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 +2934,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 +3201,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 +3209,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 +3243,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 +3252,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_dri3.c b/src/sna/sna_dri3.c index f586e242..1a2ba5dd 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); @@ -325,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)); diff --git a/src/sna/sna_driver.c b/src/sna/sna_driver.c index 488ca9b2..de2bb770 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; @@ -620,9 +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 (xf86ReturnOptValBool(sna->Options, OPTION_DELETE_DP12, FALSE)) - sna->flags |= SNA_REMOVE_OUTPUTS; + if (!sna->kgem.can_fence) + sna->flags |= SNA_LINEAR_FB; if (!xf86ReturnOptValBool(sna->Options, OPTION_SWAPBUFFERS_WAIT, TRUE)) sna->flags |= SNA_NO_WAIT; @@ -1220,13 +1218,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; } 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_io.c b/src/sna/sna_io.c index d6aa1294..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) @@ -281,6 +283,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) @@ -477,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; @@ -539,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 { @@ -597,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); } @@ -666,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); @@ -849,6 +859,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 || @@ -1038,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; @@ -1129,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); @@ -1224,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); @@ -1541,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; @@ -1636,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); @@ -1732,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); diff --git a/src/sna/sna_present.c b/src/sna/sna_present.c index 82f772f1..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; @@ -444,6 +477,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; } @@ -492,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)); @@ -540,6 +593,8 @@ flip(struct sna *sna, return FALSE; } + if (info->crtc) + sna_crtc_set_vblank(info->crtc); return TRUE; } @@ -560,7 +615,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; diff --git a/src/sna/sna_render.c b/src/sna/sna_render.c index 8a9c7f4c..a9945057 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; @@ -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; diff --git a/src/sna/sna_render.h b/src/sna/sna_render.h index f59a9283..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, @@ -540,7 +541,7 @@ enum { struct gen8_render_state { unsigned gt; - + const struct gt_info *info; struct kgem_bo *general_bo; uint32_t vs_state; 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..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)); @@ -2370,6 +2369,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..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); @@ -1013,6 +1037,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 +1059,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, @@ -1421,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; @@ -1470,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 f1532d31..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)); @@ -2386,6 +2385,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_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/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 */ 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); diff --git a/test/.gitignore b/test/.gitignore index da174be8..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 @@ -18,6 +19,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..50f2126a 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -12,8 +12,10 @@ stress_TESTS = \ DrawSegments \ cursor-test \ render-fill \ + render-glyphs \ render-trapezoid \ render-trapezoid-image \ + render-triangle \ render-fill-copy \ render-composite-solid \ render-composite-solid-mask \ 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); 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) { 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; } 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/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); 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; +} 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); 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); } } 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 diff --git a/tools/virtual.c b/tools/virtual.c index 850eb929..f5cba1a0 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,7 +1647,7 @@ 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; @@ -1652,11 +1655,24 @@ static void display_load_visible_cursor(struct display *display, XFixesCursorIma 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); + 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"); + } } } @@ -1700,6 +1716,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 +3423,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) {