[Mesa-dev] [PATCH 3/4] radeon: accelerate transfer_inline_write
Marek Olšák
maraeo at gmail.com
Wed Aug 6 04:45:25 PDT 2014
On Tue, Aug 5, 2014 at 7:31 PM, Christian König <deathsimple at vodafone.de> wrote:
> From: Christian König <christian.koenig at amd.com>
>
> Not completely implemented, cause we need DMA copy support for every hw generation.
>
> Signed-off-by: Christian König <christian.koenig at amd.com>
> ---
> src/gallium/drivers/radeon/r600_buffer_common.c | 2 +-
> src/gallium/drivers/radeon/r600_pipe_common.c | 2 +-
> src/gallium/drivers/radeon/r600_texture.c | 104 ++++++++++++++++++++++--
> 3 files changed, 100 insertions(+), 8 deletions(-)
>
> diff --git a/src/gallium/drivers/radeon/r600_buffer_common.c b/src/gallium/drivers/radeon/r600_buffer_common.c
> index d747cbc..28ab30c 100644
> --- a/src/gallium/drivers/radeon/r600_buffer_common.c
> +++ b/src/gallium/drivers/radeon/r600_buffer_common.c
> @@ -372,7 +372,7 @@ static const struct u_resource_vtbl r600_buffer_vtbl =
> r600_buffer_transfer_map, /* transfer_map */
> NULL, /* transfer_flush_region */
> r600_buffer_transfer_unmap, /* transfer_unmap */
> - NULL /* transfer_inline_write */
> + u_default_transfer_inline_write /* transfer_inline_write */
> };
>
> struct pipe_resource *r600_buffer_create(struct pipe_screen *screen,
> diff --git a/src/gallium/drivers/radeon/r600_pipe_common.c b/src/gallium/drivers/radeon/r600_pipe_common.c
> index 3476021..69d344e 100644
> --- a/src/gallium/drivers/radeon/r600_pipe_common.c
> +++ b/src/gallium/drivers/radeon/r600_pipe_common.c
> @@ -153,7 +153,7 @@ bool r600_common_context_init(struct r600_common_context *rctx,
> rctx->b.transfer_map = u_transfer_map_vtbl;
> rctx->b.transfer_flush_region = u_default_transfer_flush_region;
> rctx->b.transfer_unmap = u_transfer_unmap_vtbl;
> - rctx->b.transfer_inline_write = u_default_transfer_inline_write;
> + rctx->b.transfer_inline_write = u_transfer_inline_write_vtbl;
> rctx->b.memory_barrier = r600_memory_barrier;
> rctx->b.flush = r600_flush_from_st;
>
> diff --git a/src/gallium/drivers/radeon/r600_texture.c b/src/gallium/drivers/radeon/r600_texture.c
> index 482bbff..89b3b55 100644
> --- a/src/gallium/drivers/radeon/r600_texture.c
> +++ b/src/gallium/drivers/radeon/r600_texture.c
> @@ -849,6 +849,47 @@ static struct pipe_resource *r600_texture_from_handle(struct pipe_screen *screen
> stride, buf, &surface);
> }
>
> +static struct r600_texture *r600_texture_from_ptr(struct pipe_screen *screen,
> + const struct pipe_resource *templ,
> + void *pointer, unsigned stride)
> +{
> + struct r600_common_screen *rscreen = (struct r600_common_screen*)screen;
> + struct radeon_surface surface = {};
> + struct r600_texture *tex;
> + unsigned offset, size;
> + struct pb_buffer *buf;
> + int r;
> +
> + /* Support only 2D textures without mipmaps */
> + if ((templ->target != PIPE_TEXTURE_2D && templ->target != PIPE_TEXTURE_RECT) ||
> + templ->depth0 != 1 || templ->last_level != 0)
> + return NULL;
> +
> + /* stride needs to be at least dw aligned */
> + if (stride % 4)
> + return NULL;
> +
> + offset = ((uintptr_t)pointer) & 0xfff;
> + pointer = (void *)(((uintptr_t)pointer) - offset);
> + size = align(stride * templ->height0 + offset, 0x1000);
> +
> + /* avoid the overhead for small copies */
> + if (size < 64*1024)
> + return NULL;
> +
> + buf = rscreen->ws->buffer_from_ptr(rscreen->ws, pointer, size);
> + if (!buf)
> + return NULL;
> +
> + r = r600_init_surface(rscreen, &surface, templ, RADEON_SURF_MODE_LINEAR_ALIGNED, false);
I know you change it the next patch, but I think the alignment for
LINEAR (not ALIGNED) is 8 pixels, right? Of course, libdrm_radeon
should be reviewed if it doesn't over-align the stride. The safest
thing would be to check if stride == surface[0].pitch_in_bytes.
> + if (r)
> + return NULL;
> +
> + tex = r600_texture_create_object(screen, templ, stride, buf, &surface);
> + tex->surface.level[0].offset += offset;
> + return tex;
> +}
> +
> bool r600_init_flushed_depth_texture(struct pipe_context *ctx,
> struct pipe_resource *texture,
> struct r600_texture **staging)
> @@ -1112,14 +1153,65 @@ static void r600_texture_transfer_unmap(struct pipe_context *ctx,
> FREE(transfer);
> }
>
> +static void r600_texture_transfer_inline_write(struct pipe_context *ctx,
> + struct pipe_resource *dst,
> + unsigned level, unsigned usage,
> + const struct pipe_box *box,
> + const void *data,
> + unsigned stride,
> + unsigned layer_stride)
> +{
> + struct r600_common_context *rctx = (struct r600_common_context*)ctx;
> + struct r600_texture *rsrc;
> + struct pipe_resource *src, templ = {};
> + struct pipe_box src_box = {};
> +
> + templ.target = PIPE_TEXTURE_2D;
> + templ.format = dst->format;
> +
> + templ.width0 = box->width;
> + templ.height0 = box->height;
> + templ.depth0 = 1;
> + templ.array_size = 1;
> +
> + templ.usage = PIPE_USAGE_STAGING;
> + templ.bind = PIPE_BIND_TRANSFER_READ;
> +
> + rsrc = r600_texture_from_ptr(ctx->screen, &templ, (void *)data, stride);
> + src = (struct pipe_resource *)rsrc;
> + if (!src) {
As an optimization, you can test if the dst texture is referenced or
busy and if yes, use u_default_transfer_inline_write. If there is
non-trivial rendering going on, the buffer_wait call below will cost a
lot.
Marek
> + u_default_transfer_inline_write(ctx, dst, level, usage, box,
> + data, stride, layer_stride);
> + return;
> + }
> +
> + src_box.width = box->width;
> + src_box.height = box->height;
> + src_box.depth = box->depth;
> + rctx->dma_copy(ctx, dst, level, box->x, box->y, box->z, src, 0, &src_box);
> +
> + if (rctx->ws->cs_is_buffer_referenced(rctx->rings.gfx.cs, rsrc->resource.cs_buf,
> + RADEON_USAGE_READ))
> + rctx->rings.gfx.flush(ctx, 0, NULL);
> +
> + if (rctx->rings.dma.cs &&
> + rctx->ws->cs_is_buffer_referenced(rctx->rings.dma.cs, rsrc->resource.cs_buf,
> + RADEON_USAGE_READ))
> + rctx->rings.dma.flush(ctx, 0, NULL);
> +
> + rctx->ws->buffer_wait(rsrc->resource.buf, RADEON_USAGE_READWRITE);
> +
> + pipe_resource_reference(&src, NULL);
> +}
> +
> static const struct u_resource_vtbl r600_texture_vtbl =
> {
> - NULL, /* get_handle */
> - r600_texture_destroy, /* resource_destroy */
> - r600_texture_transfer_map, /* transfer_map */
> - NULL, /* transfer_flush_region */
> - r600_texture_transfer_unmap, /* transfer_unmap */
> - NULL /* transfer_inline_write */
> + NULL, /* get_handle */
> + r600_texture_destroy, /* resource_destroy */
> + r600_texture_transfer_map, /* transfer_map */
> + NULL, /* transfer_flush_region */
> + r600_texture_transfer_unmap, /* transfer_unmap */
> + r600_texture_transfer_inline_write /* transfer_inline_write */
> };
>
> struct pipe_surface *r600_create_surface_custom(struct pipe_context *pipe,
> --
> 1.9.1
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/mesa-dev
More information about the mesa-dev
mailing list