sna/gen8: Check offset alignment before using a userptr for RENDER
authorChris Wilson <chris@chris-wilson.co.uk>
Fri, 6 Jun 2014 07:30:59 +0000 (08:30 +0100)
committerChris Wilson <chris@chris-wilson.co.uk>
Wed, 11 Jun 2014 10:05:27 +0000 (11:05 +0100)
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=79053
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
src/sna/gen8_render.c

index 3de9259..0cbfff9 100644 (file)
@@ -214,6 +214,35 @@ static inline bool too_large(int width, int height)
        return width > GEN8_MAX_SIZE || height > GEN8_MAX_SIZE;
 }
 
+static bool unaligned(struct kgem_bo *bo, int bpp)
+{
+       int x, y;
+
+       if (bo->proxy == NULL)
+               return false;
+
+       /* Assume that all tiled proxies are constructed correctly. */
+       if (bo->tiling)
+               return true;
+
+       DBG(("%s: checking alignment of a linear proxy, offset=%d, pitch=%d, bpp=%d: => (%d, %d)\n",
+            __FUNCTION__, bo->delta, bo->pitch, bpp,
+            8 * (bo->delta % bo->pitch) / bpp, bo->delta / bo->pitch));
+
+       /* This may be a random userptr map, check that it meets the
+        * render alignment of SURFACE_VALIGN_4 | SURFACE_HALIGN_4.
+        */
+       y = bo->delta / bo->pitch;
+       if (y & 3)
+               return false;
+
+       x = 8 * (bo->delta - y * bo->pitch);
+       if (x & (4*bpp - 1))
+           return false;
+
+       return true;
+}
+
 static uint32_t gen8_get_blend(int op,
                               bool has_component_alpha,
                               uint32_t dst_format)
@@ -1855,13 +1884,18 @@ gen8_composite_picture(struct sna *sna,
                                    x, y, w, h, dst_x, dst_y);
 }
 
-static void gen8_composite_channel_convert(struct sna_composite_channel *channel)
+static bool gen8_composite_channel_convert(struct sna_composite_channel *channel)
 {
+       if (unaligned(channel->bo, PICT_FORMAT_BPP(channel->pict_format)))
+               return false;
+
        channel->repeat = gen8_repeat(channel->repeat);
        channel->filter = gen8_filter(channel->filter);
        if (channel->card_format == (unsigned)-1)
                channel->card_format = gen8_get_card_format(channel->pict_format);
        assert(channel->card_format != (unsigned)-1);
+
+       return true;
 }
 
 static void gen8_render_composite_done(struct sna *sna,
@@ -1917,6 +1951,9 @@ gen8_composite_set_target(struct sna *sna,
        if (op->dst.bo == NULL)
                return false;
 
+       if (unaligned(op->dst.bo, dst->pDrawable->bitsPerPixel))
+               return false;
+
        get_drawable_deltas(dst->pDrawable, op->dst.pixmap,
                            &op->dst.x, &op->dst.y);
 
@@ -2247,13 +2284,16 @@ gen8_render_composite(struct sna *sna,
        case 1:
                /* Did we just switch rings to prepare the source? */
                if (mask == NULL &&
-                   prefer_blt_composite(sna, tmp) &&
+                   (prefer_blt_composite(sna, tmp) ||
+                    unaligned(tmp->src.bo, PICT_FORMAT_BPP(tmp->src.pict_format))) &&
                    sna_blt_composite__convert(sna,
                                               dst_x, dst_y, width, height,
                                               tmp))
                        return true;
 
-               gen8_composite_channel_convert(&tmp->src);
+               if (!gen8_composite_channel_convert(&tmp->src))
+                       goto cleanup_dst;
+
                break;
        }
 
@@ -2298,7 +2338,8 @@ gen8_render_composite(struct sna *sna,
                                        goto cleanup_src;
                                /* fall through to fixup */
                        case 1:
-                               gen8_composite_channel_convert(&tmp->mask);
+                               if (!gen8_composite_channel_convert(&tmp->mask))
+                                       goto cleanup_src;
                                break;
                        }
                }
@@ -2532,7 +2573,8 @@ gen8_render_composite_spans(struct sna *sna,
                        goto cleanup_dst;
                /* fall through to fixup */
        case 1:
-               gen8_composite_channel_convert(&tmp->base.src);
+               if (!gen8_composite_channel_convert(&tmp->base.src))
+                       goto cleanup_dst;
                break;
        }
        tmp->base.mask.bo = NULL;
@@ -2712,7 +2754,9 @@ gen8_render_copy_boxes(struct sna *sna, uint8_t alu,
                               box, n))
                return true;
 
-       if (!(alu == GXcopy || alu == GXclear)) {
+       if (!(alu == GXcopy || alu == GXclear) ||
+           unaligned(src_bo, src->drawable.bitsPerPixel) ||
+           unaligned(dst_bo, dst->drawable.bitsPerPixel)) {
 fallback_blt:
                DBG(("%s: fallback blt\n", __FUNCTION__));
                if (!sna_blt_compare_depth(&src->drawable, &dst->drawable))
@@ -2955,7 +2999,9 @@ gen8_render_copy(struct sna *sna, uint8_t alu,
 
        if (!(alu == GXcopy || alu == GXclear) || src_bo == dst_bo ||
            too_large(src->drawable.width, src->drawable.height) ||
-           too_large(dst->drawable.width, dst->drawable.height)) {
+           too_large(dst->drawable.width, dst->drawable.height) ||
+           unaligned(src_bo, src->drawable.bitsPerPixel) ||
+           unaligned(dst_bo, dst->drawable.bitsPerPixel)) {
 fallback:
                if (!sna_blt_compare_depth(&src->drawable, &dst->drawable))
                        return false;
@@ -3072,7 +3118,8 @@ gen8_render_fill_boxes(struct sna *sna,
        }
 
        if (prefer_blt_fill(sna, dst_bo, FILL_BOXES) ||
-           !gen8_check_dst_format(format)) {
+           !gen8_check_dst_format(format) ||
+           unaligned(dst_bo, PICT_FORMAT_BPP(format))) {
                uint8_t alu = GXinvalid;
 
                if (op <= PictOpSrc) {
@@ -3301,7 +3348,8 @@ gen8_render_fill(struct sna *sna, uint8_t alu,
                return true;
 
        if (!(alu == GXcopy || alu == GXclear) ||
-           too_large(dst->drawable.width, dst->drawable.height))
+           too_large(dst->drawable.width, dst->drawable.height) ||
+           unaligned(dst_bo, dst->drawable.bitsPerPixel))
                return sna_blt_fill(sna, alu,
                                    dst_bo, dst->drawable.bitsPerPixel,
                                    color,
@@ -3387,7 +3435,8 @@ gen8_render_fill_one(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo,
 
        /* Must use the BLT if we can't RENDER... */
        if (!(alu == GXcopy || alu == GXclear) ||
-           too_large(dst->drawable.width, dst->drawable.height))
+           too_large(dst->drawable.width, dst->drawable.height) ||
+           unaligned(bo, dst->drawable.bitsPerPixel))
                return gen8_render_fill_one_try_blt(sna, dst, bo, color,
                                                    x1, y1, x2, y2, alu);
 
@@ -3479,7 +3528,8 @@ gen8_render_clear(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo)
                return true;
 
        /* Must use the BLT if we can't RENDER... */
-       if (too_large(dst->drawable.width, dst->drawable.height))
+       if (too_large(dst->drawable.width, dst->drawable.height) ||
+           unaligned(bo, dst->drawable.bitsPerPixel))
                return gen8_render_clear_try_blt(sna, dst, bo);
 
        tmp.dst.pixmap = dst;
@@ -3673,6 +3723,9 @@ gen8_render_video(struct sna *sna,
             REGION_EXTENTS(NULL, dstRegion)->y2));
 
        assert(priv->gpu_bo);
+       assert(!too_large(pixmap->drawable.width, pixmap->drawable.height));
+       assert(!unaligned(priv->gpu_bo, pixmap->drawable.bitsPerPixel));
+
        memset(&tmp, 0, sizeof(tmp));
 
        tmp.dst.pixmap = pixmap;