[igt-dev] [PATCH i-g-t 04/10] lib: Add engine copy support for YUV formats

Imre Deak
2019-12-30T03:41:18Z

Add the missing bits to the Vebox copy and AUX pagetable helpers for
copying YUV FBs with the Vebox engine.

Cc: Mika Kahola <mika.kahola@intel.com>
Signed-off-by: Imre Deak <imre.deak@intel.com>
---
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