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.st...@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.za...@pengutronix.de> regards Philipp _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev