From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by gabe.freedesktop.org (Postfix) with ESMTPS id B49DB89C99 for ; Mon, 30 Dec 2019 03:41:18 +0000 (UTC) From: Imre Deak Date: Mon, 30 Dec 2019 05:40:34 +0200 Message-Id: <20191230034040.21943-5-imre.deak@intel.com> In-Reply-To: <20191230034040.21943-1-imre.deak@intel.com> References: <20191230034040.21943-1-imre.deak@intel.com> MIME-Version: 1.0 Subject: [igt-dev] [PATCH i-g-t 04/10] lib: Add engine copy support for YUV formats List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: igt-dev-bounces@lists.freedesktop.org Sender: "igt-dev" To: igt-dev@lists.freedesktop.org List-ID: Add the missing bits to the Vebox copy and AUX pagetable helpers for copying YUV FBs with the Vebox engine. Cc: Mika Kahola Signed-off-by: Imre Deak --- lib/igt_fb.c | 79 ++++++++++++++++++++++++-- lib/intel_aux_pgtable.c | 121 ++++++++++++++++++++++++++++++++++++---- lib/intel_batchbuffer.h | 4 ++ lib/veboxcopy_gen12.c | 58 ++++++++++++++++--- 4 files changed, 238 insertions(+), 24 deletions(-) diff --git a/lib/igt_fb.c b/lib/igt_fb.c index cc0fb373..e6a3ff07 100644 --- a/lib/igt_fb.c +++ b/lib/igt_fb.c @@ -359,6 +359,13 @@ static const struct format_desc_struct *lookup_drm_format(uint32_t drm_format) return NULL; } +static bool igt_format_is_yuv_semiplanar(uint32_t format) +{ + const struct format_desc_struct *f = lookup_drm_format(format); + + return igt_format_is_yuv(format) && f->num_planes == 2; +} + /** * igt_get_fb_tile_size: * @fd: the DRM file descriptor @@ -1967,19 +1974,56 @@ static bool use_blitter(const struct igt_fb *fb) blitter_ok(fb); } +static void init_buf_ccs(struct igt_buf *buf, int ccs_idx, + uint32_t offset, uint32_t stride) +{ + buf->ccs[ccs_idx].offset = offset; + buf->ccs[ccs_idx].stride = stride; +} + +static void init_buf_surface(struct igt_buf *buf, int surface_idx, + uint32_t offset, uint32_t stride, uint32_t size) +{ + buf->surface[surface_idx].offset = offset; + buf->surface[surface_idx].stride = stride; + buf->surface[surface_idx].size = size; +} + +static int yuv_semiplanar_bpp(uint32_t drm_format) +{ + switch (drm_format) { + case DRM_FORMAT_NV12: + return 8; + case DRM_FORMAT_P010: + return 10; + case DRM_FORMAT_P012: + return 12; + case DRM_FORMAT_P016: + return 16; + default: + igt_assert_f(0, "Unsupported format: %08x\n", drm_format); + } +} + static void init_buf(struct fb_blit_upload *blit, struct igt_buf *buf, const struct igt_fb *fb, const char *name) { + int num_surfaces; + int i; + igt_assert_eq(fb->offsets[0], 0); buf->bo = gem_handle_to_libdrm_bo(blit->bufmgr, blit->fd, name, fb->gem_handle); buf->tiling = igt_fb_mod_to_tiling(fb->modifier); - buf->surface[0].stride = fb->strides[0]; buf->bpp = fb->plane_bpp[0]; - buf->surface[0].size = fb->size; + buf->format_is_yuv = igt_format_is_yuv(fb->drm_format); + buf->format_is_yuv_semiplanar = + igt_format_is_yuv_semiplanar(fb->drm_format); + if (buf->format_is_yuv_semiplanar) + buf->yuv_semiplanar_bpp = yuv_semiplanar_bpp(fb->drm_format); if (is_ccs_modifier(fb->modifier)) { igt_assert_eq(fb->strides[0] & 127, 0); @@ -1994,8 +2038,24 @@ static void init_buf(struct fb_blit_upload *blit, else buf->compression = I915_COMPRESSION_RENDER; - buf->ccs[0].offset = fb->offsets[1]; - buf->ccs[0].stride = fb->strides[1]; + num_surfaces = fb->num_planes / 2; + for (i = 0; i < num_surfaces; i++) + init_buf_ccs(buf, i, + fb->offsets[num_surfaces + i], + fb->strides[num_surfaces + i]); + } else { + num_surfaces = fb->num_planes; + } + + igt_assert(fb->offsets[0] == 0); + for (i = 0; i < num_surfaces; i++) { + uint32_t end = + i == fb->num_planes - 1 ? fb->size : fb->offsets[i + 1]; + + init_buf_surface(buf, i, + fb->offsets[i], + fb->strides[i], + end - fb->offsets[i]); } if (fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC) @@ -2007,6 +2067,15 @@ static void fini_buf(struct igt_buf *buf) drm_intel_bo_unreference(buf->bo); } +static bool use_vebox_copy(const struct igt_fb *src_fb, + const struct igt_fb *dst_fb) +{ + + return is_gen12_mc_ccs_modifier(dst_fb->modifier) || + igt_format_is_yuv(src_fb->drm_format) || + igt_format_is_yuv(dst_fb->drm_format); +} + /** * copy_with_engine: * @blit: context for the copy operation @@ -2029,7 +2098,7 @@ static void copy_with_engine(struct fb_blit_upload *blit, igt_render_copyfunc_t render_copy = NULL; igt_vebox_copyfunc_t vebox_copy = NULL; - if (is_gen12_mc_ccs_modifier(dst_fb->modifier)) + if (use_vebox_copy(src_fb, dst_fb)) vebox_copy = igt_get_vebox_copyfunc(intel_get_drm_devid(blit->fd)); else render_copy = igt_get_render_copyfunc(intel_get_drm_devid(blit->fd)); diff --git a/lib/intel_aux_pgtable.c b/lib/intel_aux_pgtable.c index 5addb2e2..fcd24f08 100644 --- a/lib/intel_aux_pgtable.c +++ b/lib/intel_aux_pgtable.c @@ -33,6 +33,12 @@ #define max(a, b) ((a) > (b) ? (a) : (b)) +#define AUX_FORMAT_YCRCB 0x03 +#define AUX_FORMAT_P010 0x07 +#define AUX_FORMAT_P016 0x08 +#define AUX_FORMAT_ARGB_8B 0x0A +#define AUX_FORMAT_NV12_21 0x0F + struct pgtable_level_desc { int idx_shift; int idx_bits; @@ -55,6 +61,23 @@ struct pgtable { drm_intel_bo *bo; }; +static uint64_t last_buf_surface_end(const struct igt_buf *buf) +{ + uint64_t end_offset = 0; + int num_surfaces = buf->format_is_yuv_semiplanar ? 2 : 1; + int i; + + for (i = 0; i < num_surfaces; i++) { + uint64_t surface_end = buf->surface[i].offset + + buf->surface[i].size; + + if (surface_end > end_offset) + end_offset = surface_end; + } + + return end_offset; +} + static int pgt_table_count(int address_bits, const struct igt_buf **bufs, int buf_count) { @@ -77,7 +100,7 @@ pgt_table_count(int address_bits, const struct igt_buf **bufs, int buf_count) /* Avoid double counting for overlapping aligned bufs. */ start = max(start, end); - end = ALIGN(buf->bo->offset64 + buf->surface[0].size, + end = ALIGN(buf->bo->offset64 + last_buf_surface_end(buf), 1UL << address_bits); igt_assert(end >= start); @@ -189,7 +212,29 @@ pgt_set_l1_entry(struct pgtable *pgt, uint64_t l1_table, *l1_entry_ptr = ptr | flags; } -static uint64_t pgt_get_l1_flags(const struct igt_buf *buf) +#define DEPTH_VAL_RESERVED 3 + +static int bpp_to_depth_val(int bpp) +{ + switch (bpp) { + case 8: + return 4; + case 10: + return 1; + case 12: + return 2; + case 16: + return 0; + case 32: + return 5; + case 64: + return 6; + default: + igt_assert_f(0, "invalid bpp %d\n", bpp); + } +} + +static uint64_t pgt_get_l1_flags(const struct igt_buf *buf, int surface_idx) { /* * The offset of .tile_mode isn't specifed by bspec, it's what Mesa @@ -213,8 +258,6 @@ static uint64_t pgt_get_l1_flags(const struct igt_buf *buf) .e = { .valid = 1, .tile_mode = buf->tiling == I915_TILING_Y ? 1 : 0, - .depth = 5, /* 32bpp */ - .format = 0xA, /* B8G8R8A8_UNORM */ } }; @@ -227,7 +270,49 @@ static uint64_t pgt_get_l1_flags(const struct igt_buf *buf) buf->tiling == I915_TILING_Yf || buf->tiling == I915_TILING_Ys); - igt_assert(buf->bpp == 32); + entry.e.ycr = surface_idx > 0; + + if (buf->format_is_yuv_semiplanar) { + entry.e.depth = bpp_to_depth_val(buf->bpp); + switch (buf->yuv_semiplanar_bpp) { + case 8: + entry.e.format = AUX_FORMAT_NV12_21; + entry.e.depth = DEPTH_VAL_RESERVED; + break; + case 10: + entry.e.format = AUX_FORMAT_P010; + entry.e.depth = bpp_to_depth_val(10); + break; + case 12: + entry.e.format = AUX_FORMAT_P016; + entry.e.depth = bpp_to_depth_val(12); + break; + case 16: + entry.e.format = AUX_FORMAT_P016; + entry.e.depth = bpp_to_depth_val(16); + break; + default: + igt_assert(0); + } + } else if (buf->format_is_yuv) { + switch (buf->bpp) { + case 16: + entry.e.format = AUX_FORMAT_YCRCB; + entry.e.depth = DEPTH_VAL_RESERVED; + break; + default: + igt_assert(0); + } + } else { + switch (buf->bpp) { + case 32: + entry.e.format = AUX_FORMAT_ARGB_8B; + entry.e.depth = bpp_to_depth_val(32); + break; + default: + igt_assert(0); + } + } return entry.l; } @@ -253,14 +338,21 @@ static uint64_t pgt_get_lx_flags(void) static void pgt_populate_entries_for_buf(struct pgtable *pgt, const struct igt_buf *buf, - uint64_t top_table) + uint64_t top_table, + int surface_idx) { - uint64_t surface_addr = buf->bo->offset64; - uint64_t surface_end = surface_addr + buf->surface[0].size; - uint64_t aux_addr = buf->bo->offset64 + buf->ccs[0].offset; - uint64_t l1_flags = pgt_get_l1_flags(buf); + uint64_t surface_addr = buf->bo->offset64 + + buf->surface[surface_idx].offset; + uint64_t surface_end = surface_addr + + buf->surface[surface_idx].size; + uint64_t aux_addr = buf->bo->offset64 + buf->ccs[surface_idx].offset; + uint64_t l1_flags = pgt_get_l1_flags(buf, surface_idx); uint64_t lx_flags = pgt_get_lx_flags(); + igt_assert(!(buf->surface[surface_idx].stride % 512)); + igt_assert_eq(buf->ccs[surface_idx].stride, + buf->surface[surface_idx].stride / 512 * 64); + for (; surface_addr < surface_end; surface_addr += MAIN_SURFACE_BLOCK_SIZE, aux_addr += AUX_CCS_BLOCK_SIZE) { @@ -292,8 +384,13 @@ static void pgt_populate_entries(struct pgtable *pgt, /* Top level table must be at offset 0. */ igt_assert(top_table == 0); - for (i = 0; i < buf_count; i++) - pgt_populate_entries_for_buf(pgt, bufs[i], top_table); + for (i = 0; i < buf_count; i++) { + igt_assert_eq(bufs[i]->surface[0].offset, 0); + + pgt_populate_entries_for_buf(pgt, bufs[i], top_table, 0); + if (bufs[i]->format_is_yuv_semiplanar) + pgt_populate_entries_for_buf(pgt, bufs[i], top_table, 1); + } } static struct pgtable * diff --git a/lib/intel_batchbuffer.h b/lib/intel_batchbuffer.h index 69580839..fd7ef03f 100644 --- a/lib/intel_batchbuffer.h +++ b/lib/intel_batchbuffer.h @@ -235,8 +235,12 @@ struct igt_buf { uint32_t tiling; enum i915_compression compression; uint32_t bpp; + uint32_t yuv_semiplanar_bpp; uint32_t *data; + bool format_is_yuv:1; + bool format_is_yuv_semiplanar:1; struct { + uint32_t offset; uint32_t stride; uint32_t size; } surface[2]; diff --git a/lib/veboxcopy_gen12.c b/lib/veboxcopy_gen12.c index 2f017514..237c43f2 100644 --- a/lib/veboxcopy_gen12.c +++ b/lib/veboxcopy_gen12.c @@ -26,7 +26,10 @@ #include "intel_aux_pgtable.h" #include "veboxcopy.h" +#define YCRCB_NORMAL 0 +#define PLANAR_420_8 4 #define R8G8B8A8_UNORM 8 +#define PLANAR_420_16 12 struct vebox_surface_state { struct { @@ -129,10 +132,23 @@ struct vebox_tiling_convert { }; } __attribute__((packed)); +static bool format_is_interleaved_yuv(int format) +{ + switch (format) { + case YCRCB_NORMAL: + case PLANAR_420_8: + case PLANAR_420_16: + return true; + } + + return false; +} + static void emit_surface_state_cmd(struct intel_batchbuffer *batch, int surface_id, int width, int height, int bpp, - int pitch, uint32_t tiling, int format) + int pitch, uint32_t tiling, int format, + uint32_t uv_offset) { struct vebox_surface_state *ss; @@ -149,11 +165,15 @@ static void emit_surface_state_cmd(struct intel_batchbuffer *batch, ss->ss2.width = width - 1; ss->ss3.surface_format = format; + if (format_is_interleaved_yuv(format)) + ss->ss3.chroma_interleave = 1; ss->ss3.surface_pitch = pitch - 1; ss->ss3.tile_walk = (tiling == I915_TILING_Y) || (tiling == I915_TILING_Yf); ss->ss3.tiled_surface = tiling != I915_TILING_NONE; + ss->ss4.u_y_offset = uv_offset / pitch; + ss->ss7.derived_surface_pitch = pitch - 1; } @@ -226,8 +246,7 @@ void gen12_vebox_copyfunc(struct intel_batchbuffer *batch, { struct aux_pgtable_info aux_pgtable_info = { }; uint32_t aux_pgtable_state; - - igt_assert(src->bpp == dst->bpp); + int format; intel_batchbuffer_flush_on_ring(batch, I915_EXEC_VEBOX); @@ -245,18 +264,43 @@ void gen12_vebox_copyfunc(struct intel_batchbuffer *batch, gen12_emit_aux_pgtable_state(batch, aux_pgtable_state, false); + /* The tiling convert command can't convert formats. */ + igt_assert_eq(src->format_is_yuv, dst->format_is_yuv); + igt_assert_eq(src->format_is_yuv_semiplanar, + dst->format_is_yuv_semiplanar); + igt_assert_eq(src->bpp, dst->bpp); + /* TODO: add support for more formats */ - igt_assert(src->bpp == 32); + switch (src->bpp) { + case 8: + igt_assert(src->format_is_yuv_semiplanar); + format = PLANAR_420_8; + break; + case 16: + igt_assert(src->format_is_yuv); + format = src->format_is_yuv_semiplanar ? PLANAR_420_16 : + YCRCB_NORMAL; + break; + case 32: + igt_assert(!src->format_is_yuv && + !src->format_is_yuv_semiplanar); + format = R8G8B8A8_UNORM; + break; + default: + igt_assert_f(0, "Unsupported bpp: %u\n", src->bpp); + } + + igt_assert(!src->format_is_yuv_semiplanar || + (src->surface[1].offset && dst->surface[1].offset)); emit_surface_state_cmd(batch, VEBOX_SURFACE_INPUT, width, height, src->bpp, src->surface[0].stride, - src->tiling, R8G8B8A8_UNORM); + src->tiling, format, src->surface[1].offset); - igt_assert(dst->bpp == 32); emit_surface_state_cmd(batch, VEBOX_SURFACE_OUTPUT, width, height, dst->bpp, dst->surface[0].stride, - dst->tiling, R8G8B8A8_UNORM); + dst->tiling, format, dst->surface[1].offset); emit_tiling_convert_cmd(batch, src->bo, src->tiling, src->compression, -- 2.23.1 _______________________________________________ igt-dev mailing list igt-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/igt-dev