index 8012ecc0a905471587f0ecb1f17022e35d86787d..e0fd66ca26148cd2c29f9cd92d46e97b04b53bd8 100644 (file)
#include "drm_fourcc.h"
#include "libkms.h"
-#ifdef HAVE_CAIRO
-#include <math.h>
-#include <cairo.h>
-#endif
+#include "buffers.h"
drmModeRes *resources;
int fd, modes;
type_name_fn(connector_type)
+#define bit_name_fn(res) \
+char * res##_str(int type) { \
+ int i; \
+ const char *sep = ""; \
+ for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \
+ if (type & (1 << i)) { \
+ printf("%s%s", sep, res##_names[i]); \
+ sep = ", "; \
+ } \
+ } \
+}
+
+static const char *mode_type_names[] = {
+ "builtin",
+ "clock_c",
+ "crtc_c",
+ "preferred",
+ "default",
+ "userdef",
+ "driver",
+};
+
+bit_name_fn(mode_type)
+
+static const char *mode_flag_names[] = {
+ "phsync",
+ "nhsync",
+ "pvsync",
+ "nvsync",
+ "interlace",
+ "dblscan",
+ "csync",
+ "pcsync",
+ "ncsync",
+ "hskew",
+ "bcast",
+ "pixmux",
+ "dblclk",
+ "clkdiv2"
+};
+
+bit_name_fn(mode_flag)
+
void dump_encoders(void)
{
drmModeEncoder *encoder;
void dump_mode(drmModeModeInfo *mode)
{
- printf("\t%s %d %d %d %d %d %d %d %d %d\n",
+ printf(" %s %d %d %d %d %d %d %d %d %d",
mode->name,
mode->vrefresh,
mode->hdisplay,
mode->vsync_start,
mode->vsync_end,
mode->vtotal);
+
+ printf(" flags: ");
+ mode_flag_str(mode->flags);
+ printf("; type: ");
+ mode_type_str(mode->type);
+ printf("\n");
}
static void
printf(" immutable");
if (prop->flags & DRM_MODE_PROP_ENUM)
printf(" enum");
+ if (prop->flags & DRM_MODE_PROP_BITMASK)
+ printf(" bitmask");
if (prop->flags & DRM_MODE_PROP_BLOB)
printf(" blob");
printf("\n");
printf(" %s=%llu", prop->enums[i].name,
prop->enums[i].value);
printf("\n");
+ } else if (prop->flags & DRM_MODE_PROP_BITMASK) {
+ printf("\t\tvalues:");
+ for (i = 0; i < prop->count_enums; i++)
+ printf(" %s=0x%llx", prop->enums[i].name,
+ (1LL << prop->enums[i].value));
+ printf("\n");
} else {
assert(prop->count_enums == 0);
}
void dump_crtcs(void)
{
drmModeCrtc *crtc;
+ drmModeObjectPropertiesPtr props;
int i;
+ uint32_t j;
printf("CRTCs:\n");
printf("id\tfb\tpos\tsize\n");
crtc->width, crtc->height);
dump_mode(&crtc->mode);
+ printf(" props:\n");
+ props = drmModeObjectGetProperties(fd, crtc->crtc_id,
+ DRM_MODE_OBJECT_CRTC);
+ if (props) {
+ for (j = 0; j < props->count_props; j++)
+ dump_prop(props->props[j],
+ props->prop_values[j]);
+ drmModeFreeObjectProperties(props);
+ } else {
+ printf("\tcould not get crtc properties: %s\n",
+ strerror(errno));
+ }
+
drmModeFreeCrtc(crtc);
}
printf("\n");
static void dump_planes(void)
{
+ drmModeObjectPropertiesPtr props;
drmModePlaneRes *plane_resources;
drmModePlane *ovr;
unsigned int i, j;
printf(" %4.4s", (char *)&ovr->formats[j]);
printf("\n");
+ printf(" props:\n");
+ props = drmModeObjectGetProperties(fd, ovr->plane_id,
+ DRM_MODE_OBJECT_PLANE);
+ if (props) {
+ for (j = 0; j < props->count_props; j++)
+ dump_prop(props->props[j],
+ props->prop_values[j]);
+ drmModeFreeObjectProperties(props);
+ } else {
+ printf("\tcould not get plane properties: %s\n",
+ strerror(errno));
+ }
+
drmModeFreePlane(ovr);
}
printf("\n");
return;
}
+/* -----------------------------------------------------------------------------
+ * Connectors and planes
+ */
+
/*
* Mode setting with the kernel interfaces is a bit of a chore.
* First you have to find the connector in question and make sure the
struct connector {
uint32_t id;
char mode_str[64];
+ char format_str[5];
+ unsigned int fourcc;
drmModeModeInfo *mode;
drmModeEncoder *encoder;
int crtc;
uint32_t w, h;
unsigned int fb_id;
char format_str[5]; /* need to leave room for terminating \0 */
+ unsigned int fourcc;
};
static void
}
-static struct kms_bo *
-allocate_buffer(struct kms_driver *kms,
- int width, int height, int *stride)
-{
- 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
- };
- 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));
- return NULL;
- }
-
- ret = kms_bo_get_prop(bo, KMS_PITCH, stride);
- if (ret) {
- fprintf(stderr, "failed to retreive buffer stride: %s\n",
- strerror(-ret));
- kms_bo_destroy(&bo);
- return NULL;
- }
-
- return bo;
-}
-
-static void
-make_pwetty(void *data, int width, int height, int stride)
-{
-#ifdef HAVE_CAIRO
- cairo_surface_t *surface;
- cairo_t *cr;
- int x, y;
-
- surface = cairo_image_surface_create_for_data(data,
- CAIRO_FORMAT_ARGB32,
- width, height,
- stride);
- cr = cairo_create(surface);
- cairo_surface_destroy(surface);
-
- cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
- for (x = 0; x < width; x += 250)
- for (y = 0; y < height; y += 250) {
- char buf[64];
-
- cairo_move_to(cr, x, y - 20);
- cairo_line_to(cr, x, y + 20);
- cairo_move_to(cr, x - 20, y);
- cairo_line_to(cr, x + 20, y);
- cairo_new_sub_path(cr);
- cairo_arc(cr, x, y, 10, 0, M_PI * 2);
- cairo_set_line_width(cr, 4);
- cairo_set_source_rgb(cr, 0, 0, 0);
- cairo_stroke_preserve(cr);
- cairo_set_source_rgb(cr, 1, 1, 1);
- cairo_set_line_width(cr, 2);
- cairo_stroke(cr);
-
- snprintf(buf, sizeof buf, "%d, %d", x, y);
- cairo_move_to(cr, x + 20, y + 20);
- cairo_text_path(cr, buf);
- cairo_set_source_rgb(cr, 0, 0, 0);
- cairo_stroke_preserve(cr);
- cairo_set_source_rgb(cr, 1, 1, 1);
- cairo_fill(cr);
- }
-
- cairo_destroy(cr);
-#endif
-}
-
-static int
-create_test_buffer(struct kms_driver *kms,
- int width, int height, int *stride_out,
- struct kms_bo **bo_out)
-{
- struct kms_bo *bo;
- int ret, i, j, stride;
- void *virtual;
-
- bo = allocate_buffer(kms, width, height, &stride);
- if (!bo)
- return -1;
-
- ret = kms_bo_map(bo, &virtual);
- if (ret) {
- fprintf(stderr, "failed to map buffer: %s\n",
- strerror(-ret));
- kms_bo_destroy(&bo);
- return -1;
- }
-
- /* paint the buffer with colored tiles */
- for (j = 0; j < height; j++) {
- uint32_t *fb_ptr = (uint32_t*)((char*)virtual + j * stride);
- for (i = 0; i < width; i++) {
- div_t d = div(i, width);
- fb_ptr[i] =
- 0x00130502 * (d.quot >> 6) +
- 0x000a1120 * (d.rem >> 6);
- }
- }
-
- make_pwetty(virtual, width, height, stride);
-
- kms_bo_unmap(bo);
-
- *bo_out = bo;
- *stride_out = stride;
- return 0;
-}
-
-static int
-create_grey_buffer(struct kms_driver *kms,
- int width, int height, int *stride_out,
- struct kms_bo **bo_out)
-{
- struct kms_bo *bo;
- int size, ret, stride;
- void *virtual;
-
- bo = allocate_buffer(kms, width, height, &stride);
- if (!bo)
- return -1;
-
- ret = kms_bo_map(bo, &virtual);
- if (ret) {
- fprintf(stderr, "failed to map buffer: %s\n",
- strerror(-ret));
- kms_bo_destroy(&bo);
- return -1;
- }
-
- size = stride * height;
- memset(virtual, 0x77, size);
- kms_bo_unmap(bo);
-
- *bo_out = bo;
- *stride_out = stride;
-
- return 0;
-}
+/* -------------------------------------------------------------------------- */
void
page_flip_handler(int fd, unsigned int frame,
new_fb_id = c->fb_id[1];
else
new_fb_id = c->fb_id[0];
-
+
drmModePageFlip(fd, c->crtc, new_fb_id,
DRM_MODE_PAGE_FLIP_EVENT, c);
c->current_fb_id = new_fb_id;
}
}
-/* swap these for big endian.. */
-#define RED 2
-#define GREEN 1
-#define BLUE 0
-
-static void
-fill420(unsigned char *y, unsigned char *u, unsigned char *v,
- int cs /*chroma pixel stride */,
- int n, int width, int height, int stride)
-{
- int i, j;
-
- /* paint the buffer with colored tiles, in blocks of 2x2 */
- for (j = 0; j < height; j+=2) {
- unsigned char *y1p = y + j * stride;
- unsigned char *y2p = y1p + stride;
- unsigned char *up = u + (j/2) * stride * cs / 2;
- unsigned char *vp = v + (j/2) * stride * cs / 2;
-
- for (i = 0; i < width; i+=2) {
- div_t d = div(n+i+j, width);
- uint32_t rgb = 0x00130502 * (d.quot >> 6) + 0x000a1120 * (d.rem >> 6);
- unsigned char *rgbp = (unsigned char *)&rgb;
- unsigned char y = (0.299 * rgbp[RED]) + (0.587 * rgbp[GREEN]) + (0.114 * rgbp[BLUE]);
-
- *(y2p++) = *(y1p++) = y;
- *(y2p++) = *(y1p++) = y;
-
- *up = (rgbp[BLUE] - y) * 0.565 + 128;
- *vp = (rgbp[RED] - y) * 0.713 + 128;
- up += cs;
- vp += cs;
- }
- }
-}
-
-static void
-fill422(unsigned char *virtual, int n, int width, int height, int stride)
-{
- int i, j;
- /* paint the buffer with colored tiles */
- for (j = 0; j < height; j++) {
- uint8_t *ptr = (uint8_t*)((char*)virtual + j * stride);
- for (i = 0; i < width; i++) {
- div_t d = div(n+i+j, width);
- uint32_t rgb = 0x00130502 * (d.quot >> 6) + 0x000a1120 * (d.rem >> 6);
- unsigned char *rgbp = (unsigned char *)&rgb;
- unsigned char y = (0.299 * rgbp[RED]) + (0.587 * rgbp[GREEN]) + (0.114 * rgbp[BLUE]);
-
- *(ptr++) = y;
- *(ptr++) = (rgbp[BLUE] - y) * 0.565 + 128;
- *(ptr++) = y;
- *(ptr++) = (rgbp[RED] - y) * 0.713 + 128;
- }
- }
-}
-
-static void
-fill1555(unsigned char *virtual, int n, int width, int height, int stride)
-{
- int i, j;
- /* paint the buffer with colored tiles */
- for (j = 0; j < height; j++) {
- uint16_t *ptr = (uint16_t*)((char*)virtual + j * stride);
- for (i = 0; i < width; i++) {
- div_t d = div(n+i+j, width);
- uint32_t rgb = 0x00130502 * (d.quot >> 6) + 0x000a1120 * (d.rem >> 6);
- unsigned char *rgbp = (unsigned char *)&rgb;
-
- *(ptr++) = 0x8000 |
- (rgbp[RED] >> 3) << 10 |
- (rgbp[GREEN] >> 3) << 5 |
- (rgbp[BLUE] >> 3);
- }
- }
-}
-
static int
set_plane(struct kms_driver *kms, struct connector *c, struct plane *p)
{
uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */
uint32_t plane_id = 0;
struct kms_bo *plane_bo;
- uint32_t plane_flags = 0, format;
+ uint32_t plane_flags = 0;
int ret, crtc_x, crtc_y, crtc_w, crtc_h;
unsigned int i;
return -1;
}
- if (!strcmp(p->format_str, "XR24")) {
- if (create_test_buffer(kms, p->w, p->h, &pitches[0], &plane_bo))
- return -1;
- kms_bo_get_prop(plane_bo, KMS_HANDLE, &handles[0]);
- format = DRM_FORMAT_XRGB8888;
- } else {
- void *virtual;
-
- /* TODO: this always allocates a buffer for 32bpp RGB.. but for
- * YUV formats, we don't use all of it.. since 4bytes/pixel is
- * worst case, so live with it for now and just don't use all
- * the buffer:
- */
- plane_bo = allocate_buffer(kms, p->w, p->h, &pitches[0]);
- if (!plane_bo)
- return -1;
-
- ret = kms_bo_map(plane_bo, &virtual);
- if (ret) {
- fprintf(stderr, "failed to map buffer: %s\n",
- strerror(-ret));
- kms_bo_destroy(&plane_bo);
- return -1;
- }
-
- /* just testing a limited # of formats to test single
- * and multi-planar path.. would be nice to add more..
- */
- if (!strcmp(p->format_str, "YUYV")) {
- pitches[0] = p->w * 2;
- offsets[0] = 0;
- kms_bo_get_prop(plane_bo, KMS_HANDLE, &handles[0]);
-
- fill422(virtual, 0, p->w, p->h, pitches[0]);
-
- format = DRM_FORMAT_YUYV;
- } else if (!strcmp(p->format_str, "NV12")) {
- pitches[0] = p->w;
- offsets[0] = 0;
- kms_bo_get_prop(plane_bo, KMS_HANDLE, &handles[0]);
- pitches[1] = p->w;
- offsets[1] = p->w * p->h;
- kms_bo_get_prop(plane_bo, KMS_HANDLE, &handles[1]);
-
- fill420(virtual, virtual+offsets[1], virtual+offsets[1]+1,
- 2, 0, p->w, p->h, pitches[0]);
-
- format = DRM_FORMAT_NV12;
- } else if (!strcmp(p->format_str, "YV12")) {
- pitches[0] = p->w;
- offsets[0] = 0;
- kms_bo_get_prop(plane_bo, KMS_HANDLE, &handles[0]);
- pitches[1] = p->w / 2;
- offsets[1] = p->w * p->h;
- kms_bo_get_prop(plane_bo, KMS_HANDLE, &handles[1]);
- pitches[2] = p->w / 2;
- offsets[2] = offsets[1] + (p->w * p->h) / 4;
- kms_bo_get_prop(plane_bo, KMS_HANDLE, &handles[2]);
-
- fill420(virtual, virtual+offsets[1], virtual+offsets[2],
- 1, 0, p->w, p->h, pitches[0]);
-
- format = DRM_FORMAT_YVU420;
- } else if (!strcmp(p->format_str, "XR15")) {
- pitches[0] = p->w * 2;
- offsets[0] = 0;
- kms_bo_get_prop(plane_bo, KMS_HANDLE, &handles[0]);
-
- fill1555(virtual, 0, p->w, p->h, pitches[0]);
-
- format = DRM_FORMAT_XRGB1555;
- } else if (!strcmp(p->format_str, "AR15")) {
- pitches[0] = p->w * 2;
- offsets[0] = 0;
- kms_bo_get_prop(plane_bo, KMS_HANDLE, &handles[0]);
-
- fill1555(virtual, 0, p->w, p->h, pitches[0]);
-
- format = DRM_FORMAT_ARGB1555;
- } else {
- fprintf(stderr, "Unknown format: %s\n", p->format_str);
- return -1;
- }
-
- kms_bo_unmap(plane_bo);
- }
+ plane_bo = create_test_buffer(kms, p->fourcc, p->w, p->h, handles,
+ pitches, offsets, PATTERN_TILES);
+ if (plane_bo == NULL)
+ return -1;
/* just use single plane format for now.. */
- if (drmModeAddFB2(fd, p->w, p->h, format,
+ if (drmModeAddFB2(fd, p->w, p->h, p->fourcc,
handles, pitches, offsets, &p->fb_id, plane_flags)) {
fprintf(stderr, "failed to add fb: %s\n", strerror(errno));
return -1;
struct kms_driver *kms;
struct kms_bo *bo, *other_bo;
unsigned int fb_id, other_fb_id;
- int i, j, ret, width, height, x, stride;
- unsigned handle;
+ int i, j, ret, width, height, x;
+ uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */
drmEventContext evctx;
width = 0;
return;
}
- if (create_test_buffer(kms, width, height, &stride, &bo))
+ bo = create_test_buffer(kms, c->fourcc, width, height, handles,
+ pitches, offsets, PATTERN_SMPTE);
+ if (bo == NULL)
return;
- kms_bo_get_prop(bo, KMS_HANDLE, &handle);
- ret = drmModeAddFB(fd, width, height, 24, 32, stride, handle, &fb_id);
+ ret = drmModeAddFB2(fd, width, height, c->fourcc,
+ handles, pitches, offsets, &fb_id, 0);
if (ret) {
fprintf(stderr, "failed to add fb (%ux%u): %s\n",
width, height, strerror(errno));
if (c[i].mode == NULL)
continue;
- printf("setting mode %s on connector %d, crtc %d\n",
- c[i].mode_str, c[i].id, c[i].crtc);
+ printf("setting mode %s@%s on connector %d, crtc %d\n",
+ c[i].mode_str, c[i].format_str, c[i].id, c[i].crtc);
ret = drmModeSetCrtc(fd, c[i].crtc, fb_id, x, 0,
&c[i].id, 1, c[i].mode);
if (!page_flip)
return;
- if (create_grey_buffer(kms, width, height, &stride, &other_bo))
+ other_bo = create_test_buffer(kms, c->fourcc, width, height, handles,
+ pitches, offsets, PATTERN_PLAIN);
+ if (other_bo == NULL)
return;
- kms_bo_get_prop(other_bo, KMS_HANDLE, &handle);
- ret = drmModeAddFB(fd, width, height, 32, 32, stride, handle,
- &other_fb_id);
+ ret = drmModeAddFB2(fd, width, height, c->fourcc, handles, pitches, offsets,
+ &other_fb_id, 0);
if (ret) {
fprintf(stderr, "failed to add fb: %s\n", strerror(errno));
return;
extern int optind, opterr, optopt;
static char optstr[] = "ecpmfs:P:v";
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+static int parse_connector(struct connector *c, const char *arg)
+{
+ unsigned int len;
+ const char *p;
+ char *endp;
+
+ c->crtc = -1;
+ strcpy(c->format_str, "XR24");
+
+ c->id = strtoul(arg, &endp, 10);
+ if (*endp == '@') {
+ arg = endp + 1;
+ c->crtc = strtoul(arg, &endp, 10);
+ }
+ if (*endp != ':')
+ return -1;
+
+ arg = endp + 1;
+
+ p = strchrnul(arg, '@');
+ len = min(sizeof c->mode_str - 1, p - arg);
+ strncpy(c->mode_str, arg, len);
+ c->mode_str[len] = '\0';
+
+ if (*p == '@') {
+ strncpy(c->format_str, p + 1, 4);
+ c->format_str[4] = '\0';
+ }
+
+ c->fourcc = format_fourcc(c->format_str);
+ if (c->fourcc == 0) {
+ fprintf(stderr, "unknown format %s\n", c->format_str);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int parse_plane(struct plane *p, const char *arg)
+{
+ strcpy(p->format_str, "XR24");
+
+ if (sscanf(arg, "%d:%dx%d@%4s", &p->con_id, &p->w, &p->h, &p->format_str) != 4 &&
+ sscanf(arg, "%d:%dx%d", &p->con_id, &p->w, &p->h) != 3)
+ return -1;
+
+ p->fourcc = format_fourcc(p->format_str);
+ if (p->fourcc == 0) {
+ fprintf(stderr, "unknown format %s\n", p->format_str);
+ return -1;
+ }
+
+ return 0;
+}
+
void usage(char *name)
{
fprintf(stderr, "usage: %s [-ecpmf]\n", name);
fprintf(stderr, "\t-m\tlist modes\n");
fprintf(stderr, "\t-f\tlist framebuffers\n");
fprintf(stderr, "\t-v\ttest vsynced page flipping\n");
- fprintf(stderr, "\t-s <connector_id>:<mode>\tset a mode\n");
- fprintf(stderr, "\t-s <connector_id>@<crtc_id>:<mode>\tset a mode\n");
- fprintf(stderr, "\t-P <connector_id>:<w>x<h>\tset a plane\n");
- fprintf(stderr, "\t-P <connector_id>:<w>x<h>@<format>\tset a plane\n");
+ fprintf(stderr, "\t-s <connector_id>[@<crtc_id>]:<mode>[@<format>]\tset a mode\n");
+ fprintf(stderr, "\t-P <connector_id>:<w>x<h>[@<format>]\tset a plane\n");
fprintf(stderr, "\n\tDefault is to dump all info.\n");
exit(0);
}
test_vsync = 1;
break;
case 's':
- con_args[count].crtc = -1;
- if (sscanf(optarg, "%d:%64s",
- &con_args[count].id,
- con_args[count].mode_str) != 2 &&
- sscanf(optarg, "%d@%d:%64s",
- &con_args[count].id,
- &con_args[count].crtc,
- con_args[count].mode_str) != 3)
+ if (parse_connector(&con_args[count], optarg) < 0)
usage(argv[0]);
count++;
break;
case 'P':
- strcpy(plane_args[plane_count].format_str, "XR24");
- if (sscanf(optarg, "%d:%dx%d@%4s",
- &plane_args[plane_count].con_id,
- &plane_args[plane_count].w,
- &plane_args[plane_count].h,
- plane_args[plane_count].format_str) != 4 &&
- sscanf(optarg, "%d:%dx%d",
- &plane_args[plane_count].con_id,
- &plane_args[plane_count].w,
- &plane_args[plane_count].h) != 3)
+ if (parse_plane(&plane_args[plane_count], optarg) < 0)
usage(argv[0]);
plane_count++;
break;