+/**
+ * Re-written z/s blits can still fail for various reasons (for example MSAA).
+ * But we want to do the fallback blit with the re-written pipe_blit_info,
+ * in particular as u_blitter cannot blit stencil. So handle the fallback
+ * ourself and never "fail".
+ */
+static bool
+do_rewritten_blit(struct fd_context *ctx, const struct pipe_blit_info *info)
+{
+ bool success = handle_rgba_blit(ctx, info);
+ if (!success)
+ success = fd_blitter_blit(ctx, info);
+ debug_assert(success); /* fallback should never fail! */
+ return success;
+}
+
+/**
+ * Handle depth/stencil blits either via u_blitter and/or re-writing the
+ * blit into an equivilant format that we can handle
+ */
+static bool
+handle_zs_blit(struct fd_context *ctx, const struct pipe_blit_info *info)
+{
+ struct pipe_blit_info blit = *info;
+
+ if (DEBUG_BLIT) {
+ fprintf(stderr, "---- handle_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->dst.format) {
+ case PIPE_FORMAT_S8_UINT:
+ debug_assert(info->mask == PIPE_MASK_S);
+ blit.mask = PIPE_MASK_R;
+ blit.src.format = PIPE_FORMAT_R8_UINT;
+ blit.dst.format = PIPE_FORMAT_R8_UINT;
+ return do_rewritten_blit(ctx, &blit);
+
+ case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
+ if (info->mask & PIPE_MASK_Z) {
+ blit.mask = PIPE_MASK_R;
+ blit.src.format = PIPE_FORMAT_R32_FLOAT;
+ blit.dst.format = PIPE_FORMAT_R32_FLOAT;
+ do_rewritten_blit(ctx, &blit);
+ }
+
+ if (info->mask & PIPE_MASK_S) {
+ blit.mask = PIPE_MASK_R;
+ blit.src.format = PIPE_FORMAT_R8_UINT;
+ blit.dst.format = PIPE_FORMAT_R8_UINT;
+ blit.src.resource = &fd_resource(info->src.resource)->stencil->base;
+ blit.dst.resource = &fd_resource(info->dst.resource)->stencil->base;
+ do_rewritten_blit(ctx, &blit);
+ }
+
+ return true;
+
+ case PIPE_FORMAT_Z16_UNORM:
+ blit.mask = PIPE_MASK_R;
+ blit.src.format = PIPE_FORMAT_R16_UNORM;
+ blit.dst.format = PIPE_FORMAT_R16_UNORM;
+ return do_rewritten_blit(ctx, &blit);
+
+ case PIPE_FORMAT_Z32_UNORM:
+ case PIPE_FORMAT_Z32_FLOAT:
+ debug_assert(info->mask == PIPE_MASK_Z);
+ blit.mask = PIPE_MASK_R;
+ blit.src.format = PIPE_FORMAT_R32_UINT;
+ blit.dst.format = PIPE_FORMAT_R32_UINT;
+ return do_rewritten_blit(ctx, &blit);
+
+ case PIPE_FORMAT_Z24X8_UNORM:
+ case PIPE_FORMAT_Z24_UNORM_S8_UINT:
+ blit.mask = 0;
+ if (info->mask & PIPE_MASK_Z)
+ blit.mask |= PIPE_MASK_R | PIPE_MASK_G | PIPE_MASK_B;
+ if (info->mask & PIPE_MASK_S)
+ blit.mask |= PIPE_MASK_A;
+ blit.src.format = PIPE_FORMAT_Z24_UNORM_S8_UINT_AS_R8G8B8A8;
+ blit.dst.format = PIPE_FORMAT_Z24_UNORM_S8_UINT_AS_R8G8B8A8;
+ return fd_blitter_blit(ctx, &blit);
+
+ default:
+ return false;
+ }
+}
+
+static bool
+handle_compressed_blit(struct fd_context *ctx, const struct pipe_blit_info *info)
+{
+ struct pipe_blit_info blit = *info;
+
+ if (DEBUG_BLIT) {
+ fprintf(stderr, "---- handle_compressed_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");
+ }
+
+ if (info->src.format != info->dst.format)
+ return fd_blitter_blit(ctx, info);
+
+ if (util_format_get_blocksize(info->src.format) == 8) {
+ blit.src.format = blit.dst.format = PIPE_FORMAT_R16G16B16A16_UINT;
+ } else {
+ debug_assert(util_format_get_blocksize(info->src.format) == 16);
+ blit.src.format = blit.dst.format = PIPE_FORMAT_R32G32B32A32_UINT;
+ }
+
+ int bw = util_format_get_blockwidth(info->src.format);
+ int bh = util_format_get_blockheight(info->src.format);
+
+ /* NOTE: x/y *must* be aligned to block boundary (ie. in
+ * glCompressedTexSubImage2D()) but width/height may not
+ * be:
+ */
+
+ debug_assert((blit.src.box.x % bw) == 0);
+ debug_assert((blit.src.box.y % bh) == 0);
+
+ blit.src.box.x /= bw;
+ blit.src.box.y /= bh;
+ blit.src.box.width = DIV_ROUND_UP(blit.src.box.width, bw);
+ blit.src.box.height = DIV_ROUND_UP(blit.src.box.height, bh);
+
+ debug_assert((blit.dst.box.x % bw) == 0);
+ debug_assert((blit.dst.box.y % bh) == 0);
+
+ blit.dst.box.x /= bw;
+ blit.dst.box.y /= bh;
+ blit.dst.box.width = DIV_ROUND_UP(blit.dst.box.width, bw);
+ blit.dst.box.height = DIV_ROUND_UP(blit.dst.box.height, bh);
+
+ return do_rewritten_blit(ctx, &blit);
+}
+
+static bool
+fd6_blit(struct fd_context *ctx, const struct pipe_blit_info *info)