Enable NV12 format on Exynos.
BUG=chromium:368775
TEST=HW video overlay works on snow and peach_pi
Change-Id: Ia149618fa086b9ba3ef998149c3557052833e33b
Signed-off-by: Yuly Novikov <ynovikov@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/318550
Reviewed-by: Stéphane Marchesin <marcheu@chromium.org>
#ifdef GBM_EXYNOS
+#include <assert.h>
+#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <xf86drm.h>
#include "gbm_priv.h"
#include "helpers.h"
+#include "util.h"
int gbm_exynos_bo_create(struct gbm_bo *bo, uint32_t width, uint32_t height,
uint32_t format, uint32_t flags)
{
- size_t size = width * height * gbm_bytes_from_format(format);
- struct drm_exynos_gem_create gem_create;
- int ret;
-
- memset(&gem_create, 0, sizeof(gem_create));
- gem_create.size = size;
- gem_create.flags = EXYNOS_BO_NONCONTIG;
-
- ret = drmIoctl(bo->gbm->fd, DRM_IOCTL_EXYNOS_GEM_CREATE, &gem_create);
- if (ret) {
- fprintf(stderr, "minigbm: DRM_IOCTL_EXYNOS_GEM_CREATE failed "
- "(size=%zu)\n", size);
- return ret;
+ size_t plane;
+
+ if (format == GBM_FORMAT_NV12) {
+ uint32_t chroma_height;
+ /* V4L2 s5p-mfc requires width to be 16 byte aligned and height 32. */
+ width = ALIGN(width, 16);
+ height = ALIGN(height, 32);
+ chroma_height = ALIGN(height / 2, 32);
+ bo->strides[0] = bo->strides[1] = width;
+ /* MFC v8+ requires 64 byte padding in the end of luma and chroma buffers. */
+ bo->sizes[0] = bo->strides[0] * height + 64;
+ bo->sizes[1] = bo->strides[1] * chroma_height + 64;
+ bo->offsets[0] = bo->offsets[1] = 0;
+ } else if (format == GBM_FORMAT_XRGB8888 || format == GBM_FORMAT_ARGB8888 ||
+ format == GBM_BO_FORMAT_XRGB8888 || format == GBM_BO_FORMAT_ARGB8888 ) {
+ bo->strides[0] = gbm_stride_from_format(format, width);
+ bo->sizes[0] = height * bo->strides[0];
+ bo->offsets[0] = 0;
+ } else {
+ fprintf(stderr, "minigbm: unsupported format %X\n", format);
+ assert(0);
+ return -EINVAL;
}
- bo->handle.u32 = gem_create.handle;
- bo->size = size;
- bo->stride = width * gbm_bytes_from_format(format);
+ for (plane = 0; plane < bo->num_planes; plane++) {
+ size_t size = bo->sizes[plane];
+ struct drm_exynos_gem_create gem_create;
+ int ret;
+
+ memset(&gem_create, 0, sizeof(gem_create));
+ gem_create.size = size;
+ gem_create.flags = EXYNOS_BO_NONCONTIG;
+
+ ret = drmIoctl(bo->gbm->fd, DRM_IOCTL_EXYNOS_GEM_CREATE, &gem_create);
+ if (ret) {
+ fprintf(stderr, "minigbm: DRM_IOCTL_EXYNOS_GEM_CREATE failed "
+ "(size=%zu)\n", size);
+ return ret;
+ }
+
+ bo->handles[plane].u32 = gem_create.handle;
+ }
return 0;
}
.format_list = {
{GBM_FORMAT_XRGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_CURSOR | GBM_BO_USE_RENDERING | GBM_BO_USE_WRITE},
{GBM_FORMAT_ARGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_CURSOR | GBM_BO_USE_RENDERING | GBM_BO_USE_WRITE},
+ {GBM_FORMAT_NV12, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING | GBM_BO_USE_WRITE},
}
};
* found in the LICENSE file.
*/
+#include <assert.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
static struct gbm_bo *gbm_bo_new(struct gbm_device *gbm,
uint32_t width, uint32_t height,
- uint32_t format, uint32_t stride)
+ uint32_t format)
{
struct gbm_bo *bo;
- bo = (struct gbm_bo*) malloc(sizeof(*bo));
+ bo = (struct gbm_bo*) calloc(1, sizeof(*bo));
if (!bo)
return NULL;
bo->gbm = gbm;
bo->width = width;
bo->height = height;
- bo->stride = stride;
bo->format = format;
- bo->handle.u32 = 0;
- bo->destroy_user_data = NULL;
- bo->user_data = NULL;
+ bo->num_planes = gbm_num_planes_from_format(format);
+ if (!bo->num_planes) {
+ free(bo);
+ return NULL;
+ }
return bo;
}
struct gbm_bo *bo;
int ret;
- bo = gbm_bo_new(gbm, width, height, format,
- width * gbm_bytes_from_format(format));
+ if (!gbm_device_is_format_supported(gbm, format, 0))
+ return NULL;
+
+ bo = gbm_bo_new(gbm, width, height, format);
if (!bo)
return NULL;
if (!gbm_device_is_format_supported(gbm, fd_data->format, usage))
return NULL;
- bo = gbm_bo_new(gbm, fd_data->width, fd_data->height, fd_data->format,
- fd_data->stride);
+ /* This function can support only single plane formats. */
+ /* If multi-plane import is desired, new function should be added. */
+ if (gbm_num_planes_from_format(fd_data->format) != 1)
+ return NULL;
+
+ bo = gbm_bo_new(gbm, fd_data->width, fd_data->height, fd_data->format);
+ bo->strides[0] = fd_data->stride;
+
if (!bo)
return NULL;
return NULL;
}
- bo->handle.u32 = prime_handle.handle;
+ bo->handles[0].u32 = prime_handle.handle;
return bo;
}
PUBLIC uint32_t
gbm_bo_get_stride(struct gbm_bo *bo)
{
- return bo->stride;
+ return gbm_bo_get_plane_stride(bo, 0);
}
PUBLIC uint32_t
gbm_bo_get_stride_or_tiling(struct gbm_bo *bo)
{
- return bo->tiling ? bo->tiling : bo->stride;
+ return bo->tiling ? bo->tiling : gbm_bo_get_stride(bo);
}
PUBLIC uint32_t
PUBLIC union gbm_bo_handle
gbm_bo_get_handle(struct gbm_bo *bo)
{
- return bo->handle;
+ return gbm_bo_get_plane_handle(bo, 0);
}
PUBLIC int
gbm_bo_get_fd(struct gbm_bo *bo)
{
+ return gbm_bo_get_plane_fd(bo, 0);
+}
+
+PUBLIC size_t
+gbm_bo_get_num_planes(struct gbm_bo *bo)
+{
+ return bo->num_planes;
+}
+
+PUBLIC union gbm_bo_handle
+gbm_bo_get_plane_handle(struct gbm_bo *bo, size_t plane)
+{
+ assert(plane < bo->num_planes);
+ return bo->handles[plane];
+}
+
+PUBLIC int
+gbm_bo_get_plane_fd(struct gbm_bo *bo, size_t plane)
+{
int fd;
+ assert(plane < bo->num_planes);
- if (drmPrimeHandleToFD(gbm_device_get_fd(bo->gbm),
- gbm_bo_get_handle(bo).u32,
- DRM_CLOEXEC,
- &fd))
+ if (drmPrimeHandleToFD(
+ gbm_device_get_fd(bo->gbm),
+ gbm_bo_get_plane_handle(bo, plane).u32,
+ DRM_CLOEXEC,
+ &fd))
return -1;
else
return fd;
}
+PUBLIC uint32_t
+gbm_bo_get_plane_offset(struct gbm_bo *bo, size_t plane)
+{
+ assert(plane < bo->num_planes);
+ return bo->offsets[plane];
+}
+
+PUBLIC uint32_t
+gbm_bo_get_plane_size(struct gbm_bo *bo, size_t plane)
+{
+ assert(plane < bo->num_planes);
+ return bo->sizes[plane];
+}
+
+PUBLIC uint32_t
+gbm_bo_get_plane_stride(struct gbm_bo *bo, size_t plane)
+{
+ assert(plane < bo->num_planes);
+ return bo->strides[plane];
+}
+
PUBLIC void
gbm_bo_set_user_data(struct gbm_bo *bo, void *data,
void (*destroy_user_data)(struct gbm_bo *, void *))
/** Format of the allocated buffer */
enum gbm_bo_format {
/** RGB with 8 bits per channel in a 32 bit value */
- GBM_BO_FORMAT_XRGB8888,
+ GBM_BO_FORMAT_XRGB8888,
/** ARGB with 8 bits per channel in a 32 bit value */
GBM_BO_FORMAT_ARGB8888
};
int
gbm_bo_get_fd(struct gbm_bo *bo);
+size_t
+gbm_bo_get_num_planes(struct gbm_bo *bo);
+
+union gbm_bo_handle
+gbm_bo_get_plane_handle(struct gbm_bo *bo, size_t plane);
+
+int
+gbm_bo_get_plane_fd(struct gbm_bo *bo, size_t plane);
+
+uint32_t
+gbm_bo_get_plane_offset(struct gbm_bo *bo, size_t plane);
+
+uint32_t
+gbm_bo_get_plane_size(struct gbm_bo *bo, size_t plane);
+
+uint32_t
+gbm_bo_get_plane_stride(struct gbm_bo *bo, size_t plane);
+
int
gbm_bo_write(struct gbm_bo *bo, const void *buf, size_t count);
#include <stdlib.h>
#include "gbm.h"
+#define GBM_MAX_PLANES 4
+
struct gbm_device
{
int fd;
struct gbm_device *gbm;
uint32_t width;
uint32_t height;
- uint32_t size;
- uint32_t stride;
uint32_t format;
uint32_t tiling;
- union gbm_bo_handle handle;
+ size_t num_planes;
+ union gbm_bo_handle handles[GBM_MAX_PLANES];
+ uint32_t offsets[GBM_MAX_PLANES];
+ uint32_t sizes[GBM_MAX_PLANES];
+ uint32_t strides[GBM_MAX_PLANES];
void *priv;
void *user_data;
void (*destroy_user_data)(struct gbm_bo *, void *);
* found in the LICENSE file.
*/
-#include <stdlib.h>
+#include <assert.h>
+#include <stdbool.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <xf86drm.h>
#include "gbm_priv.h"
#include "helpers.h"
+#include "util.h"
+
+size_t gbm_num_planes_from_format(uint32_t format)
+{
+ if (format == GBM_BO_FORMAT_XRGB8888)
+ format = GBM_FORMAT_XRGB8888;
+ if (format == GBM_BO_FORMAT_ARGB8888)
+ format = GBM_FORMAT_ARGB8888;
+
+ switch(format)
+ {
+ case GBM_FORMAT_C8:
+ case GBM_FORMAT_RGB332:
+ case GBM_FORMAT_BGR233:
+ case GBM_FORMAT_XRGB4444:
+ case GBM_FORMAT_XBGR4444:
+ case GBM_FORMAT_RGBX4444:
+ case GBM_FORMAT_BGRX4444:
+ case GBM_FORMAT_ARGB4444:
+ case GBM_FORMAT_ABGR4444:
+ case GBM_FORMAT_RGBA4444:
+ case GBM_FORMAT_BGRA4444:
+ case GBM_FORMAT_XRGB1555:
+ case GBM_FORMAT_XBGR1555:
+ case GBM_FORMAT_RGBX5551:
+ case GBM_FORMAT_BGRX5551:
+ case GBM_FORMAT_ARGB1555:
+ case GBM_FORMAT_ABGR1555:
+ case GBM_FORMAT_RGBA5551:
+ case GBM_FORMAT_BGRA5551:
+ case GBM_FORMAT_RGB565:
+ case GBM_FORMAT_BGR565:
+ case GBM_FORMAT_YUYV:
+ case GBM_FORMAT_YVYU:
+ case GBM_FORMAT_UYVY:
+ case GBM_FORMAT_VYUY:
+ case GBM_FORMAT_RGB888:
+ case GBM_FORMAT_BGR888:
+ case GBM_FORMAT_XRGB8888:
+ case GBM_FORMAT_XBGR8888:
+ case GBM_FORMAT_RGBX8888:
+ case GBM_FORMAT_BGRX8888:
+ case GBM_FORMAT_ARGB8888:
+ case GBM_FORMAT_ABGR8888:
+ case GBM_FORMAT_RGBA8888:
+ case GBM_FORMAT_BGRA8888:
+ case GBM_FORMAT_XRGB2101010:
+ case GBM_FORMAT_XBGR2101010:
+ case GBM_FORMAT_RGBX1010102:
+ case GBM_FORMAT_BGRX1010102:
+ case GBM_FORMAT_ARGB2101010:
+ case GBM_FORMAT_ABGR2101010:
+ case GBM_FORMAT_RGBA1010102:
+ case GBM_FORMAT_BGRA1010102:
+ case GBM_FORMAT_AYUV:
+ return 1;
+ case GBM_FORMAT_NV12:
+ return 2;
+ }
+
+ fprintf(stderr, "minigbm: UNKNOWN FORMAT %d\n", format);
+ return 0;
+}
int gbm_bpp_from_format(uint32_t format)
{
case GBM_FORMAT_BGR233:
return 8;
+ case GBM_FORMAT_NV12:
+ return 12;
+
case GBM_FORMAT_XRGB4444:
case GBM_FORMAT_XBGR4444:
case GBM_FORMAT_RGBX4444:
return 32;
}
- printf("UNKNOWN FORMAT %d\n", format);
+ fprintf(stderr, "minigbm: UNKNOWN FORMAT %d\n", format);
return 0;
}
-int gbm_bytes_from_format(uint32_t format)
+int gbm_stride_from_format(uint32_t format, uint32_t width)
{
- return gbm_bpp_from_format(format) / 8;
+ /* Only single-plane formats are supported */
+ assert(gbm_num_planes_from_format(format) == 1);
+ return DIV_ROUND_UP(width * gbm_bpp_from_format(format), 8);
}
int gbm_is_format_supported(struct gbm_bo *bo)
struct drm_mode_create_dumb create_dumb;
int ret;
+ /* Only single-plane formats are supported */
+ assert(gbm_num_planes_from_format(format) == 1);
+
memset(&create_dumb, 0, sizeof(create_dumb));
create_dumb.height = height;
create_dumb.width = width;
ret = drmIoctl(bo->gbm->fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb);
if (ret) {
- fprintf(stderr, "minigbm: DRM_IOCTL_MODE_CREATE_DUMB failed "
- "(handle=%x)\n", bo->handle.u32);
+ fprintf(stderr, "minigbm: DRM_IOCTL_MODE_CREATE_DUMB failed\n");
return ret;
}
- bo->handle.u32 = create_dumb.handle;
- bo->size = create_dumb.size;
- bo->stride = create_dumb.pitch;
+ bo->handles[0].u32 = create_dumb.handle;
+ bo->offsets[0] = 0;
+ bo->sizes[0] = create_dumb.size;
+ bo->strides[0] = create_dumb.pitch;
return 0;
}
int ret;
memset(&destroy_dumb, 0, sizeof(destroy_dumb));
- destroy_dumb.handle = bo->handle.u32;
+ destroy_dumb.handle = bo->handles[0].u32;
ret = drmIoctl(bo->gbm->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_dumb);
if (ret) {
fprintf(stderr, "minigbm: DRM_IOCTL_MODE_DESTROY_DUMB failed "
- "(handle=%x)\n", bo->handle.u32);
+ "(handle=%x)\n", bo->handles[0].u32);
return ret;
}
int gbm_gem_bo_destroy(struct gbm_bo *bo)
{
struct drm_gem_close gem_close;
- int ret;
-
- memset(&gem_close, 0, sizeof(gem_close));
- gem_close.handle = bo->handle.u32;
-
- ret = drmIoctl(bo->gbm->fd, DRM_IOCTL_GEM_CLOSE, &gem_close);
- if (ret) {
- fprintf(stderr, "minigbm: DRM_IOCTL_GEM_CLOSE failed "
- "(handle=%x)\n", bo->handle.u32);
- return ret;
+ int ret, error = 0;
+ size_t plane, i;
+
+ for (plane = 0; plane < bo->num_planes; plane++) {
+ bool already_closed = false;
+ for (i = 1; i < plane && !already_closed; i++)
+ if (bo->handles[i-1].u32 == bo->handles[plane].u32)
+ already_closed = true;
+ if (already_closed)
+ continue;
+
+ memset(&gem_close, 0, sizeof(gem_close));
+ gem_close.handle = bo->handles[plane].u32;
+
+ ret = drmIoctl(bo->gbm->fd, DRM_IOCTL_GEM_CLOSE, &gem_close);
+ if (ret) {
+ fprintf(stderr, "minigbm: DRM_IOCTL_GEM_CLOSE failed "
+ "(handle=%x) error %d\n",
+ bo->handles[plane].u32, ret);
+ error = ret;
+ }
}
- return 0;
+ return error;
}
#ifndef HELPERS_H
#define HELPERS_H
+size_t gbm_num_planes_from_format(uint32_t format);
int gbm_bpp_from_format(uint32_t format);
-int gbm_bytes_from_format(uint32_t format);
+int gbm_stride_from_format(uint32_t format, uint32_t width);
int gbm_is_format_supported(struct gbm_bo *bo);
int gbm_dumb_bo_create(struct gbm_bo *bo, uint32_t width, uint32_t height,
uint32_t format, uint32_t flags);
uint32_t format, uint32_t flags)
{
struct gbm_device *gbm = bo->gbm;
- int bpp = gbm_bytes_from_format(format);
+ int bpp = gbm_stride_from_format(format, 1);
struct drm_i915_gem_create gem_create;
struct drm_i915_gem_set_tiling gem_set_tiling;
uint32_t tiling_mode = I915_TILING_NONE;
i915_align_dimensions(gbm, tiling_mode, &width, &height, bpp);
- bo->stride = width * bpp;
+ bo->strides[0] = width * bpp;
- if (!i915_verify_dimensions(gbm, bo->stride, height))
+ if (!i915_verify_dimensions(gbm, bo->strides[0], height))
return EINVAL;
memset(&gem_create, 0, sizeof(gem_create));
"(size=%zu)\n", size);
return ret;
}
- bo->handle.u32 = gem_create.handle;
- bo->size = size;
+ bo->handles[0].u32 = gem_create.handle;
+ bo->sizes[0] = size;
+ bo->offsets[0] = 0;
memset(&gem_set_tiling, 0, sizeof(gem_set_tiling));
do {
- gem_set_tiling.handle = bo->handle.u32;
+ gem_set_tiling.handle = bo->handles[0].u32;
gem_set_tiling.tiling_mode = tiling_mode;
- gem_set_tiling.stride = bo->stride;
+ gem_set_tiling.stride = bo->strides[0];
ret = drmIoctl(gbm->fd, DRM_IOCTL_I915_GEM_SET_TILING,
&gem_set_tiling);
} while (ret == -1 && (errno == EINTR || errno == EAGAIN));
if (ret == -1) {
struct drm_gem_close gem_close;
- gem_close.handle = bo->handle.u32;
+ gem_close.handle = bo->handles[0].u32;
fprintf(stderr, "minigbm: DRM_IOCTL_I915_GEM_SET_TILING failed "
"errno=%x (handle=%x, tiling=%x, stride=%x)\n",
errno,
int gbm_mediatek_bo_create(struct gbm_bo *bo, uint32_t width, uint32_t height,
uint32_t format, uint32_t flags)
{
- size_t size = width * height * gbm_bytes_from_format(format);
+ size_t size;
struct drm_mtk_gem_create gem_create;
int ret;
+ bo->strides[0] = gbm_stride_from_format(format, width);
+ size = height * bo->strides[0];
+
memset(&gem_create, 0, sizeof(gem_create));
gem_create.size = size;
return ret;
}
- bo->handle.u32 = gem_create.handle;
- bo->size = size;
- bo->stride = width * gbm_bytes_from_format(format);
+ bo->handles[0].u32 = gem_create.handle;
+ bo->sizes[0] = size;
+ bo->offsets[0] = 0;
return 0;
}
int gbm_rockchip_bo_create(struct gbm_bo *bo, uint32_t width, uint32_t height,
uint32_t format, uint32_t flags)
{
- size_t size = width * height * gbm_bytes_from_format(format);
+ size_t size;
struct drm_rockchip_gem_create gem_create;
int ret;
+ bo->strides[0] = gbm_stride_from_format(format, width);
+ size = height * bo->strides[0];
+
memset(&gem_create, 0, sizeof(gem_create));
gem_create.size = size;
return ret;
}
- bo->handle.u32 = gem_create.handle;
- bo->size = size;
- bo->stride = width * gbm_bytes_from_format(format);
+ bo->handles[0].u32 = gem_create.handle;
+ bo->sizes[0] = size;
+ bo->offsets[0] = 0;
return 0;
}
#include "gbm_priv.h"
#include "helpers.h"
+#include "util.h"
/*
* GOB (Group Of Bytes) is the basic unit of the blocklinear layout.
return block_height_log2;
}
-static inline uint32_t align_up(uint32_t value, uint32_t alignment)
-{
- return (value + (alignment-1)) & ~(alignment-1);
-}
-
static void compute_layout_blocklinear(int width, int height, int format,
enum nv_mem_kind *kind,
uint32_t *block_height_log2,
uint32_t *stride, uint32_t *size)
{
- int pitch = width * gbm_bytes_from_format(format);
+ int pitch = gbm_stride_from_format(format, width);
/* Align to blocklinear blocks. */
- pitch = align_up(pitch, NV_BLOCKLINEAR_GOB_WIDTH);
+ pitch = ALIGN(pitch, NV_BLOCKLINEAR_GOB_WIDTH);
/* Compute padded height. */
*block_height_log2 = compute_block_height_log2(height);
int block_height = 1 << *block_height_log2;
int padded_height =
- align_up(height, NV_BLOCKLINEAR_GOB_HEIGHT * block_height);
+ ALIGN(height, NV_BLOCKLINEAR_GOB_HEIGHT * block_height);
int bytes = pitch * padded_height;
* This will reduce the required page table size (see discussion in NV
* bug 1321091), and also acts as a WAR for NV bug 1325421.
*/
- bytes = align_up(bytes, NV_PREFERRED_PAGE_SIZE);
+ bytes = ALIGN(bytes, NV_PREFERRED_PAGE_SIZE);
*kind = NV_MEM_KIND_GENERIC_16Bx2;
*stride = pitch;
static void compute_layout_linear(int width, int height, int format,
uint32_t *stride, uint32_t *size)
{
- *stride = width * gbm_bytes_from_format(format);
+ *stride = gbm_stride_from_format(format, width);
*size = *stride * height;
}
return ret;
}
- bo->handle.u32 = gem_create.handle;
- bo->size = size;
- bo->stride = stride;
+ bo->handles[0].u32 = gem_create.handle;
+ bo->offsets[0] = 0;
+ bo->sizes[0] = size;
+ bo->strides[0] = stride;
if (kind != NV_MEM_KIND_PITCH) {
struct drm_tegra_gem_set_tiling gem_tile;
memset(&gem_tile, 0, sizeof(gem_tile));
- gem_tile.handle = bo->handle.u32;
+ gem_tile.handle = bo->handles[0].u32;
gem_tile.mode = DRM_TEGRA_GEM_TILING_MODE_BLOCK;
gem_tile.value = block_height_log2;
#define ARRAY_SIZE(A) (sizeof(A)/sizeof(*(A)))
#define PUBLIC __attribute__((visibility("default")))
#define ALIGN(A, B) (((A) + (B) - 1) / (B) * (B))
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
#endif