freedreno: rework blit API
[mesa.git] / src / gallium / drivers / freedreno / a5xx / fd5_blitter.c
index 5769b7eb8f37531a226827b0e72de0afeaa2f60d..0cfe92ac22f5e9e979f769a11eb8e78c10377603 100644 (file)
@@ -52,6 +52,9 @@ ok_dims(const struct pipe_resource *r, const struct pipe_box *b, int lvl)
 static bool
 ok_format(enum pipe_format fmt)
 {
+       if (util_format_is_compressed(fmt))
+               return false;
+
        switch (fmt) {
        case PIPE_FORMAT_R10G10B10A2_SSCALED:
        case PIPE_FORMAT_R10G10B10A2_SNORM:
@@ -66,8 +69,13 @@ ok_format(enum pipe_format fmt)
        case PIPE_FORMAT_R10G10B10A2_UINT:
                return false;
        default:
-               return true;
+               break;
        }
+
+       if (fd5_pipe2color(fmt) == ~0)
+               return false;
+
+       return true;
 }
 
 static bool
@@ -85,6 +93,16 @@ can_do_blit(const struct pipe_blit_info *info)
        if (!ok_format(info->src.format))
                return false;
 
+       /* hw ignores {SRC,DST}_INFO.COLOR_SWAP if {SRC,DST}_INFO.TILE_MODE
+        * is set (not linear).  We can kind of get around that when tiling/
+        * untiling by setting both src and dst COLOR_SWAP=WZYX, but that
+        * means the formats must match:
+        */
+       if ((fd_resource(info->dst.resource)->tile_mode ||
+                               fd_resource(info->src.resource)->tile_mode) &&
+                       info->dst.format != info->src.format)
+               return false;
+
        /* until we figure out a few more registers: */
        if ((info->dst.box.width != info->src.box.width) ||
                        (info->dst.box.height != info->src.box.height))
@@ -128,12 +146,6 @@ can_do_blit(const struct pipe_blit_info *info)
        if (info->mask != util_format_get_mask(info->dst.format))
                return false;
 
-       if (util_format_is_compressed(info->dst.format))
-               return false;
-
-       if (util_format_is_compressed(info->src.format))
-               return false;
-
        return true;
 }
 
@@ -254,6 +266,7 @@ emit_blit_buffer(struct fd_ringbuffer *ring, const struct pipe_blit_info *info)
                 */
                OUT_PKT4(ring, REG_A5XX_RB_2D_SRC_INFO, 9);
                OUT_RING(ring, A5XX_RB_2D_SRC_INFO_COLOR_FORMAT(RB5_R8_UNORM) |
+                               A5XX_RB_2D_SRC_INFO_TILE_MODE(TILE5_LINEAR) |
                                A5XX_RB_2D_SRC_INFO_COLOR_SWAP(WZYX));
                OUT_RELOC(ring, src->bo, soff, 0, 0);    /* RB_2D_SRC_LO/HI */
                OUT_RING(ring, A5XX_RB_2D_SRC_SIZE_PITCH(p) |
@@ -273,6 +286,7 @@ emit_blit_buffer(struct fd_ringbuffer *ring, const struct pipe_blit_info *info)
                 */
                OUT_PKT4(ring, REG_A5XX_RB_2D_DST_INFO, 9);
                OUT_RING(ring, A5XX_RB_2D_DST_INFO_COLOR_FORMAT(RB5_R8_UNORM) |
+                               A5XX_RB_2D_DST_INFO_TILE_MODE(TILE5_LINEAR) |
                                A5XX_RB_2D_DST_INFO_COLOR_SWAP(WZYX));
                OUT_RELOCW(ring, dst->bo, doff, 0, 0);   /* RB_2D_DST_LO/HI */
                OUT_RING(ring, A5XX_RB_2D_DST_SIZE_PITCH(p) |
@@ -312,6 +326,7 @@ emit_blit(struct fd_ringbuffer *ring, const struct pipe_blit_info *info)
        struct fd_resource *src, *dst;
        struct fd_resource_slice *sslice, *dslice;
        enum a5xx_color_fmt sfmt, dfmt;
+       enum a5xx_tile_mode stile, dtile;
        enum a3xx_color_swap sswap, dswap;
        unsigned ssize, dsize, spitch, dpitch;
        unsigned sx1, sy1, sx2, sy2;
@@ -326,12 +341,27 @@ emit_blit(struct fd_ringbuffer *ring, const struct pipe_blit_info *info)
        sfmt = fd5_pipe2color(info->src.format);
        dfmt = fd5_pipe2color(info->dst.format);
 
+       stile = fd_resource_level_linear(info->src.resource, info->src.level) ?
+                       TILE5_LINEAR : src->tile_mode;
+       dtile = fd_resource_level_linear(info->dst.resource, info->dst.level) ?
+                       TILE5_LINEAR : dst->tile_mode;
+
        sswap = fd5_pipe2swap(info->src.format);
        dswap = fd5_pipe2swap(info->dst.format);
 
        spitch = sslice->pitch * src->cpp;
        dpitch = dslice->pitch * dst->cpp;
 
+       /* if dtile, then dswap ignored by hw, and likewise if stile then sswap
+        * ignored by hw.. but in this case we have already rejected the blit
+        * if src and dst formats differ, so juse use WZYX for both src and
+        * dst swap mode (so we don't change component order)
+        */
+       if (stile || dtile) {
+               debug_assert(info->src.format == info->dst.format);
+               sswap = dswap = WZYX;
+       }
+
        sx1 = sbox->x;
        sy1 = sbox->y;
        sx2 = sbox->x + sbox->width - 1;
@@ -367,6 +397,7 @@ emit_blit(struct fd_ringbuffer *ring, const struct pipe_blit_info *info)
                 */
                OUT_PKT4(ring, REG_A5XX_RB_2D_SRC_INFO, 9);
                OUT_RING(ring, A5XX_RB_2D_SRC_INFO_COLOR_FORMAT(sfmt) |
+                               A5XX_RB_2D_SRC_INFO_TILE_MODE(stile) |
                                A5XX_RB_2D_SRC_INFO_COLOR_SWAP(sswap));
                OUT_RELOC(ring, src->bo, soff, 0, 0);    /* RB_2D_SRC_LO/HI */
                OUT_RING(ring, A5XX_RB_2D_SRC_SIZE_PITCH(spitch) |
@@ -379,6 +410,7 @@ emit_blit(struct fd_ringbuffer *ring, const struct pipe_blit_info *info)
 
                OUT_PKT4(ring, REG_A5XX_GRAS_2D_SRC_INFO, 1);
                OUT_RING(ring, A5XX_GRAS_2D_SRC_INFO_COLOR_FORMAT(sfmt) |
+                               A5XX_GRAS_2D_SRC_INFO_TILE_MODE(stile) |
                                A5XX_GRAS_2D_SRC_INFO_COLOR_SWAP(sswap));
 
                /*
@@ -386,6 +418,7 @@ emit_blit(struct fd_ringbuffer *ring, const struct pipe_blit_info *info)
                 */
                OUT_PKT4(ring, REG_A5XX_RB_2D_DST_INFO, 9);
                OUT_RING(ring, A5XX_RB_2D_DST_INFO_COLOR_FORMAT(dfmt) |
+                               A5XX_RB_2D_DST_INFO_TILE_MODE(dtile) |
                                A5XX_RB_2D_DST_INFO_COLOR_SWAP(dswap));
                OUT_RELOCW(ring, dst->bo, doff, 0, 0);   /* RB_2D_DST_LO/HI */
                OUT_RING(ring, A5XX_RB_2D_DST_SIZE_PITCH(dpitch) |
@@ -398,6 +431,7 @@ emit_blit(struct fd_ringbuffer *ring, const struct pipe_blit_info *info)
 
                OUT_PKT4(ring, REG_A5XX_GRAS_2D_DST_INFO, 1);
                OUT_RING(ring, A5XX_GRAS_2D_DST_INFO_COLOR_FORMAT(dfmt) |
+                               A5XX_GRAS_2D_DST_INFO_TILE_MODE(dtile) |
                                A5XX_GRAS_2D_DST_INFO_COLOR_SWAP(dswap));
 
                /*
@@ -415,17 +449,16 @@ emit_blit(struct fd_ringbuffer *ring, const struct pipe_blit_info *info)
        }
 }
 
-void
+bool
 fd5_blitter_blit(struct fd_context *ctx, const struct pipe_blit_info *info)
 {
        struct fd_batch *batch;
 
        if (!can_do_blit(info)) {
-               fd_blitter_blit(ctx, info);
-               return;
+               return false;
        }
 
-       batch = fd_batch_create(ctx, true);
+       batch = fd_bc_alloc_batch(&ctx->screen->batch_cache, ctx, true);
 
        fd5_emit_restore(batch, batch->draw);
        fd5_emit_lrz_flush(batch->draw);
@@ -434,6 +467,8 @@ fd5_blitter_blit(struct fd_context *ctx, const struct pipe_blit_info *info)
 
        if ((info->src.resource->target == PIPE_BUFFER) &&
                        (info->dst.resource->target == PIPE_BUFFER)) {
+               assert(fd_resource(info->src.resource)->tile_mode == TILE5_LINEAR);
+               assert(fd_resource(info->dst.resource)->tile_mode == TILE5_LINEAR);
                emit_blit_buffer(batch->draw, info);
        } else {
                /* I don't *think* we need to handle blits between buffer <-> !buffer */
@@ -441,8 +476,23 @@ fd5_blitter_blit(struct fd_context *ctx, const struct pipe_blit_info *info)
                debug_assert(info->dst.resource->target != PIPE_BUFFER);
                emit_blit(batch->draw, info);
        }
+
        fd_resource(info->dst.resource)->valid = true;
        batch->needs_flush = true;
 
        fd_batch_flush(batch, false, false);
+
+       return true;
+}
+
+unsigned
+fd5_tile_mode(const struct pipe_resource *tmpl)
+{
+       /* basically just has to be a format we can blit, so uploads/downloads
+        * via linear staging buffer works:
+        */
+       if (ok_format(tmpl->format))
+               return TILE5_3;
+
+       return TILE5_LINEAR;
 }