[PATCH] modetest: Allocate dumb buffers with the correct bpp

Laurent Pinchart laurent.pinchart at ideasonboard.com
Tue Dec 9 14:14:39 PST 2014


The modetest application uses libkms to allocate dumb buffers, leading
to overallocation due to the hardcoded 32 bpp value. This can even cause
failures in drivers when the resulting pitch is too large for the
hardware to handle and gets rejected by the driver when creating the
frame buffer.

Fix this by computing the required bpp value and allocating dumb buffers
directly without going through libkms.

Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
---
 tests/modetest/Android.mk  |   2 +-
 tests/modetest/Makefile.am |   2 -
 tests/modetest/buffers.c   | 216 ++++++++++++++++++++++++++++++++++++---------
 tests/modetest/buffers.h   |   6 +-
 tests/modetest/modetest.c  |  45 +++++-----
 5 files changed, 197 insertions(+), 74 deletions(-)

diff --git a/tests/modetest/Android.mk b/tests/modetest/Android.mk
index 0a32b5f..aee3564 100644
--- a/tests/modetest/Android.mk
+++ b/tests/modetest/Android.mk
@@ -9,6 +9,6 @@ LOCAL_MODULE := modetest
 
 LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/libdrm
 
-LOCAL_SHARED_LIBRARIES := libdrm libkms
+LOCAL_SHARED_LIBRARIES := libdrm
 
 include $(BUILD_EXECUTABLE)
diff --git a/tests/modetest/Makefile.am b/tests/modetest/Makefile.am
index 8fc924a..93820fa 100644
--- a/tests/modetest/Makefile.am
+++ b/tests/modetest/Makefile.am
@@ -4,7 +4,6 @@ AM_CFLAGS = $(filter-out -Wpointer-arith, $(WARN_CFLAGS))
 
 AM_CFLAGS += \
 	-I$(top_srcdir)/include/drm \
-	-I$(top_srcdir)/libkms/ \
 	-I$(top_srcdir)
 
 if HAVE_INSTALL_TESTS
@@ -19,7 +18,6 @@ modetest_SOURCES = $(MODETEST_FILES)
 
 modetest_LDADD = \
 	$(top_builddir)/libdrm.la \
-	$(top_builddir)/libkms/libkms.la \
 	-lpthread
 
 if HAVE_CAIRO
diff --git a/tests/modetest/buffers.c b/tests/modetest/buffers.c
index e725c32..e4e8149 100644
--- a/tests/modetest/buffers.c
+++ b/tests/modetest/buffers.c
@@ -34,9 +34,13 @@
 #include <stdlib.h>
 #include <stdint.h>
 #include <string.h>
+#include <sys/ioctl.h>
 
+#include "drm.h"
 #include "drm_fourcc.h"
-#include "libkms.h"
+
+#include "libdrm.h"
+#include "xf86drm.h"
 
 #include "buffers.h"
 
@@ -47,6 +51,16 @@
 
 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
 
+struct bo
+{
+	int fd;
+	void *ptr;
+	size_t size;
+	size_t offset;
+	size_t pitch;
+	unsigned handle;
+};
+
 /* -----------------------------------------------------------------------------
  * Formats
  */
@@ -1001,48 +1015,82 @@ fill_pattern(unsigned int format, enum fill_pattern pattern, void *planes[3],
  * Buffers management
  */
 
-static struct kms_bo *
-allocate_buffer(struct kms_driver *kms, unsigned int width, unsigned int height,
-		unsigned int *stride)
+static struct bo *
+bo_create_dumb(int fd, unsigned int width, unsigned int height, unsigned int bpp)
 {
-	struct kms_bo *bo;
-	unsigned bo_attribs[] = {
-		KMS_WIDTH,   0,
-		KMS_HEIGHT,  0,
-		KMS_BO_TYPE, KMS_BO_TYPE_SCANOUT_X8R8G8B8,
-		KMS_TERMINATE_PROP_LIST
-	};
+	struct drm_mode_create_dumb arg;
+	struct bo *bo;
 	int ret;
 
-	bo_attribs[1] = width;
-	bo_attribs[3] = height;
-
-	ret = kms_bo_create(kms, bo_attribs, &bo);
-	if (ret) {
-		fprintf(stderr, "failed to alloc buffer: %s\n",
-			strerror(-ret));
+	bo = malloc(sizeof(*bo));
+	if (bo == NULL) {
+		fprintf(stderr, "failed to allocate buffer object\n");
 		return NULL;
 	}
 
-	ret = kms_bo_get_prop(bo, KMS_PITCH, stride);
+	memset(&arg, 0, sizeof(arg));
+	arg.bpp = bpp;
+	arg.width = width;
+	arg.height = height;
+
+	ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &arg);
 	if (ret) {
-		fprintf(stderr, "failed to retreive buffer stride: %s\n",
-			strerror(-ret));
-		kms_bo_destroy(&bo);
+		fprintf(stderr, "failed to create dumb buffer: %s\n",
+			strerror(errno));
+		free(bo);
 		return NULL;
 	}
 
+	bo->fd = fd;
+	bo->handle = arg.handle;
+	bo->size = arg.size;
+	bo->pitch = arg.pitch;
+
 	return bo;
 }
 
-struct kms_bo *
-create_test_buffer(struct kms_driver *kms, unsigned int format,
-		   unsigned int width, unsigned int height,
-		   unsigned int handles[4], unsigned int pitches[4],
-		   unsigned int offsets[4], enum fill_pattern pattern)
+static int bo_map(struct bo *bo, void **out)
+{
+	struct drm_mode_map_dumb arg;
+	void *map;
+	int ret;
+
+	memset(&arg, 0, sizeof(arg));
+	arg.handle = bo->handle;
+
+	ret = drmIoctl(bo->fd, DRM_IOCTL_MODE_MAP_DUMB, &arg);
+	if (ret)
+		return ret;
+
+	map = drm_mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,
+		       bo->fd, arg.offset);
+	if (map == MAP_FAILED)
+		return -EINVAL;
+
+	bo->ptr = map;
+	*out = map;
+
+	return 0;
+}
+
+static void bo_unmap(struct bo *bo)
+{
+	if (!bo->ptr)
+		return;
+
+	drm_munmap(bo->ptr, bo->size);
+	bo->ptr = NULL;
+}
+
+struct bo *
+bo_create(int fd, unsigned int format,
+	  unsigned int width, unsigned int height,
+	  unsigned int handles[4], unsigned int pitches[4],
+	  unsigned int offsets[4], enum fill_pattern pattern)
 {
 	unsigned int virtual_height;
-	struct kms_bo *bo;
+	struct bo *bo;
+	unsigned int bpp;
 	void *planes[3] = { 0, };
 	void *virtual;
 	int ret;
@@ -1050,6 +1098,70 @@ create_test_buffer(struct kms_driver *kms, unsigned int format,
 	switch (format) {
 	case DRM_FORMAT_NV12:
 	case DRM_FORMAT_NV21:
+	case DRM_FORMAT_NV16:
+	case DRM_FORMAT_NV61:
+	case DRM_FORMAT_YUV420:
+	case DRM_FORMAT_YVU420:
+		bpp = 8;
+		break;
+
+	case DRM_FORMAT_ARGB4444:
+	case DRM_FORMAT_XRGB4444:
+	case DRM_FORMAT_ABGR4444:
+	case DRM_FORMAT_XBGR4444:
+	case DRM_FORMAT_RGBA4444:
+	case DRM_FORMAT_RGBX4444:
+	case DRM_FORMAT_BGRA4444:
+	case DRM_FORMAT_BGRX4444:
+	case DRM_FORMAT_ARGB1555:
+	case DRM_FORMAT_XRGB1555:
+	case DRM_FORMAT_ABGR1555:
+	case DRM_FORMAT_XBGR1555:
+	case DRM_FORMAT_RGBA5551:
+	case DRM_FORMAT_RGBX5551:
+	case DRM_FORMAT_BGRA5551:
+	case DRM_FORMAT_BGRX5551:
+	case DRM_FORMAT_RGB565:
+	case DRM_FORMAT_BGR565:
+	case DRM_FORMAT_UYVY:
+	case DRM_FORMAT_VYUY:
+	case DRM_FORMAT_YUYV:
+	case DRM_FORMAT_YVYU:
+		bpp = 16;
+		break;
+
+	case DRM_FORMAT_BGR888:
+	case DRM_FORMAT_RGB888:
+		bpp = 24;
+		break;
+
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_ABGR8888:
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_RGBA8888:
+	case DRM_FORMAT_RGBX8888:
+	case DRM_FORMAT_BGRA8888:
+	case DRM_FORMAT_BGRX8888:
+	case DRM_FORMAT_ARGB2101010:
+	case DRM_FORMAT_XRGB2101010:
+	case DRM_FORMAT_ABGR2101010:
+	case DRM_FORMAT_XBGR2101010:
+	case DRM_FORMAT_RGBA1010102:
+	case DRM_FORMAT_RGBX1010102:
+	case DRM_FORMAT_BGRA1010102:
+	case DRM_FORMAT_BGRX1010102:
+		bpp = 32;
+		break;
+
+	default:
+		fprintf(stderr, "unsupported format 0x%08x\n",  format);
+		return NULL;
+	}
+
+	switch (format) {
+	case DRM_FORMAT_NV12:
+	case DRM_FORMAT_NV21:
 		virtual_height = height * 3 / 2;
 		break;
 
@@ -1063,15 +1175,15 @@ create_test_buffer(struct kms_driver *kms, unsigned int format,
 		break;
 	}
 
-	bo = allocate_buffer(kms, width, virtual_height, &pitches[0]);
+	bo = bo_create_dumb(fd, width, virtual_height, bpp);
 	if (!bo)
 		return NULL;
 
-	ret = kms_bo_map(bo, &virtual);
+	ret = bo_map(bo, &virtual);
 	if (ret) {
 		fprintf(stderr, "failed to map buffer: %s\n",
-			strerror(-ret));
-		kms_bo_destroy(&bo);
+			strerror(-errno));
+		bo_destroy(bo);
 		return NULL;
 	}
 
@@ -1084,8 +1196,8 @@ create_test_buffer(struct kms_driver *kms, unsigned int format,
 	case DRM_FORMAT_YUYV:
 	case DRM_FORMAT_YVYU:
 		offsets[0] = 0;
-		kms_bo_get_prop(bo, KMS_HANDLE, &handles[0]);
-		kms_bo_get_prop(bo, KMS_PITCH, &pitches[0]);
+		handles[0] = bo->handle;
+		pitches[0] = bo->pitch;
 
 		planes[0] = virtual;
 		break;
@@ -1095,11 +1207,11 @@ create_test_buffer(struct kms_driver *kms, unsigned int format,
 	case DRM_FORMAT_NV16:
 	case DRM_FORMAT_NV61:
 		offsets[0] = 0;
-		kms_bo_get_prop(bo, KMS_HANDLE, &handles[0]);
-		kms_bo_get_prop(bo, KMS_PITCH, &pitches[0]);
+		handles[0] = bo->handle;
+		pitches[0] = bo->pitch;
 		pitches[1] = pitches[0];
 		offsets[1] = pitches[0] * height;
-		kms_bo_get_prop(bo, KMS_HANDLE, &handles[1]);
+		handles[1] = bo->handle;
 
 		planes[0] = virtual;
 		planes[1] = virtual + offsets[1];
@@ -1108,14 +1220,14 @@ create_test_buffer(struct kms_driver *kms, unsigned int format,
 	case DRM_FORMAT_YUV420:
 	case DRM_FORMAT_YVU420:
 		offsets[0] = 0;
-		kms_bo_get_prop(bo, KMS_HANDLE, &handles[0]);
-		kms_bo_get_prop(bo, KMS_PITCH, &pitches[0]);
+		handles[0] = bo->handle;
+		pitches[0] = bo->pitch;
 		pitches[1] = pitches[0] / 2;
 		offsets[1] = pitches[0] * height;
-		kms_bo_get_prop(bo, KMS_HANDLE, &handles[1]);
+		handles[1] = bo->handle;
 		pitches[2] = pitches[1];
 		offsets[2] = offsets[1] + pitches[1] * height / 2;
-		kms_bo_get_prop(bo, KMS_HANDLE, &handles[2]);
+		handles[2] = bo->handle;
 
 		planes[0] = virtual;
 		planes[1] = virtual + offsets[1];
@@ -1159,15 +1271,31 @@ create_test_buffer(struct kms_driver *kms, unsigned int format,
 	case DRM_FORMAT_BGRA1010102:
 	case DRM_FORMAT_BGRX1010102:
 		offsets[0] = 0;
-		kms_bo_get_prop(bo, KMS_HANDLE, &handles[0]);
-		kms_bo_get_prop(bo, KMS_PITCH, &pitches[0]);
+		handles[0] = bo->handle;
+		pitches[0] = bo->pitch;
 
 		planes[0] = virtual;
 		break;
 	}
 
 	fill_pattern(format, pattern, planes, width, height, pitches[0]);
-	kms_bo_unmap(bo);
+	bo_unmap(bo);
 
 	return bo;
 }
+
+void bo_destroy(struct bo *bo)
+{
+	struct drm_mode_destroy_dumb arg;
+	int ret;
+
+	memset(&arg, 0, sizeof(arg));
+	arg.handle = bo->handle;
+
+	ret = drmIoctl(bo->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg);
+	if (ret)
+		fprintf(stderr, "failed to destroy dumb buffer: %s\n",
+			strerror(errno));
+
+	free(bo);
+}
diff --git a/tests/modetest/buffers.h b/tests/modetest/buffers.h
index e320389..ad73d0e 100644
--- a/tests/modetest/buffers.h
+++ b/tests/modetest/buffers.h
@@ -27,8 +27,7 @@
 #ifndef __BUFFERS_H__
 #define __BUFFERS_H__
 
-struct kms_bo;
-struct kms_driver;
+struct bo;
 
 enum fill_pattern {
 	PATTERN_TILES = 0,
@@ -36,10 +35,11 @@ enum fill_pattern {
 	PATTERN_SMPTE = 2,
 };
 
-struct kms_bo *create_test_buffer(struct kms_driver *kms, unsigned int format,
+struct bo *bo_create(int fd, unsigned int format,
 		   unsigned int width, unsigned int height,
 		   unsigned int handles[4], unsigned int pitches[4],
 		   unsigned int offsets[4], enum fill_pattern pattern);
+void bo_destroy(struct bo *bo);
 
 unsigned int format_fourcc(const char *name);
 
diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c
index 2c9a17a..4b9cf2f 100644
--- a/tests/modetest/modetest.c
+++ b/tests/modetest/modetest.c
@@ -57,7 +57,6 @@
 #include "xf86drm.h"
 #include "xf86drmMode.h"
 #include "drm_fourcc.h"
-#include "libkms.h"
 
 #include "buffers.h"
 #include "cursor.h"
@@ -104,14 +103,13 @@ struct device {
 	int fd;
 
 	struct resources *resources;
-	struct kms_driver *kms;
 
 	struct {
 		unsigned int width;
 		unsigned int height;
 
 		unsigned int fb_id;
-		struct kms_bo *bo;
+		struct bo *bo;
 	} mode;
 };
 
@@ -968,7 +966,7 @@ static int set_plane(struct device *dev, struct plane_arg *p)
 	drmModePlane *ovr;
 	uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */
 	uint32_t plane_id = 0;
-	struct kms_bo *plane_bo;
+	struct bo *plane_bo;
 	uint32_t plane_flags = 0;
 	int crtc_x, crtc_y, crtc_w, crtc_h;
 	struct crtc *crtc = NULL;
@@ -1009,8 +1007,8 @@ static int set_plane(struct device *dev, struct plane_arg *p)
 	fprintf(stderr, "testing %dx%d@%s overlay plane %u\n",
 		p->w, p->h, p->format_str, plane_id);
 
-	plane_bo = create_test_buffer(dev->kms, p->fourcc, p->w, p->h, handles,
-				      pitches, offsets, PATTERN_TILES);
+	plane_bo = bo_create(dev->fd, p->fourcc, p->w, p->h, handles,
+			     pitches, offsets, PATTERN_TILES);
 	if (plane_bo == NULL)
 		return -1;
 
@@ -1050,7 +1048,7 @@ static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int co
 {
 	uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */
 	unsigned int fb_id;
-	struct kms_bo *bo;
+	struct bo *bo;
 	unsigned int i;
 	unsigned int j;
 	int ret, x;
@@ -1070,9 +1068,8 @@ static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int co
 			dev->mode.height = pipe->mode->vdisplay;
 	}
 
-	bo = create_test_buffer(dev->kms, pipes[0].fourcc,
-				dev->mode.width, dev->mode.height,
-				handles, pitches, offsets, PATTERN_SMPTE);
+	bo = bo_create(dev->fd, pipes[0].fourcc, dev->mode.width, dev->mode.height,
+		       handles, pitches, offsets, PATTERN_SMPTE);
 	if (bo == NULL)
 		return;
 
@@ -1129,7 +1126,7 @@ static void set_planes(struct device *dev, struct plane_arg *p, unsigned int cou
 static void set_cursors(struct device *dev, struct pipe_arg *pipes, unsigned int count)
 {
 	uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */
-	struct kms_bo *bo;
+	struct bo *bo;
 	unsigned int i;
 	int ret;
 
@@ -1140,8 +1137,8 @@ static void set_cursors(struct device *dev, struct pipe_arg *pipes, unsigned int
 	/* create cursor bo.. just using PATTERN_PLAIN as it has
 	 * translucent alpha
 	 */
-	bo = create_test_buffer(dev->kms, DRM_FORMAT_ARGB8888,
-			cw, ch, handles, pitches, offsets, PATTERN_PLAIN);
+	bo = bo_create(dev->fd, DRM_FORMAT_ARGB8888, cw, ch, handles, pitches,
+		       offsets, PATTERN_PLAIN);
 	if (bo == NULL)
 		return;
 
@@ -1170,14 +1167,14 @@ static void test_page_flip(struct device *dev, struct pipe_arg *pipes, unsigned
 {
 	uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */
 	unsigned int other_fb_id;
-	struct kms_bo *other_bo;
+	struct bo *other_bo;
 	drmEventContext evctx;
 	unsigned int i;
 	int ret;
 
-	other_bo = create_test_buffer(dev->kms, pipes[0].fourcc,
-				      dev->mode.width, dev->mode.height,
-				      handles, pitches, offsets, PATTERN_PLAIN);
+	other_bo = bo_create(dev->fd, pipes[0].fourcc,
+			     dev->mode.width, dev->mode.height,
+			     handles, pitches, offsets, PATTERN_PLAIN);
 	if (other_bo == NULL)
 		return;
 
@@ -1252,7 +1249,7 @@ static void test_page_flip(struct device *dev, struct pipe_arg *pipes, unsigned
 		drmHandleEvent(dev->fd, &evctx);
 	}
 
-	kms_bo_destroy(&other_bo);
+	bo_destroy(other_bo);
 }
 
 #define min(a, b)	((a) < (b) ? (a) : (b))
@@ -1611,10 +1608,11 @@ int main(int argc, char **argv)
 		set_property(&dev, &prop_args[i]);
 
 	if (count || plane_count) {
-		ret = kms_create(dev.fd, &dev.kms);
-		if (ret) {
-			fprintf(stderr, "failed to create kms driver: %s\n",
-				strerror(-ret));
+		uint64_t cap = 0;
+
+		ret = drmGetCap(dev.fd, DRM_CAP_DUMB_BUFFER, &cap);
+		if (ret || cap == 0) {
+			fprintf(stderr, "driver doesn't support the dumb buffer API\n");
 			return 1;
 		}
 
@@ -1638,8 +1636,7 @@ int main(int argc, char **argv)
 		if (test_cursor)
 			clear_cursors(&dev);
 
-		kms_bo_destroy(&dev.mode.bo);
-		kms_destroy(&dev.kms);
+		bo_destroy(dev.mode.bo);
 	}
 
 	free_resources(dev.resources);
-- 
Regards,

Laurent Pinchart



More information about the dri-devel mailing list