[Mesa-dev] [PATCH 6/8] etnaviv: use filter blit for 2D YUV import on old GC320
Philipp Zabel
p.zabel at pengutronix.de
Mon Apr 15 10:57:29 UTC 2019
On Fri, 2019-04-12 at 19:38 +0200, Lucas Stach wrote:
> The GC320 without the 2D tiling feature doesn't support regular blits
> with YUV input, as well as the tiled output. So on those cores we need
> need to do a filter blit for the YUV->RGB conversion to a temporary
> linear buffer and then do a tiling blit into the texture buffer using
> the RS engine on the 3D core.
>
> Not the most efficient path, but at least gives us the same level of
> functionality as on the newer GC320 cores and looks the same to the
> application.
>
> Signed-off-by: Lucas Stach <l.stach at pengutronix.de>
> ---
> src/gallium/drivers/etnaviv/etnaviv_2d.c | 198 ++++++++++++++++++++---
> 1 file changed, 180 insertions(+), 18 deletions(-)
>
> diff --git a/src/gallium/drivers/etnaviv/etnaviv_2d.c b/src/gallium/drivers/etnaviv/etnaviv_2d.c
> index 457fa4e0cbd0..31b6bf4313dd 100644
> --- a/src/gallium/drivers/etnaviv/etnaviv_2d.c
> +++ b/src/gallium/drivers/etnaviv/etnaviv_2d.c
> @@ -25,13 +25,16 @@
> #include "etnaviv_context.h"
> #include "etnaviv_emit.h"
> #include "etnaviv_screen.h"
> +#include "etnaviv_rs.h"
>
> #include "pipe/p_state.h"
> #include "util/u_format.h"
>
> #include "hw/state_2d.xml.h"
> +#include "hw/common.xml.h"
>
> #include <assert.h>
> +#include <math.h>
>
> #define EMIT_STATE(state_name, src_value) \
> etna_coalsence_emit(stream, &coalesce, VIVS_##state_name, src_value)
> @@ -39,15 +42,85 @@
> #define EMIT_STATE_RELOC(state_name, src_value) \
> etna_coalsence_emit_reloc(stream, &coalesce, VIVS_##state_name, src_value)
>
> +/* stolen from xf86-video-armada */
> +#define KERNEL_ROWS 17
> +#define KERNEL_INDICES 9
> +#define KERNEL_SIZE (KERNEL_ROWS * KERNEL_INDICES)
> +#define KERNEL_STATE_SZ ((KERNEL_SIZE + 1) / 2)
> +
> +static bool filter_kernel_initialized;
> +static uint32_t filter_kernel[KERNEL_STATE_SZ];
> +
> +static inline float
> +sinc (float x)
^
> +{
> + return x != 0.0 ? sinf (x) / x : 1.0;
^
> +}
> +
> +static void
> +etnaviv_init_filter_kernel(void)
> +{
> + unsigned row, idx, i;
> + int16_t kernel_val[KERNEL_STATE_SZ * 2];
> + float row_ofs = 0.5;
> + float radius = 4.0;
> +
> + /* Compute lanczos filter kernel */
> + for (row = i = 0; row < KERNEL_ROWS; row++) {
> + float kernel[KERNEL_INDICES] = { 0.0 };
> + float sum = 0.0;
> +
> + for (idx = 0; idx < KERNEL_INDICES; idx++) {
> + float x = idx - 4.0 + row_ofs;
> +
> + if (fabs (x) <= radius)
> + kernel[idx] = sinc (M_PI * x) * sinc (M_PI * x / radius);
^ ^
Why the whitespace?
> +
> + sum += kernel[idx];
> + }
> +
> + /* normalise the row */
> + if (sum)
> + for (idx = 0; idx < KERNEL_INDICES; idx++)
> + kernel[idx] /= sum;
> +
> + /* convert to 1.14 format */
> + for (idx = 0; idx < KERNEL_INDICES; idx++) {
> + int val = kernel[idx] * (float) (1 << 14);
> +
> + if (val < -0x8000)
> + val = -0x8000;
> + else if (val > 0x7fff)
> + val = 0x7fff;
> +
> + kernel_val[i++] = val;
> + }
> +
> + row_ofs -= 1.0 / ((KERNEL_ROWS - 1) * 2);
> + }
> +
> + kernel_val[KERNEL_SIZE] = 0;
> +
> + /* Now convert the kernel values into state values */
> + for (i = 0; i < KERNEL_STATE_SZ * 2; i += 2)
> + filter_kernel[i / 2] =
> + VIVS_DE_FILTER_KERNEL_COEFFICIENT0 (kernel_val[i]) |
> + VIVS_DE_FILTER_KERNEL_COEFFICIENT1 (kernel_val[i + 1]);
> +}
> +
> bool etna_try_2d_blit(struct pipe_context *pctx,
> const struct pipe_blit_info *blit_info)
> {
> struct etna_context *ctx = etna_context(pctx);
> + struct etna_screen *screen = ctx->screen;
> struct etna_cmd_stream *stream = ctx->stream2d;
> struct etna_coalesce coalesce;
> struct etna_reloc ry, ru, rv, rdst;
> struct pipe_resource *res_y, *res_u, *res_v, *res_dst;
> + struct etna_bo *temp_bo = NULL;
> uint32_t src_format;
> + bool ext_blt = VIV_2D_FEATURE(screen, chipMinorFeatures2, 2D_TILING);
> + uint32_t dst_config;
>
> assert(util_format_is_yuv(blit_info->src.format));
> assert(blit_info->dst.format == PIPE_FORMAT_R8G8B8A8_UNORM);
> @@ -55,6 +128,11 @@ bool etna_try_2d_blit(struct pipe_context *pctx,
> if (!stream)
> return FALSE;
>
> + if (unlikely(!ext_blt && !filter_kernel_initialized)) {
> + etnaviv_init_filter_kernel();
> + filter_kernel_initialized = true;
> + }
> +
> switch (blit_info->src.format) {
> case PIPE_FORMAT_NV12:
> src_format = DE_FORMAT_NV12;
> @@ -66,6 +144,18 @@ bool etna_try_2d_blit(struct pipe_context *pctx,
> return FALSE;
> }
>
> + res_dst = blit_info->dst.resource;
> +
> + if (!ext_blt && etna_resource(res_dst)->layout != ETNA_LAYOUT_LINEAR) {
> + struct etna_resource *dst = etna_resource(blit_info->dst.resource);
> + unsigned int bo_size = dst->levels[blit_info->dst.level].stride *
> + dst->levels[blit_info->dst.level].padded_height;
> +
> + temp_bo = etna_bo_new(screen->dev, bo_size, DRM_ETNA_GEM_CACHE_WC);
> + if (!temp_bo)
> + return FALSE;
> + }
> +
> res_y = blit_info->src.resource;
> res_u = res_y->next ? res_y->next : res_y;
> res_v = res_u->next ? res_u->next : res_u;
> @@ -79,8 +169,7 @@ bool etna_try_2d_blit(struct pipe_context *pctx,
>
> ry.flags = ru.flags = rv.flags = ETNA_RELOC_READ;
>
> - res_dst = blit_info->dst.resource;
> - rdst.bo = etna_resource(res_dst)->bo;
> + rdst.bo = temp_bo ? temp_bo : etna_resource(res_dst)->bo;
> rdst.flags = ETNA_RELOC_WRITE;
> rdst.offset = 0;
>
> @@ -114,11 +203,15 @@ bool etna_try_2d_blit(struct pipe_context *pctx,
>
> /* Drawing engine configuration */
> EMIT_STATE(DE_DEST_ROTATION_CONFIG, 0);
> - EMIT_STATE(DE_DEST_CONFIG,
> - VIVS_DE_DEST_CONFIG_FORMAT(DE_FORMAT_A8R8G8B8) |
> - VIVS_DE_DEST_CONFIG_COMMAND_BIT_BLT |
> - VIVS_DE_DEST_CONFIG_SWIZZLE(DE_SWIZZLE_ABGR) |
> - VIVS_DE_DEST_CONFIG_TILED_ENABLE);
> + dst_config = VIVS_DE_DEST_CONFIG_FORMAT(DE_FORMAT_A8R8G8B8) |
> + VIVS_DE_DEST_CONFIG_SWIZZLE(DE_SWIZZLE_ABGR);
> + if (ext_blt) {
> + dst_config |= VIVS_DE_DEST_CONFIG_COMMAND_BIT_BLT |
> + VIVS_DE_DEST_CONFIG_TILED_ENABLE;
> + } else {
> + dst_config |= VIVS_DE_DEST_CONFIG_COMMAND_HOR_FILTER_BLT;
> + }
> + EMIT_STATE(DE_DEST_CONFIG, dst_config);
> EMIT_STATE(DE_ROP,
> VIVS_DE_ROP_ROP_FG(0xcc) | VIVS_DE_ROP_ROP_BG(0xcc) |
> VIVS_DE_ROP_TYPE_ROP4);
> @@ -136,21 +229,46 @@ bool etna_try_2d_blit(struct pipe_context *pctx,
> EMIT_STATE(DE_SRC_ROTATION_HEIGHT, 0);
> EMIT_STATE(DE_ROT_ANGLE, 0);
>
> + if (!ext_blt) {
> + EMIT_STATE(DE_VR_SOURCE_IMAGE_LOW,
> + VIVS_DE_VR_SOURCE_IMAGE_LOW_LEFT (0) |
> + VIVS_DE_VR_SOURCE_IMAGE_LOW_TOP (0));
> + EMIT_STATE(DE_VR_SOURCE_IMAGE_HIGH,
> + VIVS_DE_VR_SOURCE_IMAGE_HIGH_RIGHT(blit_info->src.box.width) |
> + VIVS_DE_VR_SOURCE_IMAGE_HIGH_BOTTOM(blit_info->src.box.height));
> + EMIT_STATE(DE_VR_SOURCE_ORIGIN_LOW, VIVS_DE_VR_SOURCE_ORIGIN_LOW_X(1));
> + EMIT_STATE(DE_VR_SOURCE_ORIGIN_HIGH, VIVS_DE_VR_SOURCE_ORIGIN_HIGH_Y(1));
> + EMIT_STATE(DE_VR_TARGET_WINDOW_LOW,
> + VIVS_DE_VR_TARGET_WINDOW_LOW_LEFT(0) |
> + VIVS_DE_VR_TARGET_WINDOW_LOW_TOP(0));
> + EMIT_STATE(DE_VR_TARGET_WINDOW_HIGH,
> + VIVS_DE_VR_TARGET_WINDOW_HIGH_RIGHT(blit_info->dst.box.width) |
> + VIVS_DE_VR_TARGET_WINDOW_HIGH_BOTTOM(blit_info->dst.box.height));
> + }
> +
> etna_coalesce_end(stream, &coalesce);
>
> - etna_cmd_stream_emit(stream, VIV_FE_DRAW_2D_HEADER_OP_DRAW_2D |
> - VIV_FE_DRAW_2D_HEADER_COUNT(1));
> - etna_cmd_stream_emit(stream, 0xdeadbeef);
> + if (ext_blt) {
> + etna_cmd_stream_emit(stream, VIV_FE_DRAW_2D_HEADER_OP_DRAW_2D |
> + VIV_FE_DRAW_2D_HEADER_COUNT(1));
> + etna_cmd_stream_emit(stream, 0xdeadbeef);
>
> - etna_cmd_stream_emit(stream, VIV_FE_DRAW_2D_TOP_LEFT_X(0) |
> - VIV_FE_DRAW_2D_TOP_LEFT_Y(0));
> - etna_cmd_stream_emit(stream,
> - VIV_FE_DRAW_2D_BOTTOM_RIGHT_X(blit_info->dst.box.width) |
> - VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y(blit_info->dst.box.height));
> + etna_cmd_stream_emit(stream, VIV_FE_DRAW_2D_TOP_LEFT_X(0) |
> + VIV_FE_DRAW_2D_TOP_LEFT_Y(0));
> + etna_cmd_stream_emit(stream,
> + VIV_FE_DRAW_2D_BOTTOM_RIGHT_X(blit_info->dst.box.width) |
> + VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y(blit_info->dst.box.height));
>
> - etna_set_state(stream, 1, 0);
> - etna_set_state(stream, 1, 0);
> - etna_set_state(stream, 1, 0);
> + etna_set_state(stream, 1, 0);
> + etna_set_state(stream, 1, 0);
> + etna_set_state(stream, 1, 0);
> + } else {
> + etna_set_state_multi(stream, VIVS_DE_FILTER_KERNEL(0), KERNEL_STATE_SZ,
> + filter_kernel);
> +
> + etna_set_state(stream, VIVS_DE_VR_CONFIG,
> + VIVS_DE_VR_CONFIG_START_HORIZONTAL_BLIT);
> + }
>
> etna_set_state(stream, VIVS_GL_FLUSH_CACHE, VIVS_GL_FLUSH_CACHE_PE2D);
>
> @@ -160,5 +278,49 @@ bool etna_try_2d_blit(struct pipe_context *pctx,
> */
> etna_cmd_stream_flush(ctx->stream2d);
>
> + if (temp_bo) {
> + struct etna_resource *dst = etna_resource(res_dst);
> + struct compiled_rs_state tile_blit;
> +
> + etna_compile_rs_state(ctx, &tile_blit, &(struct rs_state) {
> + .source_format = RS_FORMAT_X8R8G8B8,
> + .source_tiling = ETNA_LAYOUT_LINEAR,
> + .source = temp_bo,
> + .source_offset = 0,
> + .source_stride = dst->levels[0].stride,
> + .source_padded_width = dst->levels[0].padded_width,
> + .source_padded_height = dst->levels[0].padded_height,
> + .source_ts_valid = 0,
> + .dest_format = RS_FORMAT_X8R8G8B8,
> + .dest_tiling = ETNA_LAYOUT_TILED,
> + .dest = dst->bo,
> + .dest_offset = 0,
> + .dest_stride = dst->levels[0].stride,
> + .dest_padded_height = dst->levels[0].padded_height,
> + .downsample_x = 0,
> + .downsample_y = 0,
> + .swap_rb = 0,
> + .dither = {0xffffffff, 0xffffffff},
> + .clear_mode = VIVS_RS_CLEAR_CONTROL_MODE_DISABLED,
> + .width = blit_info->dst.box.width,
> + .height = blit_info->dst.box.height,
> + });
> +
> + /* The combined color/depth cache flush is required to avoid pixels stuck
> + * in the caches being flushed to the RS target. This seems to be some bug
> + * found on at least GC2000, with no other known workaround.
> + */
> + etna_set_state(ctx->stream, VIVS_GL_FLUSH_CACHE,
> + VIVS_GL_FLUSH_CACHE_COLOR | VIVS_GL_FLUSH_CACHE_DEPTH);
> + etna_stall(ctx->stream, SYNC_RECIPIENT_RA, SYNC_RECIPIENT_PE);
> + etna_set_state(ctx->stream, VIVS_TS_MEM_CONFIG, 0);
> + ctx->dirty |= ETNA_DIRTY_TS;
> + etna_submit_rs_state(ctx, &tile_blit);
> +
> + /* flush now, so we can get rid of the temp BO right here */
> + etna_cmd_stream_flush(ctx->stream);
> + etna_bo_del(temp_bo);
> + }
> +
> return TRUE;
> }
Reviewed-by: Philipp Zabel <p.zabel at pengutronix.de>
regards
Philipp
More information about the mesa-dev
mailing list