Mesa (master): panfrost: Import staging routines from freedreno
GitLab Mirror
gitlab-mirror at kemper.freedesktop.org
Wed Aug 12 14:16:32 UTC 2020
Module: Mesa
Branch: master
Commit: c54d45dd90a0606a9287bdcc03fd2463e47039a2
URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=c54d45dd90a0606a9287bdcc03fd2463e47039a2
Author: Alyssa Rosenzweig <alyssa.rosenzweig at collabora.com>
Date: Tue Jul 21 12:57:25 2020 -0400
panfrost: Import staging routines from freedreno
For software access to AFBC textures.
Signed-off-by: Alyssa Rosenzweig <alyssa.rosenzweig at collabora.com>
Tested-by: Icecream95 <ixn at keemail.me>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6159>
---
src/gallium/drivers/panfrost/pan_resource.c | 151 ++++++++++++++++++++++++----
src/gallium/drivers/panfrost/pan_resource.h | 4 +
2 files changed, 136 insertions(+), 19 deletions(-)
diff --git a/src/gallium/drivers/panfrost/pan_resource.c b/src/gallium/drivers/panfrost/pan_resource.c
index 614c22f67de..8226b4b3c3e 100644
--- a/src/gallium/drivers/panfrost/pan_resource.c
+++ b/src/gallium/drivers/panfrost/pan_resource.c
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2008 VMware, Inc.
- * Copyright (C) 2014 Broadcom
+ * Copyright (C) 2012 Rob Clark <robclark at freedesktop.org>
+ * Copyright (C) 2014-2017 Broadcom
* Copyright (C) 2018-2019 Alyssa Rosenzweig
* Copyright (C) 2019 Collabora, Ltd.
*
@@ -597,6 +598,81 @@ panfrost_resource_destroy(struct pipe_screen *screen,
ralloc_free(rsrc);
}
+/* Most of the time we can do CPU-side transfers, but sometimes we need to use
+ * the 3D pipe for this. Let's wrap u_blitter to blit to/from staging textures.
+ * Code adapted from freedreno */
+
+static struct panfrost_resource *
+pan_alloc_staging(struct panfrost_context *ctx, struct panfrost_resource *rsc,
+ unsigned level, const struct pipe_box *box)
+{
+ struct pipe_context *pctx = &ctx->base;
+ struct pipe_resource tmpl = rsc->base;
+
+ tmpl.width0 = box->width;
+ tmpl.height0 = box->height;
+ /* for array textures, box->depth is the array_size, otherwise
+ * for 3d textures, it is the depth:
+ */
+ if (tmpl.array_size > 1) {
+ if (tmpl.target == PIPE_TEXTURE_CUBE)
+ tmpl.target = PIPE_TEXTURE_2D_ARRAY;
+ tmpl.array_size = box->depth;
+ tmpl.depth0 = 1;
+ } else {
+ tmpl.array_size = 1;
+ tmpl.depth0 = box->depth;
+ }
+ tmpl.last_level = 0;
+ tmpl.bind |= PIPE_BIND_LINEAR;
+
+ struct pipe_resource *pstaging =
+ pctx->screen->resource_create(pctx->screen, &tmpl);
+ if (!pstaging)
+ return NULL;
+
+ return pan_resource(pstaging);
+}
+
+static void
+pan_blit_from_staging(struct pipe_context *pctx, struct panfrost_gtransfer *trans)
+{
+ struct pipe_resource *dst = trans->base.resource;
+ struct pipe_blit_info blit = {};
+
+ blit.dst.resource = dst;
+ blit.dst.format = dst->format;
+ blit.dst.level = trans->base.level;
+ blit.dst.box = trans->base.box;
+ blit.src.resource = trans->staging.rsrc;
+ blit.src.format = trans->staging.rsrc->format;
+ blit.src.level = 0;
+ blit.src.box = trans->staging.box;
+ blit.mask = util_format_get_mask(trans->staging.rsrc->format);
+ blit.filter = PIPE_TEX_FILTER_NEAREST;
+
+ panfrost_blit(pctx, &blit);
+}
+
+static void
+pan_blit_to_staging(struct pipe_context *pctx, struct panfrost_gtransfer *trans)
+{
+ struct pipe_resource *src = trans->base.resource;
+ struct pipe_blit_info blit = {};
+
+ blit.src.resource = src;
+ blit.src.format = src->format;
+ blit.src.level = trans->base.level;
+ blit.src.box = trans->base.box;
+ blit.dst.resource = trans->staging.rsrc;
+ blit.dst.format = trans->staging.rsrc->format;
+ blit.dst.level = 0;
+ blit.dst.box = trans->staging.box;
+ blit.mask = util_format_get_mask(trans->staging.rsrc->format);
+ blit.filter = PIPE_TEX_FILTER_NEAREST;
+
+ panfrost_blit(pctx, &blit);
+}
static void *
panfrost_transfer_map(struct pipe_context *pctx,
@@ -612,15 +688,48 @@ panfrost_transfer_map(struct pipe_context *pctx,
int bytes_per_pixel = util_format_get_blocksize(rsrc->internal_format);
struct panfrost_bo *bo = rsrc->bo;
+ /* Can't map tiled/compressed directly */
+ if ((usage & PIPE_TRANSFER_MAP_DIRECTLY) && rsrc->modifier != DRM_FORMAT_MOD_LINEAR)
+ return NULL;
+
struct panfrost_gtransfer *transfer = rzalloc(pctx, struct panfrost_gtransfer);
transfer->base.level = level;
transfer->base.usage = usage;
transfer->base.box = *box;
pipe_resource_reference(&transfer->base.resource, resource);
-
*out_transfer = &transfer->base;
+ /* We don't have s/w routines for AFBC, so use a staging texture */
+ if (drm_is_afbc(rsrc->modifier)) {
+ struct panfrost_resource *staging = pan_alloc_staging(ctx, rsrc, level, box);
+ transfer->base.stride = staging->slices[0].stride;
+ transfer->base.layer_stride = transfer->base.stride * box->height;
+
+ transfer->staging.rsrc = &staging->base;
+
+ transfer->staging.box = *box;
+ transfer->staging.box.x = 0;
+ transfer->staging.box.y = 0;
+ transfer->staging.box.z = 0;
+
+ assert(transfer->staging.rsrc != NULL);
+
+ /* TODO: Eliminate this flush. It's only there to determine if
+ * we're initialized or not, when the initialization could come
+ * from a pending batch XXX */
+ panfrost_flush_batches_accessing_bo(ctx, rsrc->bo, true);
+
+ if ((usage & PIPE_TRANSFER_READ) && rsrc->slices[level].initialized) {
+ pan_blit_to_staging(pctx, transfer);
+ panfrost_flush_batches_accessing_bo(ctx, staging->bo, true);
+ panfrost_bo_wait(staging->bo, INT64_MAX, false);
+ }
+
+ panfrost_bo_mmap(staging->bo);
+ return staging->bo->cpu;
+ }
+
/* If we haven't already mmaped, now's the time */
panfrost_bo_mmap(bo);
@@ -699,33 +808,26 @@ panfrost_transfer_map(struct pipe_context *pctx,
}
}
- if (rsrc->modifier != DRM_FORMAT_MOD_LINEAR) {
- /* Non-linear resources need to be indirectly mapped */
-
- if (usage & PIPE_TRANSFER_MAP_DIRECTLY)
- return NULL;
-
+ if (rsrc->modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED) {
transfer->base.stride = box->width * bytes_per_pixel;
transfer->base.layer_stride = transfer->base.stride * box->height;
transfer->map = ralloc_size(transfer, transfer->base.layer_stride * box->depth);
assert(box->depth == 1);
if ((usage & PIPE_TRANSFER_READ) && rsrc->slices[level].initialized) {
- if (drm_is_afbc(rsrc->modifier)) {
- unreachable("Unimplemented: reads from AFBC");
- } else if (rsrc->modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED) {
- panfrost_load_tiled_image(
+ panfrost_load_tiled_image(
transfer->map,
bo->cpu + rsrc->slices[level].offset,
box->x, box->y, box->width, box->height,
transfer->base.stride,
rsrc->slices[level].stride,
rsrc->internal_format);
- }
}
return transfer->map;
} else {
+ assert (rsrc->modifier == DRM_FORMAT_MOD_LINEAR);
+
/* Direct, persistent writes create holes in time for
* caching... I don't know if this is actually possible but we
* should still get it right */
@@ -765,17 +867,28 @@ panfrost_transfer_unmap(struct pipe_context *pctx,
struct panfrost_gtransfer *trans = pan_transfer(transfer);
struct panfrost_resource *prsrc = (struct panfrost_resource *) transfer->resource;
- /* Mark whatever we wrote as written */
- if (transfer->usage & PIPE_TRANSFER_WRITE)
- prsrc->slices[transfer->level].initialized = true;
+ /* AFBC will use a staging resource. `initialized` will be set when the
+ * fragment job is created; this is deferred to prevent useless surface
+ * reloads that can cascade into DATA_INVALID_FAULTs due to reading
+ * malformed AFBC data if uninitialized */
+ if (trans->staging.rsrc) {
+ if (transfer->usage & PIPE_TRANSFER_WRITE) {
+ pan_blit_from_staging(pctx, trans);
+ panfrost_flush_batches_accessing_bo(pan_context(pctx), pan_resource(trans->staging.rsrc)->bo, true);
+ }
+
+ pipe_resource_reference(&trans->staging.rsrc, NULL);
+ }
+
+ /* Tiling will occur in software from a staging cpu buffer */
if (trans->map) {
struct panfrost_bo *bo = prsrc->bo;
if (transfer->usage & PIPE_TRANSFER_WRITE) {
- if (drm_is_afbc(prsrc->modifier)) {
- unreachable("Unimplemented: writes to AFBC\n");
- } else if (prsrc->modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED) {
+ prsrc->slices[transfer->level].initialized = true;
+
+ if (prsrc->modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED) {
assert(transfer->box.depth == 1);
/* Do we overwrite the entire resource? If so,
diff --git a/src/gallium/drivers/panfrost/pan_resource.h b/src/gallium/drivers/panfrost/pan_resource.h
index ccf3af45082..60970cb44f9 100644
--- a/src/gallium/drivers/panfrost/pan_resource.h
+++ b/src/gallium/drivers/panfrost/pan_resource.h
@@ -85,6 +85,10 @@ pan_resource(struct pipe_resource *p)
struct panfrost_gtransfer {
struct pipe_transfer base;
void *map;
+ struct {
+ struct pipe_resource *rsrc;
+ struct pipe_box box;
+ } staging;
};
static inline struct panfrost_gtransfer *
More information about the mesa-commit
mailing list