freedreno/ir3: Push UBOs to constant file
[mesa.git] / src / gallium / drivers / freedreno / a6xx / fd6_blitter.c
index 13a5e4afb436b3d1167ca36a2ebef19502b5a5ad..f16eda744562a0d0a0e980502af28b20eb53fb68 100644 (file)
@@ -52,6 +52,33 @@ ok_dims(const struct pipe_resource *r, const struct pipe_box *b, int lvl)
                (b->z >= 0) && (b->z + b->depth <= last_layer);
 }
 
+static bool
+ok_format(enum pipe_format pfmt)
+{
+       enum a6xx_color_fmt fmt = fd6_pipe2color(pfmt);
+
+       switch (pfmt) {
+       case PIPE_FORMAT_Z24_UNORM_S8_UINT:
+       case PIPE_FORMAT_Z24X8_UNORM:
+       case PIPE_FORMAT_Z16_UNORM:
+       case PIPE_FORMAT_Z32_UNORM:
+       case PIPE_FORMAT_Z32_FLOAT:
+       case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
+       case PIPE_FORMAT_S8_UINT:
+               return true;
+       default:
+               break;
+       }
+
+       if (fmt == ~0)
+               return false;
+
+       if (fd6_ifmt(fmt) == 0)
+               return false;
+
+       return true;
+}
+
 #define DEBUG_BLIT_FALLBACK 0
 #define fail_if(cond)                                                                                                  \
        do {                                                                                                                            \
@@ -77,6 +104,10 @@ can_do_blit(const struct pipe_blit_info *info)
         */
        fail_if(info->dst.box.depth != info->src.box.depth);
 
+       /* Fail if unsupported format: */
+       fail_if(!ok_format(info->src.format));
+       fail_if(!ok_format(info->dst.format));
+
        /* We can blit if both or neither formats are compressed formats... */
        fail_if(util_format_is_compressed(info->src.format) !=
                        util_format_is_compressed(info->src.format));
@@ -85,18 +116,6 @@ can_do_blit(const struct pipe_blit_info *info)
        fail_if(util_format_is_compressed(info->src.format) &&
                        info->src.format != info->dst.format);
 
-       /* 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:
-        */
-       fail_if((fd_resource(info->dst.resource)->tile_mode ||
-                        fd_resource(info->src.resource)->tile_mode) &&
-                       info->dst.format != info->src.format);
-
-       /* src box can be inverted, which we don't support.. dst box cannot: */
-       fail_if((info->src.box.width < 0) || (info->src.box.height < 0));
-
        fail_if(!ok_dims(info->src.resource, &info->src.box, info->src.level));
 
        fail_if(!ok_dims(info->dst.resource, &info->dst.box, info->dst.level));
@@ -105,18 +124,47 @@ can_do_blit(const struct pipe_blit_info *info)
        debug_assert(info->dst.box.height >= 0);
        debug_assert(info->dst.box.depth >= 0);
 
-       fail_if(info->dst.resource->nr_samples + info->src.resource->nr_samples > 2);
+       /* We could probably blit between resources with equal sample count.. */
+       fail_if(info->dst.resource->nr_samples > 1);
+
+       /* CP_BLIT supports resolving, but seems to pick one only of the samples
+        * (no blending). This doesn't work for RGBA resolves, so we fall back in
+        * that case.  However, GL/GLES spec says:
+        *
+        *   "If the source formats are integer types or stencil values, a single
+        *    sample’s value is selected for each pixel. If the source formats are
+        *    floating-point or normalized types, the sample values for each pixel
+        *    are resolved in an implementationdependent manner. If the source
+        *    formats are depth values, sample values are resolved in an
+        *    implementation-dependent manner where the result will be between the
+        *    minimum and maximum depth values in the pixel."
+        *
+        * so do those with CP_BLIT.
+        */
+       fail_if((info->mask & PIPE_MASK_RGBA) &&
+                       info->src.resource->nr_samples > 1);
 
        fail_if(info->window_rectangle_include);
 
-       fail_if(info->render_condition_enable);
+       fail_if(util_format_is_srgb(info->src.format));
+       fail_if(util_format_is_srgb(info->dst.format));
+
+       const struct util_format_description *src_desc =
+               util_format_description(info->src.format);
+       const struct util_format_description *dst_desc =
+               util_format_description(info->dst.format);
+       const int common_channels = MIN2(src_desc->nr_channels, dst_desc->nr_channels);
+
+       if (info->mask & PIPE_MASK_RGBA) {
+               for (int i = 0; i < common_channels; i++) {
+                       fail_if(memcmp(&src_desc->channel[i],
+                                                  &dst_desc->channel[i],
+                                                  sizeof(src_desc->channel[0])));
+               }
+       }
 
        fail_if(info->alpha_blend);
 
-       fail_if(info->mask != util_format_get_mask(info->src.format));
-
-       fail_if(info->mask != util_format_get_mask(info->dst.format));
-
        return true;
 }
 
@@ -228,13 +276,15 @@ emit_blit_buffer(struct fd_ringbuffer *ring, const struct pipe_blit_info *info)
                /*
                 * Emit source:
                 */
-               OUT_PKT4(ring, REG_A6XX_SP_PS_2D_SRC_INFO, 13);
+               OUT_PKT4(ring, REG_A6XX_SP_PS_2D_SRC_INFO, 10);
                OUT_RING(ring, A6XX_SP_PS_2D_SRC_INFO_COLOR_FORMAT(RB6_R8_UNORM) |
-                               A6XX_SP_PS_2D_SRC_INFO_TILE_MODE(TILE6_LINEAR) |
-                                A6XX_SP_PS_2D_SRC_INFO_COLOR_SWAP(WZYX) | 0x500000);
+                               A6XX_SP_PS_2D_SRC_INFO_TILE_MODE(src->tile_mode) |
+                                A6XX_SP_PS_2D_SRC_INFO_COLOR_SWAP(WZYX) |
+                                COND(fd6_ubwc_enabled(src, src->tile_mode), A6XX_SP_PS_2D_SRC_INFO_FLAGS) |
+                                0x500000);
                OUT_RING(ring, A6XX_SP_PS_2D_SRC_SIZE_WIDTH(sshift + w) |
                                 A6XX_SP_PS_2D_SRC_SIZE_HEIGHT(1)); /* SP_PS_2D_SRC_SIZE */
-               OUT_RELOC(ring, src->bo, soff, 0, 0);    /* SP_PS_2D_SRC_LO/HI */
+               OUT_RELOC(ring, src->bo, soff + src->offset, 0, 0);    /* SP_PS_2D_SRC_LO/HI */
                OUT_RING(ring, A6XX_SP_PS_2D_SRC_PITCH_PITCH(p));
 
                OUT_RING(ring, 0x00000000);
@@ -243,18 +293,25 @@ emit_blit_buffer(struct fd_ringbuffer *ring, const struct pipe_blit_info *info)
                OUT_RING(ring, 0x00000000);
                OUT_RING(ring, 0x00000000);
 
-               OUT_RING(ring, 0x00000000);
-               OUT_RING(ring, 0x00000000);
-               OUT_RING(ring, 0x00000000);
+               if (fd6_ubwc_enabled(src, src->tile_mode)) {
+                       OUT_PKT4(ring, REG_A6XX_SP_PS_2D_SRC_FLAGS_LO, 6);
+                       OUT_RELOC(ring, src->bo, soff + src->ubwc_offset, 0, 0);
+                       OUT_RING(ring, A6XX_RB_MRT_FLAG_BUFFER_PITCH_PITCH(src->ubwc_pitch) |
+                                        A6XX_RB_MRT_FLAG_BUFFER_PITCH_ARRAY_PITCH(src->ubwc_size));
+                       OUT_RING(ring, 0x00000000);
+                       OUT_RING(ring, 0x00000000);
+                       OUT_RING(ring, 0x00000000);
+               }
 
                /*
                 * Emit destination:
                 */
                OUT_PKT4(ring, REG_A6XX_RB_2D_DST_INFO, 9);
                OUT_RING(ring, A6XX_RB_2D_DST_INFO_COLOR_FORMAT(RB6_R8_UNORM) |
-                                A6XX_RB_2D_DST_INFO_TILE_MODE(TILE6_LINEAR) |
-                                A6XX_RB_2D_DST_INFO_COLOR_SWAP(WZYX));
-               OUT_RELOC(ring, dst->bo, doff, 0, 0);    /* RB_2D_DST_LO/HI */
+                                A6XX_RB_2D_DST_INFO_TILE_MODE(dst->tile_mode) |
+                                A6XX_RB_2D_DST_INFO_COLOR_SWAP(WZYX) |
+                                COND(fd6_ubwc_enabled(dst, dst->tile_mode), A6XX_RB_2D_DST_INFO_FLAGS));
+               OUT_RELOC(ring, dst->bo, doff + dst->offset, 0, 0);    /* RB_2D_DST_LO/HI */
                OUT_RING(ring, A6XX_RB_2D_DST_SIZE_PITCH(p));
                OUT_RING(ring, 0x00000000);
                OUT_RING(ring, 0x00000000);
@@ -262,6 +319,15 @@ emit_blit_buffer(struct fd_ringbuffer *ring, const struct pipe_blit_info *info)
                OUT_RING(ring, 0x00000000);
                OUT_RING(ring, 0x00000000);
 
+               if (fd6_ubwc_enabled(dst, dst->tile_mode)) {
+                       OUT_PKT4(ring, REG_A6XX_RB_2D_DST_FLAGS_LO, 6);
+                       OUT_RELOC(ring, dst->bo, doff + dst->ubwc_offset, 0, 0);
+                       OUT_RING(ring, A6XX_RB_MRT_FLAG_BUFFER_PITCH_PITCH(dst->ubwc_pitch) |
+                                        A6XX_RB_MRT_FLAG_BUFFER_PITCH_ARRAY_PITCH(dst->ubwc_size));
+                       OUT_RING(ring, 0x00000000);
+                       OUT_RING(ring, 0x00000000);
+                       OUT_RING(ring, 0x00000000);
+               }
                /*
                 * Blit command:
                 */
@@ -279,13 +345,13 @@ emit_blit_buffer(struct fd_ringbuffer *ring, const struct pipe_blit_info *info)
                OUT_RING(ring, 0x3f);
                OUT_WFI5(ring);
 
-               OUT_PKT4(ring, 0x8c01, 1);
+               OUT_PKT4(ring, REG_A6XX_RB_UNKNOWN_8C01, 1);
                OUT_RING(ring, 0);
 
-               OUT_PKT4(ring, 0xacc0, 1);
+               OUT_PKT4(ring, REG_A6XX_SP_2D_SRC_FORMAT, 1);
                OUT_RING(ring, 0xf180);
 
-               OUT_PKT4(ring, 0x8e04, 1);
+               OUT_PKT4(ring, REG_A6XX_RB_UNKNOWN_8E04, 1);
                OUT_RING(ring, 0x01000000);
 
                OUT_PKT7(ring, CP_BLIT, 1);
@@ -293,7 +359,7 @@ emit_blit_buffer(struct fd_ringbuffer *ring, const struct pipe_blit_info *info)
 
                OUT_WFI5(ring);
 
-               OUT_PKT4(ring, 0x8e04, 1);
+               OUT_PKT4(ring, REG_A6XX_RB_UNKNOWN_8E04, 1);
                OUT_RING(ring, 0);
        }
 }
@@ -309,8 +375,8 @@ emit_blit_texture(struct fd_ringbuffer *ring, const struct pipe_blit_info *info)
        enum a6xx_tile_mode stile, dtile;
        enum a3xx_color_swap sswap, dswap;
        unsigned spitch, dpitch;
-       unsigned sx1, sy1, sx2, sy2;
-       unsigned dx1, dy1, dx2, dy2;
+       int sx1, sy1, sx2, sy2;
+       int dx1, dy1, dx2, dy2;
 
        if (DEBUG_BLIT_FALLBACK) {
                fprintf(stderr, "texture blit: ");
@@ -341,8 +407,8 @@ emit_blit_texture(struct fd_ringbuffer *ring, const struct pipe_blit_info *info)
        dtile = fd_resource_level_linear(info->dst.resource, info->dst.level) ?
                        TILE6_LINEAR : dst->tile_mode;
 
-       sswap = fd6_pipe2swap(info->src.format);
-       dswap = fd6_pipe2swap(info->dst.format);
+       sswap = stile ? WZYX : fd6_pipe2swap(info->src.format);
+       dswap = dtile ? WZYX : fd6_pipe2swap(info->dst.format);
 
        if (util_format_is_compressed(info->src.format)) {
                debug_assert(info->src.format == info->dst.format);
@@ -369,16 +435,6 @@ emit_blit_texture(struct fd_ringbuffer *ring, const struct pipe_blit_info *info)
        uint32_t width = DIV_ROUND_UP(u_minify(src->base.width0, info->src.level), blockwidth) * nelements;
        uint32_t height = DIV_ROUND_UP(u_minify(src->base.height0, info->src.level), blockheight);
 
-       /* 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;
-       }
-
        OUT_PKT7(ring, CP_SET_MARKER, 1);
        OUT_RING(ring, A2XX_CP_SET_MARKER_0_MODE(RM6_BLIT2DSCALE));
 
@@ -413,23 +469,35 @@ emit_blit_texture(struct fd_ringbuffer *ring, const struct pipe_blit_info *info)
                if (info->filter == PIPE_TEX_FILTER_LINEAR)
                        filter = A6XX_SP_PS_2D_SRC_INFO_FILTER;
 
-               OUT_PKT4(ring, REG_A6XX_SP_PS_2D_SRC_INFO, 13);
+               enum a3xx_msaa_samples samples = fd_msaa_samples(src->base.nr_samples);
+
+               OUT_PKT4(ring, REG_A6XX_SP_PS_2D_SRC_INFO, 10);
                OUT_RING(ring, A6XX_SP_PS_2D_SRC_INFO_COLOR_FORMAT(sfmt) |
                                A6XX_SP_PS_2D_SRC_INFO_TILE_MODE(stile) |
-                               A6XX_SP_PS_2D_SRC_INFO_COLOR_SWAP(sswap) | 0x500000 | filter);
+                               A6XX_SP_PS_2D_SRC_INFO_COLOR_SWAP(sswap) |
+                                A6XX_SP_PS_2D_SRC_INFO_SAMPLES(samples) |
+                                COND(fd6_ubwc_enabled(src, stile), A6XX_SP_PS_2D_SRC_INFO_FLAGS) |
+                                0x500000 | filter);
                OUT_RING(ring, A6XX_SP_PS_2D_SRC_SIZE_WIDTH(width) |
                                 A6XX_SP_PS_2D_SRC_SIZE_HEIGHT(height)); /* SP_PS_2D_SRC_SIZE */
-               OUT_RELOC(ring, src->bo, soff, 0, 0);    /* SP_PS_2D_SRC_LO/HI */
+               OUT_RELOC(ring, src->bo, soff + src->offset, 0, 0);    /* SP_PS_2D_SRC_LO/HI */
                OUT_RING(ring, A6XX_SP_PS_2D_SRC_PITCH_PITCH(spitch));
+
                OUT_RING(ring, 0x00000000);
                OUT_RING(ring, 0x00000000);
                OUT_RING(ring, 0x00000000);
                OUT_RING(ring, 0x00000000);
                OUT_RING(ring, 0x00000000);
 
-               OUT_RING(ring, 0x00000000);
-               OUT_RING(ring, 0x00000000);
-               OUT_RING(ring, 0x00000000);
+               if (fd6_ubwc_enabled(src, stile)) {
+                       OUT_PKT4(ring, REG_A6XX_SP_PS_2D_SRC_FLAGS_LO, 6);
+                       OUT_RELOC(ring, src->bo, soff + src->ubwc_offset, 0, 0);
+                       OUT_RING(ring, A6XX_RB_MRT_FLAG_BUFFER_PITCH_PITCH(src->ubwc_pitch) |
+                                        A6XX_RB_MRT_FLAG_BUFFER_PITCH_ARRAY_PITCH(src->ubwc_size));
+                       OUT_RING(ring, 0x00000000);
+                       OUT_RING(ring, 0x00000000);
+                       OUT_RING(ring, 0x00000000);
+               }
 
                /*
                 * Emit destination:
@@ -437,8 +505,9 @@ emit_blit_texture(struct fd_ringbuffer *ring, const struct pipe_blit_info *info)
                OUT_PKT4(ring, REG_A6XX_RB_2D_DST_INFO, 9);
                OUT_RING(ring, A6XX_RB_2D_DST_INFO_COLOR_FORMAT(dfmt) |
                                 A6XX_RB_2D_DST_INFO_TILE_MODE(dtile) |
-                                A6XX_RB_2D_DST_INFO_COLOR_SWAP(dswap));
-               OUT_RELOC(ring, dst->bo, doff, 0, 0);    /* RB_2D_DST_LO/HI */
+                                A6XX_RB_2D_DST_INFO_COLOR_SWAP(dswap) |
+                                COND(fd6_ubwc_enabled(dst, dtile), A6XX_RB_2D_DST_INFO_FLAGS));
+               OUT_RELOCW(ring, dst->bo, doff + dst->offset, 0, 0);    /* RB_2D_DST_LO/HI */
                OUT_RING(ring, A6XX_RB_2D_DST_SIZE_PITCH(dpitch));
                OUT_RING(ring, 0x00000000);
                OUT_RING(ring, 0x00000000);
@@ -446,6 +515,15 @@ emit_blit_texture(struct fd_ringbuffer *ring, const struct pipe_blit_info *info)
                OUT_RING(ring, 0x00000000);
                OUT_RING(ring, 0x00000000);
 
+               if (fd6_ubwc_enabled(dst, dtile)) {
+                       OUT_PKT4(ring, REG_A6XX_RB_2D_DST_FLAGS_LO, 6);
+                       OUT_RELOC(ring, dst->bo, doff + dst->ubwc_offset, 0, 0);
+                       OUT_RING(ring, A6XX_RB_MRT_FLAG_BUFFER_PITCH_PITCH(dst->ubwc_pitch) |
+                                        A6XX_RB_MRT_FLAG_BUFFER_PITCH_ARRAY_PITCH(dst->ubwc_size));
+                       OUT_RING(ring, 0x00000000);
+                       OUT_RING(ring, 0x00000000);
+                       OUT_RING(ring, 0x00000000);
+               }
                /*
                 * Blit command:
                 */
@@ -463,13 +541,25 @@ emit_blit_texture(struct fd_ringbuffer *ring, const struct pipe_blit_info *info)
                OUT_RING(ring, 0x3f);
                OUT_WFI5(ring);
 
-               OUT_PKT4(ring, 0x8c01, 1);
+               OUT_PKT4(ring, REG_A6XX_RB_UNKNOWN_8C01, 1);
                OUT_RING(ring, 0);
 
-               OUT_PKT4(ring, 0xacc0, 1);
-               OUT_RING(ring, 0xf180);
-
-               OUT_PKT4(ring, 0x8e04, 1);
+               OUT_PKT4(ring, REG_A6XX_SP_2D_SRC_FORMAT, 1);
+               OUT_RING(ring, A6XX_SP_2D_SRC_FORMAT_COLOR_FORMAT(sfmt) |
+                               COND(util_format_is_pure_sint(info->src.format),
+                                               A6XX_SP_2D_SRC_FORMAT_SINT) |
+                               COND(util_format_is_pure_uint(info->src.format),
+                                               A6XX_SP_2D_SRC_FORMAT_UINT) |
+                               COND(util_format_is_snorm(info->src.format),
+                                               A6XX_SP_2D_SRC_FORMAT_SINT |
+                                               A6XX_SP_2D_SRC_FORMAT_NORM) |
+                               COND(util_format_is_unorm(info->src.format),
+// TODO sometimes blob uses UINT+NORM but dEQP seems unhappy about that
+//                                             A6XX_SP_2D_SRC_FORMAT_UINT |
+                                               A6XX_SP_2D_SRC_FORMAT_NORM) |
+                               0xf000);
+
+               OUT_PKT4(ring, REG_A6XX_RB_UNKNOWN_8E04, 1);
                OUT_RING(ring, 0x01000000);
 
                OUT_PKT7(ring, CP_BLIT, 1);
@@ -477,25 +567,135 @@ emit_blit_texture(struct fd_ringbuffer *ring, const struct pipe_blit_info *info)
 
                OUT_WFI5(ring);
 
-               OUT_PKT4(ring, 0x8e04, 1);
+               OUT_PKT4(ring, REG_A6XX_RB_UNKNOWN_8E04, 1);
                OUT_RING(ring, 0);
        }
 }
 
 static void
-fd6_blit(struct pipe_context *pctx, const struct pipe_blit_info *info)
+rewrite_zs_blit(struct fd_ringbuffer *ring, const struct pipe_blit_info *info)
+{
+       struct pipe_blit_info separate = *info;
+
+       if (DEBUG_BLIT_FALLBACK) {
+               fprintf(stderr, "---- rewrite_separate_zs_blit: ");
+               util_dump_blit_info(stderr, info);
+               fprintf(stderr, "\ndst resource: ");
+               util_dump_resource(stderr, info->dst.resource);
+               fprintf(stderr, "\nsrc resource: ");
+               util_dump_resource(stderr, info->src.resource);
+               fprintf(stderr, "\n\n");
+       }
+
+       switch (info->src.format) {
+       case PIPE_FORMAT_S8_UINT:
+               debug_assert(info->mask == PIPE_MASK_S);
+               separate.mask = PIPE_MASK_R;
+               separate.src.format = PIPE_FORMAT_R8_UINT;
+               separate.dst.format = PIPE_FORMAT_R8_UINT;
+               emit_blit_texture(ring, &separate);
+               break;
+
+       case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
+               if (info->mask & PIPE_MASK_Z) {
+                       separate.mask = PIPE_MASK_R;
+                       separate.src.format = PIPE_FORMAT_R32_FLOAT;
+                       separate.dst.format = PIPE_FORMAT_R32_FLOAT;
+                       emit_blit_texture(ring, &separate);
+               }
+               if (info->mask & PIPE_MASK_S) {
+                       separate.mask = PIPE_MASK_R;
+                       separate.src.format = PIPE_FORMAT_R8_UINT;
+                       separate.dst.format = PIPE_FORMAT_R8_UINT;
+                       separate.src.resource = &fd_resource(info->src.resource)->stencil->base;
+                       separate.dst.resource = &fd_resource(info->dst.resource)->stencil->base;
+                       emit_blit_texture(ring, &separate);
+               }
+               break;
+
+       case PIPE_FORMAT_Z16_UNORM:
+               separate.mask = PIPE_MASK_R;
+               separate.src.format = PIPE_FORMAT_R16_UNORM;
+               separate.dst.format = PIPE_FORMAT_R16_UNORM;
+               emit_blit_texture(ring, &separate);
+               break;
+
+       case PIPE_FORMAT_Z32_UNORM:
+       case PIPE_FORMAT_Z32_FLOAT:
+               debug_assert(info->mask == PIPE_MASK_Z);
+               separate.mask = PIPE_MASK_R;
+               separate.src.format = PIPE_FORMAT_R32_UINT;
+               separate.dst.format = PIPE_FORMAT_R32_UINT;
+               emit_blit_texture(ring, &separate);
+               break;
+
+       case PIPE_FORMAT_Z24_UNORM_S8_UINT:
+               debug_assert(info->mask == PIPE_MASK_ZS);
+       case PIPE_FORMAT_Z24X8_UNORM:
+       case PIPE_FORMAT_X8Z24_UNORM:
+               separate.mask = PIPE_MASK_R;
+               separate.src.format = PIPE_FORMAT_R32_UINT;
+               separate.dst.format = PIPE_FORMAT_R32_UINT;
+               emit_blit_texture(ring, &separate);
+               break;
+
+       default:
+               unreachable("");
+       }
+}
+
+static void
+rewrite_combined_zs_blit(struct fd_context *ctx, const struct pipe_blit_info *info)
+{
+       struct pipe_blit_info separate = *info;
+
+       if (DEBUG_BLIT_FALLBACK) {
+               fprintf(stderr, "---- rewrite_combined_zs_blit: ");
+               util_dump_blit_info(stderr, info);
+               fprintf(stderr, "\ndst resource: ");
+               util_dump_resource(stderr, info->dst.resource);
+               fprintf(stderr, "\nsrc resource: ");
+               util_dump_resource(stderr, info->src.resource);
+               fprintf(stderr, "\n");
+       }
+
+       switch (info->mask) {
+       case PIPE_MASK_Z:
+               separate.mask = PIPE_MASK_R | PIPE_MASK_G | PIPE_MASK_B;
+               separate.src.format = PIPE_FORMAT_R8G8B8A8_UNORM;
+               separate.dst.format = PIPE_FORMAT_R8G8B8A8_UNORM;
+
+               fd_blitter_blit(ctx, &separate);
+               break;
+
+       case PIPE_MASK_S:
+               separate.mask = PIPE_MASK_A;
+               separate.src.format = PIPE_FORMAT_R8G8B8A8_UNORM;
+               separate.dst.format = PIPE_FORMAT_R8G8B8A8_UNORM;
+
+               fd_blitter_blit(ctx, &separate);
+               break;
+
+       default:
+               unreachable("");
+       }
+}
+
+static bool
+fd6_blit(struct fd_context *ctx, const struct pipe_blit_info *info)
 {
-       struct fd_context *ctx = fd_context(pctx);
        struct fd_batch *batch;
 
-       if (!can_do_blit(info)) {
-               fd_blitter_pipe_begin(ctx, info->render_condition_enable, false, FD_STAGE_BLIT);
-               fd_blitter_blit(ctx, info);
-               fd_blitter_pipe_end(ctx);
-               return;
+       if (info->dst.format == PIPE_FORMAT_Z24_UNORM_S8_UINT &&
+               info->mask != PIPE_MASK_ZS)  {
+               rewrite_combined_zs_blit(ctx, info);
+               return true;
        }
 
-       fd_fence_ref(pctx->screen, &ctx->last_fence, NULL);
+       if (!can_do_blit(info))
+               return false;
+
+       fd_fence_ref(ctx->base.screen, &ctx->last_fence, NULL);
 
        batch = fd_bc_alloc_batch(&ctx->screen->batch_cache, ctx, true);
 
@@ -520,7 +720,12 @@ fd6_blit(struct pipe_context *pctx, const struct pipe_blit_info *info)
                /* I don't *think* we need to handle blits between buffer <-> !buffer */
                debug_assert(info->src.resource->target != PIPE_BUFFER);
                debug_assert(info->dst.resource->target != PIPE_BUFFER);
-               emit_blit_texture(batch->draw, info);
+
+               if (info->mask & (PIPE_MASK_ZS)) {
+                       rewrite_zs_blit(batch->draw, info);
+               } else {
+                       emit_blit_texture(batch->draw, info);
+               }
        }
 
        fd6_event_write(batch, batch->draw, 0x1d, true);
@@ -532,42 +737,8 @@ fd6_blit(struct pipe_context *pctx, const struct pipe_blit_info *info)
 
        fd_batch_flush(batch, false, false);
        fd_batch_reference(&batch, NULL);
-}
 
-static void
-fd6_resource_copy_region(struct pipe_context *pctx,
-               struct pipe_resource *dst,
-               unsigned dst_level,
-               unsigned dstx, unsigned dsty, unsigned dstz,
-               struct pipe_resource *src,
-               unsigned src_level,
-               const struct pipe_box *src_box)
-{
-       struct pipe_blit_info info;
-
-       debug_assert(src->format == dst->format);
-
-       memset(&info, 0, sizeof info);
-       info.dst.resource = dst;
-       info.dst.level = dst_level;
-       info.dst.box.x = dstx;
-       info.dst.box.y = dsty;
-       info.dst.box.z = dstz;
-       info.dst.box.width = src_box->width;
-       info.dst.box.height = src_box->height;
-       assert(info.dst.box.width >= 0);
-       assert(info.dst.box.height >= 0);
-       info.dst.box.depth = 1;
-       info.dst.format = dst->format;
-       info.src.resource = src;
-       info.src.level = src_level;
-       info.src.box = *src_box;
-       info.src.format = src->format;
-       info.mask = util_format_get_mask(src->format);
-       info.filter = PIPE_TEX_FILTER_NEAREST;
-       info.scissor_enable = 0;
-
-       fd6_blit(pctx, &info);
+       return true;
 }
 
 void
@@ -576,8 +747,7 @@ fd6_blitter_init(struct pipe_context *pctx)
        if (fd_mesa_debug & FD_DBG_NOBLIT)
                return;
 
-       pctx->resource_copy_region = fd6_resource_copy_region;
-       pctx->blit = fd6_blit;
+       fd_context(pctx)->blit = fd6_blit;
 }
 
 unsigned
@@ -586,5 +756,8 @@ fd6_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:
         */
-       return TILE6_3;
+       if (ok_format(tmpl->format))
+               return TILE6_3;
+
+       return TILE6_LINEAR;
 }