diff --git a/kmscube.c b/kmscube.c
index a37190959e99a51858a574b16e3749e04fc13ee5..df2731d528971b5b8cd634bf737522d693173c80 100644 (file)
--- a/kmscube.c
+++ b/kmscube.c
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
+#include <stdbool.h>
#include <unistd.h>
#include <errno.h>
+#include <signal.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
+#include <drm_fourcc.h>
#include <gbm.h>
#include "esUtil.h"
uint8_t DISP_ID = 0;
uint8_t all_display = 0;
int8_t connector_id = -1;
+char* device = "/dev/dri/card0";
static struct {
EGLDisplay display;
uint32_t connector_id[MAX_DISPLAYS];
uint32_t resource_id;
uint32_t encoder[MAX_DISPLAYS];
+ uint32_t format[MAX_DISPLAYS];
drmModeModeInfo *mode[MAX_DISPLAYS];
drmModeConnector *connectors[MAX_DISPLAYS];
} drm;
uint32_t fb_id;
};
+static uint32_t drm_fmt_to_gbm_fmt(uint32_t fmt)
+{
+ switch (fmt) {
+ case DRM_FORMAT_XRGB8888:
+ return GBM_FORMAT_XRGB8888;
+ case DRM_FORMAT_ARGB8888:
+ return GBM_FORMAT_ARGB8888;
+ case DRM_FORMAT_RGB565:
+ return GBM_FORMAT_RGB565;
+ default:
+ printf("Unsupported DRM format: 0x%x", fmt);
+ return GBM_FORMAT_XRGB8888;
+ }
+}
+
+static bool search_plane_format(uint32_t desired_format, int formats_count, uint32_t* formats)
+{
+ int i;
+
+ for ( i = 0; i < formats_count; i++)
+ {
+ if (desired_format == formats[i])
+ return true;
+ }
+
+ return false;
+}
+
+int get_drm_prop_val(int fd, drmModeObjectPropertiesPtr props,
+ const char *name, unsigned int *p_val) {
+ drmModePropertyPtr p;
+ unsigned int i, prop_id = 0; /* Property ID should always be > 0 */
+
+ for (i = 0; !prop_id && i < props->count_props; i++) {
+ p = drmModeGetProperty(fd, props->props[i]);
+ if (!strcmp(p->name, name)){
+ prop_id = p->prop_id;
+ break;
+ }
+ drmModeFreeProperty(p);
+ }
+
+ if (!prop_id) {
+ printf("Could not find %s property\n", name);
+ return(-1);
+ }
+
+ drmModeFreeProperty(p);
+ *p_val = props->prop_values[i];
+ return 0;
+}
+
+static bool set_drm_format(void)
+{
+ /* desired DRM format in order */
+ static const uint32_t drm_formats[] = {DRM_FORMAT_XRGB8888, DRM_FORMAT_ARGB8888, DRM_FORMAT_RGB565};
+ drmModePlaneRes *plane_res;
+ bool found = false;
+ int i,k;
+
+ drmSetClientCap(drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
+
+ plane_res = drmModeGetPlaneResources(drm.fd);
+
+ if (!plane_res) {
+ printf("drmModeGetPlaneResources failed: %s\n", strerror(errno));
+ drmSetClientCap(drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 0);
+ return false;
+ }
+
+ /*
+ * find the plane connected to crtc_id (the primary plane) and then find the desired pixel format
+ * from the plane format list
+ */
+ for (i = 0; i < plane_res->count_planes; i++)
+ {
+ drmModePlane *plane = drmModeGetPlane(drm.fd, plane_res->planes[i]);
+ drmModeObjectProperties *props;
+ unsigned int plane_type;
+
+ if(plane == NULL)
+ continue;
+
+ props = drmModeObjectGetProperties(drm.fd, plane->plane_id, DRM_MODE_OBJECT_PLANE);
+
+ if(props == NULL){
+ printf("plane (%d) properties not found\n", plane->plane_id);
+ drmModeFreePlane(plane);
+ continue;
+ }
+
+ if(get_drm_prop_val(drm.fd, props, "type", &plane_type) < 0)
+ {
+ printf("plane (%d) type value not found\n", plane->plane_id);
+ drmModeFreeObjectProperties(props);
+ drmModeFreePlane(plane);
+ continue;
+ }
+
+ if (plane_type != DRM_PLANE_TYPE_PRIMARY)
+ {
+ drmModeFreeObjectProperties(props);
+ drmModeFreePlane(plane);
+ continue;
+ }
+ else if (!plane->crtc_id)
+ {
+ plane->crtc_id = drm.crtc_id[drm.ndisp];
+ }
+
+ drmModeFreeObjectProperties(props);
+
+ if (plane->crtc_id == drm.crtc_id[drm.ndisp])
+ {
+ for (k = 0; k < ARRAY_SIZE(drm_formats); k++)
+ {
+ if (search_plane_format(drm_formats[k], plane->count_formats, plane->formats))
+ {
+ drm.format[drm.ndisp] = drm_formats[k];
+ drmModeFreePlane(plane);
+ drmModeFreePlaneResources(plane_res);
+ drmSetClientCap(drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 0);
+ return true;
+ }
+ }
+ }
+
+ drmModeFreePlane(plane);
+ }
+
+ drmModeFreePlaneResources(plane_res);
+ drmSetClientCap(drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 0);
+ return false;
+}
+
static int init_drm(void)
{
- static const char *modules[] = {
- "omapdrm", "i915", "radeon", "nouveau", "vmwgfx", "exynos"
- };
drmModeRes *resources;
drmModeConnector *connector = NULL;
drmModeEncoder *encoder = NULL;
- int i, j;
- uint32_t maxRes, curRes;
+ drmModeCrtc *crtc = NULL;
- for (i = 0; i < ARRAY_SIZE(modules); i++) {
- printf("trying to load module %s...", modules[i]);
- drm.fd = drmOpen(modules[i], NULL);
- if (drm.fd < 0) {
- printf("failed.\n");
- } else {
- printf("success.\n");
- break;
- }
- }
+ int i, j, k;
+ uint32_t maxRes, curRes;
+ /* Open default dri device */
+ drm.fd = open(device, O_RDWR | O_CLOEXEC);
if (drm.fd < 0) {
- printf("could not open drm device\n");
+ printf("could not open drm device %s\n", device);
return -1;
}
for (i = 0; i < resources->count_connectors; i++) {
connector = drmModeGetConnector(drm.fd, resources->connectors[i]);
if (connector->connection == DRM_MODE_CONNECTED) {
- /* choose the first supported mode */
- drm.mode[drm.ndisp] = &connector->modes[0];
- drm.connector_id[drm.ndisp] = connector->connector_id;
- for (j=0; j<resources->count_encoders; j++) {
- encoder = drmModeGetEncoder(drm.fd, resources->encoders[j]);
+ /* find the matched encoders */
+ for (j=0; j<connector->count_encoders; j++) {
+ encoder = drmModeGetEncoder(drm.fd, connector->encoders[j]);
+
+ /* Take the fisrt one, if none is assigned */
+ if (!connector->encoder_id)
+ {
+ connector->encoder_id = encoder->encoder_id;
+ }
+
if (encoder->encoder_id == connector->encoder_id)
+ {
+ /* find the first valid CRTC if not assigned */
+ if (!encoder->crtc_id)
+ {
+ for (k = 0; k < resources->count_crtcs; ++k) {
+ /* check whether this CRTC works with the encoder */
+ if (!(encoder->possible_crtcs & (1 << k)))
+ continue;
+
+ encoder->crtc_id = resources->crtcs[k];
+ break;
+ }
+
+ if (!encoder->crtc_id)
+ {
+ printf("Encoder(%d): no CRTC find!\n", encoder->encoder_id);
+ drmModeFreeEncoder(encoder);
+ encoder = NULL;
+ continue;
+ }
+ }
+
break;
+ }
drmModeFreeEncoder(encoder);
encoder = NULL;
}
if (!encoder) {
- printf("no encoder!\n");
- return -1;
+ printf("Connector (%d): no encoder!\n", connector->connector_id);
+ drmModeFreeConnector(connector);
+ continue;
}
+ /* choose the current or first supported mode */
+ crtc = drmModeGetCrtc(drm.fd, encoder->crtc_id);
+ for (j = 0; j < connector->count_modes; j++)
+ {
+ if (crtc->mode_valid)
+ {
+ if ((connector->modes[j].hdisplay == crtc->width) &&
+ (connector->modes[j].vdisplay == crtc->height))
+ {
+ drm.mode[drm.ndisp] = &connector->modes[j];
+ break;
+ }
+ }
+ else
+ {
+ if ((connector->modes[j].hdisplay == crtc->x) &&
+ (connector->modes[j].vdisplay == crtc->y))
+ {
+ drm.mode[drm.ndisp] = &connector->modes[j];
+ break;
+ }
+ }
+ }
+
+ if(j >= connector->count_modes)
+ drm.mode[drm.ndisp] = &connector->modes[0];
+
+ drm.connector_id[drm.ndisp] = connector->connector_id;
+
drm.encoder[drm.ndisp] = (uint32_t) encoder;
drm.crtc_id[drm.ndisp] = encoder->crtc_id;
drm.connectors[drm.ndisp] = connector;
- printf("### Display [%d]: CRTC = %d, Connector = %d\n", drm.ndisp, drm.crtc_id[drm.ndisp], drm.connector_id[drm.ndisp]);
+ if (!set_drm_format())
+ {
+ // Error handling
+ printf("No desired pixel format found!\n");
+ return -1;
+ }
+
+ printf("### Display [%d]: CRTC = %d, Connector = %d, format = 0x%x\n", drm.ndisp, drm.crtc_id[drm.ndisp], drm.connector_id[drm.ndisp], drm.format[drm.ndisp]);
printf("\tMode chosen [%s] : Clock => %d, Vertical refresh => %d, Type => %d\n", drm.mode[drm.ndisp]->name, drm.mode[drm.ndisp]->clock, drm.mode[drm.ndisp]->vrefresh, drm.mode[drm.ndisp]->type);
printf("\tHorizontal => %d, %d, %d, %d, %d\n", drm.mode[drm.ndisp]->hdisplay, drm.mode[drm.ndisp]->hsync_start, drm.mode[drm.ndisp]->hsync_end, drm.mode[drm.ndisp]->htotal, drm.mode[drm.ndisp]->hskew);
printf("\tVertical => %d, %d, %d, %d, %d\n", drm.mode[drm.ndisp]->vdisplay, drm.mode[drm.ndisp]->vsync_start, drm.mode[drm.ndisp]->vsync_end, drm.mode[drm.ndisp]->vtotal, drm.mode[drm.ndisp]->vscan);
gbm.surface = gbm_surface_create(gbm.dev,
drm.mode[DISP_ID]->hdisplay, drm.mode[DISP_ID]->vdisplay,
- GBM_FORMAT_XRGB8888,
+ drm_fmt_to_gbm_fmt(drm.format[DISP_ID]),
GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
if (!gbm.surface) {
printf("failed to create gbm surface\n");
drmModeFreeConnector(drm.connectors[i]);
}
drmModeFreeResources(drm.resource_id);
- drmClose(drm.fd);
+ close(drm.fd);
return;
}
static struct drm_fb * drm_fb_get_from_bo(struct gbm_bo *bo)
{
struct drm_fb *fb = gbm_bo_get_user_data(bo);
- uint32_t width, height, stride, handle;
+ uint32_t width, height, format;
+ uint32_t bo_handles[4] = {0}, offsets[4] = {0}, pitches[4] = {0};
int ret;
if (fb)
width = gbm_bo_get_width(bo);
height = gbm_bo_get_height(bo);
- stride = gbm_bo_get_stride(bo);
- handle = gbm_bo_get_handle(bo).u32;
+ pitches[0] = gbm_bo_get_stride(bo);
+ bo_handles[0] = gbm_bo_get_handle(bo).u32;
+ format = gbm_bo_get_format(bo);
- ret = drmModeAddFB(drm.fd, width, height, 24, 32, stride, handle, &fb->fb_id);
+ ret = drmModeAddFB2(drm.fd, width, height, format, bo_handles, pitches, offsets, &fb->fb_id, 0);
if (ret) {
printf("failed to create fb: %s\n", strerror(errno));
free(fb);
unsigned int sec, unsigned int usec, void *data)
{
int *waiting_for_flip = data;
- *waiting_for_flip = 0;
+ *waiting_for_flip = *waiting_for_flip - 1;
}
void print_usage()
printf("\t-h : Help\n");
printf("\t-a : Enable all displays\n");
printf("\t-c <id> : Display using connector_id [if not specified, use the first connected connector]\n");
+ printf("\t-d /dev/dri/cardX : DRM device to be used. [If not specified, use /dev/dri/card0]\n");
+ printf("\t-n <number> (optional): Number of frames to render\n");
+}
+
+int kms_signalhandler(int signum)
+{
+ switch(signum) {
+ case SIGINT:
+ case SIGTERM:
+ /* Allow the pending page flip requests to be completed before
+ * the teardown sequence */
+ sleep(1);
+ printf("Handling signal number = %d\n", signum);
+ cleanup_kmscube();
+ break;
+ default:
+ printf("Unknown signal\n");
+ break;
+ }
+ exit(1);
}
int main(int argc, char *argv[])
uint32_t i = 0;
int ret;
int opt;
+ int frame_count = -1;
+
+ signal(SIGINT, kms_signalhandler);
+ signal(SIGTERM, kms_signalhandler);
- while ((opt = getopt(argc, argv, "ahc:")) != -1) {
+ while ((opt = getopt(argc, argv, "ahc:d:n:")) != -1) {
switch(opt) {
case 'a':
all_display = 1;
case 'c':
connector_id = atoi(optarg);
break;
+ case 'd':
+ device = optarg;
+ break;
+ case 'n':
+ frame_count = atoi(optarg);
+ break;
+
default:
printf("Undefined option %s\n", argv[optind]);
}
}
- while (1) {
+ while (frame_count != 0) {
struct gbm_bo *next_bo;
- int waiting_for_flip = 1;
+ int waiting_for_flip;
+ int cc;
draw(i++);
* hw composition
*/
- ret = drmModePageFlip(drm.fd, drm.crtc_id[DISP_ID], fb->fb_id,
- DRM_MODE_PAGE_FLIP_EVENT, &waiting_for_flip);
- if (ret) {
- printf("failed to queue page flip: %s\n", strerror(errno));
- return -1;
+ if (all_display) {
+ for (cc=0;cc<drm.ndisp; cc++) {
+ ret = drmModePageFlip(drm.fd, drm.crtc_id[cc], fb->fb_id,
+ DRM_MODE_PAGE_FLIP_EVENT, &waiting_for_flip);
+ if (ret) {
+ printf("failed to queue page flip: %s\n", strerror(errno));
+ return -1;
+ }
+ }
+ waiting_for_flip = drm.ndisp;
+ } else {
+ ret = drmModePageFlip(drm.fd, drm.crtc_id[DISP_ID], fb->fb_id,
+ DRM_MODE_PAGE_FLIP_EVENT, &waiting_for_flip);
+ if (ret) {
+ printf("failed to queue page flip: %s\n", strerror(errno));
+ return -1;
+ }
+ waiting_for_flip = 1;
}
while (waiting_for_flip) {
/* release last buffer to render on again: */
gbm_surface_release_buffer(gbm.surface, bo);
bo = next_bo;
+
+ if(frame_count >= 0)
+ frame_count--;
}
cleanup_kmscube();