From b1efbd8d169f6d72f69a0f381db9f6dc80e372bf Mon Sep 17 00:00:00 2001 From: "Kristian H. Kristensen" Date: Tue, 6 Sep 2016 11:43:26 -0700 Subject: [PATCH] rockchip: Add support for AFBC buffers This adds support for allocating AFBC (ARM FrameBuffer Compression) buffers with minigbm for Rockchip SoCs. AFBC buffers are allocated through the new gbm_bo_create_with_modifiers() entry point. Callers are responsible for determining which modifiers are valid for the intended use case and pass in that list. gbm will then pick the optimal modifier and allocate a buffer with that layout. The chosen modifier can be queries through gbm_bo_get_format_modifier(). Callers of the new entry point are expected to forward the modifier when using the buffer with other APIs (EGL, KMS etc). The old gbm_bo_create() entry point continues to work as before and won't allocate AFBC buffers. BUG=chrome-os-partner:56407 TEST=drm-tests null_platform_test with AFBC support Change-Id: I1aa345b0d79c4545b7bfc17e9699ef6ad57c68e2 Reviewed-on: https://chromium-review.googlesource.com/386318 Commit-Ready: Kristian H. Kristensen Tested-by: Kristian H. Kristensen Reviewed-by: Gurchetan Singh --- drv.c | 39 +++++++++++++++++++++++++++ drv.h | 6 +++++ drv_priv.h | 5 ++++ gbm.c | 26 ++++++++++++++++++ gbm.h | 6 +++++ rockchip.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 170 insertions(+), 2 deletions(-) diff --git a/drv.c b/drv.c index 6356c10..b4df6a5 100644 --- a/drv.c +++ b/drv.c @@ -4,6 +4,7 @@ * found in the LICENSE file. */ #include +#include #include #include #include @@ -249,6 +250,44 @@ struct bo *drv_bo_create(struct driver *drv, uint32_t width, uint32_t height, return bo; } +struct bo *drv_bo_create_with_modifiers(struct driver *drv, + uint32_t width, uint32_t height, + uint32_t format, + const uint64_t *modifiers, uint32_t count) +{ + int ret; + size_t plane; + struct bo *bo; + + if (!drv->backend->bo_create_with_modifiers) { + errno = ENOENT; + return NULL; + } + + bo = drv_bo_new(drv, width, height, format); + + if (!bo) + return NULL; + + ret = drv->backend->bo_create_with_modifiers(bo, width, height, + format, modifiers, count); + + if (ret) { + free(bo); + return NULL; + } + + pthread_mutex_lock(&drv->driver_lock); + + for (plane = 0; plane < bo->num_planes; plane++) + drv_increment_reference_count(drv, bo, plane); + + pthread_mutex_unlock(&drv->driver_lock); + + return bo; +} + + void drv_bo_destroy(struct bo *bo) { size_t plane; diff --git a/drv.h b/drv.h index 9204475..355ea45 100644 --- a/drv.h +++ b/drv.h @@ -92,6 +92,12 @@ struct bo * drv_bo_create(struct driver *drv, uint32_t width, uint32_t height, uint32_t format, uint64_t flags); +struct bo * +drv_bo_create_with_modifiers(struct driver *drv, + uint32_t width, uint32_t height, + uint32_t format, + const uint64_t *modifiers, uint32_t count); + void drv_bo_destroy(struct bo *bo); diff --git a/drv_priv.h b/drv_priv.h index 9b0e4da..cdd13ee 100644 --- a/drv_priv.h +++ b/drv_priv.h @@ -67,6 +67,11 @@ struct backend void (*close)(struct driver *drv); int (*bo_create)(struct bo *bo, uint32_t width, uint32_t height, uint32_t format, uint32_t flags); + int (*bo_create_with_modifiers)(struct bo *bo, + uint32_t width, uint32_t height, + uint32_t format, + const uint64_t *modifiers, + uint32_t count); void* (*bo_map)(struct bo *bo, struct map_info *data, size_t plane); int (*bo_unmap)(struct bo *bo, struct map_info *data); int (*bo_destroy)(struct bo *bo); diff --git a/gbm.c b/gbm.c index 1a81e7e..6ad32ce 100644 --- a/gbm.c +++ b/gbm.c @@ -137,6 +137,32 @@ PUBLIC struct gbm_bo *gbm_bo_create(struct gbm_device *gbm, uint32_t width, return bo; } +PUBLIC struct gbm_bo *gbm_bo_create_with_modifiers(struct gbm_device *gbm, + uint32_t width, + uint32_t height, + uint32_t format, + const uint64_t *modifiers, + uint32_t count) +{ + struct gbm_bo *bo; + + bo = gbm_bo_new(gbm, format); + + if (!bo) + return NULL; + + bo->bo = drv_bo_create_with_modifiers(gbm->drv, + width, height, format, + modifiers, count); + + if (!bo->bo) { + free(bo); + return NULL; + } + + return bo; +} + PUBLIC void gbm_bo_destroy(struct gbm_bo *bo) { if (bo->destroy_user_data) { diff --git a/gbm.h b/gbm.h index 03c10ec..1fb338f 100644 --- a/gbm.h +++ b/gbm.h @@ -262,6 +262,12 @@ gbm_bo_create(struct gbm_device *gbm, uint32_t width, uint32_t height, uint32_t format, uint32_t flags); +struct gbm_bo * +gbm_bo_create_with_modifiers(struct gbm_device *gbm, + uint32_t width, uint32_t height, + uint32_t format, + const uint64_t *modifiers, uint32_t count); + #define GBM_BO_IMPORT_WL_BUFFER 0x5501 #define GBM_BO_IMPORT_EGL_IMAGE 0x5502 #define GBM_BO_IMPORT_FD 0x5503 diff --git a/rockchip.c b/rockchip.c index f066754..5e20036 100644 --- a/rockchip.c +++ b/rockchip.c @@ -44,14 +44,75 @@ static struct supported_combination combos[11] = { BO_USE_RENDERING | BO_USE_SW_READ_RARELY | BO_USE_SW_WRITE_RARELY}, }; +static int afbc_bo_from_format(struct bo *bo, uint32_t width, uint32_t height, + uint32_t format) +{ + /* We've restricted ourselves to four bytes per pixel. */ + const uint32_t pixel_size = 4; + + const uint32_t clump_width = 4; + const uint32_t clump_height = 4; + +#define AFBC_NARROW 1 +#if AFBC_NARROW == 1 + const uint32_t block_width = 4 * clump_width; + const uint32_t block_height = 4 * clump_height; +#else + const uint32_t block_width = 8 * clump_width; + const uint32_t block_height = 2 * clump_height; +#endif + + const uint32_t header_block_size = 16; + const uint32_t body_block_size = block_width * block_height * pixel_size; + const uint32_t width_in_blocks = DIV_ROUND_UP(width, block_width); + const uint32_t height_in_blocks = DIV_ROUND_UP(height, block_height); + const uint32_t total_blocks = width_in_blocks * height_in_blocks; + + const uint32_t header_plane_size = total_blocks * header_block_size; + const uint32_t body_plane_size = total_blocks * body_block_size; + + /* GPU requires 64 bytes, but EGL import code expects 1024 byte + * alignement for the body plane. */ + const uint32_t body_plane_alignment = 1024; + + const uint32_t body_plane_offset = + ALIGN(header_plane_size, body_plane_alignment); + const uint32_t total_size = + body_plane_offset + body_plane_size; + + bo->strides[0] = width_in_blocks * block_width * pixel_size; + bo->sizes[0] = total_size; + bo->offsets[0] = 0; + + bo->total_size = total_size; + + bo->format_modifiers[0] = DRM_FORMAT_MOD_CHROMEOS_ROCKCHIP_AFBC; + + return 0; +} + static int rockchip_init(struct driver *drv) { drv_insert_combinations(drv, combos, ARRAY_SIZE(combos)); return drv_add_kms_flags(drv); } -static int rockchip_bo_create(struct bo *bo, uint32_t width, uint32_t height, - uint32_t format, uint32_t flags) +static bool has_modifier(const uint64_t *list, uint32_t count, uint64_t modifier) +{ + uint32_t i; + + for (i = 0; i < count; i++) + if (list[i] == modifier) + return true; + + return false; +} + +static int rockchip_bo_create_with_modifiers(struct bo *bo, + uint32_t width, uint32_t height, + uint32_t format, + const uint64_t *modifiers, + uint32_t count) { int ret; size_t plane; @@ -67,7 +128,17 @@ static int rockchip_bo_create(struct bo *bo, uint32_t width, uint32_t height, drv_bo_from_format(bo, aligned_width, height, format); bo->total_size = bo->strides[0] * aligned_height + w_mbs * h_mbs * 128; + } else if (has_modifier(modifiers, count, + DRM_FORMAT_MOD_CHROMEOS_ROCKCHIP_AFBC)) { + /* If the caller has decided they can use AFBC, always + * pick that */ + afbc_bo_from_format(bo, width, height, format); } else { + if (!has_modifier(modifiers, count, DRM_FORMAT_MOD_NONE)) { + errno = EINVAL; + fprintf(stderr, "no usable modifier found\n"); + return -1; + } drv_bo_from_format(bo, width, height, format); } @@ -89,11 +160,25 @@ static int rockchip_bo_create(struct bo *bo, uint32_t width, uint32_t height, return 0; } +static int rockchip_bo_create(struct bo *bo, uint32_t width, uint32_t height, + uint32_t format, uint32_t flags) +{ + uint64_t modifiers[] = { DRM_FORMAT_MOD_NONE }; + + return rockchip_bo_create_with_modifiers(bo, width, height, format, + modifiers, ARRAY_SIZE(modifiers)); +} + static void *rockchip_bo_map(struct bo *bo, struct map_info *data, size_t plane) { int ret; struct drm_rockchip_gem_map_off gem_map; + /* We can only map buffers created with SW access flags, which should + * have no modifiers (ie, not AFBC). */ + if (bo->format_modifiers[0] == DRM_FORMAT_MOD_CHROMEOS_ROCKCHIP_AFBC) + return MAP_FAILED; + memset(&gem_map, 0, sizeof(gem_map)); gem_map.handle = bo->handles[0].u32; @@ -129,6 +214,7 @@ struct backend backend_rockchip = .name = "rockchip", .init = rockchip_init, .bo_create = rockchip_bo_create, + .bo_create_with_modifiers = rockchip_bo_create_with_modifiers, .bo_destroy = drv_gem_bo_destroy, .bo_map = rockchip_bo_map, .resolve_format = rockchip_resolve_format, -- 2.11.0