atomictest: add NV12 support

Make atomictest support NV12 format.
Conversion from RGB to YUV is done in software using the same matrix
than for modetest.
Remove bbp parameter from create_sp_bo because it is link to plane format.

Change-Id: I2f844b24d11fca65310668522bca4427c2c5e4ef
Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
diff --git a/tests/planetest/atomictest.c b/tests/planetest/atomictest.c
index 6df3f16..5fec911 100644
--- a/tests/planetest/atomictest.c
+++ b/tests/planetest/atomictest.c
@@ -91,8 +91,7 @@
 			goto out;
 		}
 
-		plane[i]->bo = create_sp_bo(dev, plane_w, plane_h, 16, 32,
-				plane[i]->format, 0);
+		plane[i]->bo = create_sp_bo(dev, plane_w, plane_h, 16, plane[i]->format, 0);
 		if (!plane[i]->bo) {
 			printf("failed to create plane bo\n");
 			goto out;
diff --git a/tests/planetest/bo.c b/tests/planetest/bo.c
index 9a71828..d4b82c6 100644
--- a/tests/planetest/bo.c
+++ b/tests/planetest/bo.c
@@ -13,9 +13,46 @@
 #include "bo.h"
 #include "dev.h"
 
+#define MAKE_YUV_601_Y(r, g, b) \
+	((( 66 * (r) + 129 * (g) +  25 * (b) + 128) >> 8) + 16)
+#define MAKE_YUV_601_U(r, g, b) \
+	(((-38 * (r) -  74 * (g) + 112 * (b) + 128) >> 8) + 128)
+#define MAKE_YUV_601_V(r, g, b) \
+	(((112 * (r) -  94 * (g) -  18 * (b) + 128) >> 8) + 128)
+
+static void draw_rect_yuv(struct sp_bo *bo, uint32_t x, uint32_t y, uint32_t width,
+		uint32_t height, uint8_t a, uint8_t r, uint8_t g, uint8_t b)
+{
+	uint32_t i, j, xmax = x + width, ymax = y + height;
+
+	if (xmax > bo->width)
+		xmax = bo->width;
+	if (ymax > bo->height)
+		ymax = bo->height;
+
+	for (i = y; i < ymax; i++) {
+		uint8_t *luma = bo->map_addr + i * bo->pitch;
+
+		for (j = x; j < xmax; j++)
+			luma[j] = MAKE_YUV_601_Y(r, g, b);
+	}
+
+	for (i = y; i < ymax / 2; i++) {
+		uint8_t *chroma = bo->map_addr + (i + height) * bo->pitch;
+
+		for (j = x; j < xmax / 2; j++) {
+			chroma[j*2] = MAKE_YUV_601_U(r, g, b);
+			chroma[j*2 + 1] = MAKE_YUV_601_V(r, g, b);
+		}
+	}
+}
+
 void fill_bo(struct sp_bo *bo, uint8_t a, uint8_t r, uint8_t g, uint8_t b)
 {
-	draw_rect(bo, 0, 0, bo->width, bo->height, a, r, g, b);
+	if (bo->format == DRM_FORMAT_NV12)
+		draw_rect_yuv(bo, 0, 0, bo->width, bo->height, a, r, g, b);
+	else
+		draw_rect(bo, 0, 0, bo->width, bo->height, a, r, g, b);
 }
 
 void draw_rect(struct sp_bo *bo, uint32_t x, uint32_t y, uint32_t width,
@@ -59,6 +96,11 @@
 	handles[0] = bo->handle;
 	pitches[0] = bo->pitch;
 	offsets[0] = 0;
+	if (bo->format == DRM_FORMAT_NV12) {
+		handles[1] = bo->handle;
+		pitches[1] = pitches[0];
+		offsets[1] = pitches[0] * bo->height;
+	}
 
 	ret = drmModeAddFB2(bo->dev->fd, bo->width, bo->height,
 			format, handles, pitches, offsets,
@@ -94,8 +136,21 @@
 	return 0;
 }
 
+static int format_to_bpp(uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_NV12:
+		return 8;
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_RGBA8888:
+	default:
+		return 32;
+	}
+}
+
 struct sp_bo *create_sp_bo(struct sp_dev *dev, uint32_t width, uint32_t height,
-		uint32_t depth, uint32_t bpp, uint32_t format, uint32_t flags)
+		uint32_t depth, uint32_t format, uint32_t flags)
 {
 	int ret;
 	struct drm_mode_create_dumb cd;
@@ -105,9 +160,13 @@
 	if (!bo)
 		return NULL;
 
-	cd.height = height;
+	if (format == DRM_FORMAT_NV12)
+		cd.height = height * 3 / 2;
+	else
+		cd.height = height;
+
 	cd.width = width;
-	cd.bpp = bpp;
+	cd.bpp = format_to_bpp(format);
 	cd.flags = flags;
 
 	ret = drmIoctl(dev->fd, DRM_IOCTL_MODE_CREATE_DUMB, &cd);
@@ -120,7 +179,7 @@
 	bo->width = width;
 	bo->height = height;
 	bo->depth = depth;
-	bo->bpp = bpp;
+	bo->bpp = format_to_bpp(format);
 	bo->format = format;
 	bo->flags = flags;
 
diff --git a/tests/planetest/bo.h b/tests/planetest/bo.h
index 4c5ddf8..7471e12 100644
--- a/tests/planetest/bo.h
+++ b/tests/planetest/bo.h
@@ -23,7 +23,7 @@
 };
 
 struct sp_bo *create_sp_bo(struct sp_dev *dev, uint32_t width, uint32_t height,
-		uint32_t depth, uint32_t bpp, uint32_t format, uint32_t flags);
+		uint32_t depth, uint32_t format, uint32_t flags);
 
 void fill_bo(struct sp_bo *bo, uint8_t a, uint8_t r, uint8_t g, uint8_t b);
 void draw_rect(struct sp_bo *bo, uint32_t x, uint32_t y, uint32_t width,
diff --git a/tests/planetest/dev.c b/tests/planetest/dev.c
index c8277df..bd0968c 100644
--- a/tests/planetest/dev.c
+++ b/tests/planetest/dev.c
@@ -93,7 +93,8 @@
 	for (i = 0; i < plane->plane->count_formats; i++) {
 		if (plane->plane->formats[i] == DRM_FORMAT_XRGB8888 ||
 		    plane->plane->formats[i] == DRM_FORMAT_ARGB8888 ||
-		    plane->plane->formats[i] == DRM_FORMAT_RGBA8888) {
+		    plane->plane->formats[i] == DRM_FORMAT_RGBA8888 ||
+		    plane->plane->formats[i] == DRM_FORMAT_NV12) {
 			*format = plane->plane->formats[i];
 			return 0;
 		}
diff --git a/tests/planetest/planetest.c b/tests/planetest/planetest.c
index 7fcfca6..5e187c9 100644
--- a/tests/planetest/planetest.c
+++ b/tests/planetest/planetest.c
@@ -79,7 +79,7 @@
 			goto out;
 		}
 
-		plane[i]->bo = create_sp_bo(dev, plane_w, plane_h, 16, 32,
+		plane[i]->bo = create_sp_bo(dev, plane_w, plane_h, 16,
 				plane[i]->format, 0);
 		if (!plane[i]->bo) {
 			printf("failed to create plane bo\n");