On Friday, 2018-07-20 13:33:29 +0200, Benjamin Gaignard wrote: > This is a modetest like tool but using atomic API. > > With modetest_atomic it is mandatory to specify a mode ("-s") > and a plane ("-P") to display a pattern on screen. > > "-v" does a loop swapping between two framebuffers for each > active planes. > > modetest_atomic doesn't offer cursor support > > Signed-off-by: Benjamin Gaignard <benjamin.gaignard@xxxxxxxxxx> > --- > > The code is based on modetest and keep most of it infrastructure > like arguments parsing, finding properties id from their name, > resources dumping or the general way of working. > It duplicates modetest code but adding compilation flags or > conditional tests everywhere in modetest would have made it > more complex and unreadable. I don't have an opinion on whether duplicating the test is the right thing, but if you do, please also duplicate the lines in tests/modetest/meson.build :) > > Creating modetest_atomic could allow to test atomic API without > need to use "big" frameworks like weston, drm_hwcomposer or igt > with all their dependencies. > kmscube could also be used to test atomic API but it need EGL. > > It have been tested (only) on stm driver with one or two planes > actived. > > tests/modetest/Makefile.am | 13 +- > tests/modetest/Makefile.sources | 7 + > tests/modetest/modetest_atomic.c | 1546 ++++++++++++++++++++++++++++++++++++++ > 3 files changed, 1564 insertions(+), 2 deletions(-) > create mode 100644 tests/modetest/modetest_atomic.c > > diff --git a/tests/modetest/Makefile.am b/tests/modetest/Makefile.am > index 4b296c83..8f697bb3 100644 > --- a/tests/modetest/Makefile.am > +++ b/tests/modetest/Makefile.am > @@ -10,10 +10,12 @@ AM_CFLAGS += \ > > if HAVE_INSTALL_TESTS > bin_PROGRAMS = \ > - modetest > + modetest \ > + modetest_atomic > else > noinst_PROGRAMS = \ > - modetest > + modetest \ > + modetest_atomic > endif > > modetest_SOURCES = $(MODETEST_FILES) > @@ -22,3 +24,10 @@ modetest_LDADD = \ > $(top_builddir)/libdrm.la \ > $(top_builddir)/tests/util/libutil.la \ > $(CAIRO_LIBS) > + > +modetest_atomic_SOURCES = $(MODETEST_ATOMIC_FILES) > + > +modetest_atomic_LDADD = \ > + $(top_builddir)/libdrm.la \ > + $(top_builddir)/tests/util/libutil.la \ > + $(CAIRO_LIBS) > diff --git a/tests/modetest/Makefile.sources b/tests/modetest/Makefile.sources > index 399af0df..0a1df4c0 100644 > --- a/tests/modetest/Makefile.sources > +++ b/tests/modetest/Makefile.sources > @@ -4,3 +4,10 @@ MODETEST_FILES := \ > cursor.c \ > cursor.h \ > modetest.c > + > +MODETEST_ATOMIC_FILES := \ > + buffers.c \ > + buffers.h \ > + cursor.c \ > + cursor.h \ > + modetest_atomic.c > diff --git a/tests/modetest/modetest_atomic.c b/tests/modetest/modetest_atomic.c > new file mode 100644 > index 00000000..8c877860 > --- /dev/null > +++ b/tests/modetest/modetest_atomic.c > @@ -0,0 +1,1546 @@ > +/* > + * DRM based mode setting test program > + * Copyright 2008 Tungsten Graphics > + * Jakob Bornecrantz <jakob@xxxxxxxxxxxxxxxxxxxx> > + * Copyright 2008 Intel Corporation > + * Jesse Barnes <jesse.barnes@xxxxxxxxx> > + * > + * Permission is hereby granted, free of charge, to any person obtaining a > + * copy of this software and associated documentation files (the "Software"), > + * to deal in the Software without restriction, including without limitation > + * the rights to use, copy, modify, merge, publish, distribute, sublicense, > + * and/or sell copies of the Software, and to permit persons to whom the > + * Software is furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice shall be included in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE > + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS > + * IN THE SOFTWARE. > + */ > + > +/* > + * This fairly simple test program dumps output in a similar format to the > + * "xrandr" tool everyone knows & loves. It's necessarily slightly different > + * since the kernel separates outputs into encoder and connector structures, > + * each with their own unique ID. The program also allows test testing of the > + * memory management and mode setting APIs by allowing the user to specify a > + * connector and mode to use for mode setting. If all works as expected, a > + * blue background should be painted on the monitor attached to the specified > + * connector after the selected mode is set. > + * > + * TODO: use cairo to write the mode info on the selected output once > + * the mode has been programmed, along with possible test patterns. > + */ > + > +#ifdef HAVE_CONFIG_H > +#include "config.h" > +#endif > + > +#include <assert.h> > +#include <ctype.h> > +#include <stdbool.h> > +#include <stdio.h> > +#include <stdlib.h> > +#include <stdint.h> > +#include <inttypes.h> > +#include <unistd.h> > +#include <string.h> > +#include <strings.h> > +#include <errno.h> > +#include <poll.h> > +#include <sys/time.h> > +#ifdef HAVE_SYS_SELECT_H > +#include <sys/select.h> > +#endif > + > +#include "xf86drm.h" > +#include "xf86drmMode.h" > +#include "drm_fourcc.h" > + > +#include "util/common.h" > +#include "util/format.h" > +#include "util/kms.h" > +#include "util/pattern.h" > + > +#include "buffers.h" > + > +struct crtc { > + drmModeCrtc *crtc; > + drmModeObjectProperties *props; > + drmModePropertyRes **props_info; > + drmModeModeInfo *mode; > +}; > + > +struct encoder { > + drmModeEncoder *encoder; > +}; > + > +struct connector { > + drmModeConnector *connector; > + drmModeObjectProperties *props; > + drmModePropertyRes **props_info; > + char *name; > +}; > + > +struct fb { > + drmModeFB *fb; > +}; > + > +struct plane { > + drmModePlane *plane; > + drmModeObjectProperties *props; > + drmModePropertyRes **props_info; > +}; > + > +struct resources { > + drmModeRes *res; > + drmModePlaneRes *plane_res; > + > + struct crtc *crtcs; > + struct encoder *encoders; > + struct connector *connectors; > + struct fb *fbs; > + struct plane *planes; > +}; > + > +struct device { > + int fd; > + > + struct resources *resources; > + drmModeAtomicReq *req; > +}; > + > +static inline int64_t U642I64(uint64_t val) > +{ > + return (int64_t)*((int64_t *)&val); > +} > + > +#define bit_name_fn(res) \ > +const char * res##_str(int type) { \ > + unsigned 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 = ", "; \ > + } \ > + } \ > + return NULL; \ > +} > + > +static const char *mode_type_names[] = { > + "builtin", > + "clock_c", > + "crtc_c", > + "preferred", > + "default", > + "userdef", > + "driver", > +}; > + > +static 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" > +}; > + > +static bit_name_fn(mode_flag) > + > +static void dump_fourcc(uint32_t fourcc) > +{ > + printf(" %c%c%c%c", > + fourcc, > + fourcc >> 8, > + fourcc >> 16, > + fourcc >> 24); > +} > + > +static void dump_encoders(struct device *dev) > +{ > + drmModeEncoder *encoder; > + int i; > + > + printf("Encoders:\n"); > + printf("id\tcrtc\ttype\tpossible crtcs\tpossible clones\t\n"); > + for (i = 0; i < dev->resources->res->count_encoders; i++) { > + encoder = dev->resources->encoders[i].encoder; > + if (!encoder) > + continue; > + > + printf("%d\t%d\t%s\t0x%08x\t0x%08x\n", > + encoder->encoder_id, > + encoder->crtc_id, > + util_lookup_encoder_type_name(encoder->encoder_type), > + encoder->possible_crtcs, > + encoder->possible_clones); > + } > + printf("\n"); > +} > + > +static void dump_mode(drmModeModeInfo *mode) > +{ > + printf(" %s %d %d %d %d %d %d %d %d %d %d", > + mode->name, > + mode->vrefresh, > + mode->hdisplay, > + mode->hsync_start, > + mode->hsync_end, > + mode->htotal, > + mode->vdisplay, > + mode->vsync_start, > + mode->vsync_end, > + mode->vtotal, > + mode->clock); > + > + printf(" flags: "); > + mode_flag_str(mode->flags); > + printf("; type: "); > + mode_type_str(mode->type); > + printf("\n"); > +} > + > +static void dump_blob(struct device *dev, uint32_t blob_id) > +{ > + uint32_t i; > + unsigned char *blob_data; > + drmModePropertyBlobPtr blob; > + > + blob = drmModeGetPropertyBlob(dev->fd, blob_id); > + if (!blob) { > + printf("\n"); > + return; > + } > + > + blob_data = blob->data; > + > + for (i = 0; i < blob->length; i++) { > + if (i % 16 == 0) > + printf("\n\t\t\t"); > + printf("%.2hhx", blob_data[i]); > + } > + printf("\n"); > + > + drmModeFreePropertyBlob(blob); > +} > + > +static void dump_prop(struct device *dev, drmModePropertyPtr prop, > + uint32_t prop_id, uint64_t value) > +{ > + int i; > + printf("\t%d", prop_id); > + if (!prop) { > + printf("\n"); > + return; > + } > + > + printf(" %s:\n", prop->name); > + > + printf("\t\tflags:"); > + if (prop->flags & DRM_MODE_PROP_PENDING) > + printf(" pending"); > + if (prop->flags & DRM_MODE_PROP_IMMUTABLE) > + printf(" immutable"); > + if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE)) > + printf(" signed range"); > + if (drm_property_type_is(prop, DRM_MODE_PROP_RANGE)) > + printf(" range"); > + if (drm_property_type_is(prop, DRM_MODE_PROP_ENUM)) > + printf(" enum"); > + if (drm_property_type_is(prop, DRM_MODE_PROP_BITMASK)) > + printf(" bitmask"); > + if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB)) > + printf(" blob"); > + if (drm_property_type_is(prop, DRM_MODE_PROP_OBJECT)) > + printf(" object"); > + printf("\n"); > + > + if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE)) { > + printf("\t\tvalues:"); > + for (i = 0; i < prop->count_values; i++) > + printf(" %"PRId64, U642I64(prop->values[i])); > + printf("\n"); > + } > + > + if (drm_property_type_is(prop, DRM_MODE_PROP_RANGE)) { > + printf("\t\tvalues:"); > + for (i = 0; i < prop->count_values; i++) > + printf(" %"PRIu64, prop->values[i]); > + printf("\n"); > + } > + > + if (drm_property_type_is(prop, DRM_MODE_PROP_ENUM)) { > + printf("\t\tenums:"); > + for (i = 0; i < prop->count_enums; i++) > + printf(" %s=%llu", prop->enums[i].name, > + prop->enums[i].value); > + printf("\n"); > + } else if (drm_property_type_is(prop, 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); > + } > + > + if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB)) { > + printf("\t\tblobs:\n"); > + for (i = 0; i < prop->count_blobs; i++) > + dump_blob(dev, prop->blob_ids[i]); > + printf("\n"); > + } else { > + assert(prop->count_blobs == 0); > + } > + > + printf("\t\tvalue:"); > + if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB)) > + dump_blob(dev, value); > + else if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE)) > + printf(" %"PRId64"\n", value); > + else > + printf(" %"PRIu64"\n", value); > +} > + > +static void dump_connectors(struct device *dev) > +{ > + int i, j; > + > + printf("Connectors:\n"); > + printf("id\tencoder\tstatus\t\tname\t\tsize (mm)\tmodes\tencoders\n"); > + for (i = 0; i < dev->resources->res->count_connectors; i++) { > + struct connector *_connector = &dev->resources->connectors[i]; > + drmModeConnector *connector = _connector->connector; > + if (!connector) > + continue; > + > + printf("%d\t%d\t%s\t%-15s\t%dx%d\t\t%d\t", > + connector->connector_id, > + connector->encoder_id, > + util_lookup_connector_status_name(connector->connection), > + _connector->name, > + connector->mmWidth, connector->mmHeight, > + connector->count_modes); > + > + for (j = 0; j < connector->count_encoders; j++) > + printf("%s%d", j > 0 ? ", " : "", connector->encoders[j]); > + printf("\n"); > + > + if (connector->count_modes) { > + printf(" modes:\n"); > + printf("\tname refresh (Hz) hdisp hss hse htot vdisp " > + "vss vse vtot)\n"); > + for (j = 0; j < connector->count_modes; j++) > + dump_mode(&connector->modes[j]); > + } > + > + if (_connector->props) { > + printf(" props:\n"); > + for (j = 0; j < (int)_connector->props->count_props; j++) > + dump_prop(dev, _connector->props_info[j], > + _connector->props->props[j], > + _connector->props->prop_values[j]); > + } > + } > + printf("\n"); > +} > + > +static void dump_crtcs(struct device *dev) > +{ > + int i; > + uint32_t j; > + > + printf("CRTCs:\n"); > + printf("id\tfb\tpos\tsize\n"); > + for (i = 0; i < dev->resources->res->count_crtcs; i++) { > + struct crtc *_crtc = &dev->resources->crtcs[i]; > + drmModeCrtc *crtc = _crtc->crtc; > + if (!crtc) > + continue; > + > + printf("%d\t%d\t(%d,%d)\t(%dx%d)\n", > + crtc->crtc_id, > + crtc->buffer_id, > + crtc->x, crtc->y, > + crtc->width, crtc->height); > + dump_mode(&crtc->mode); > + > + if (_crtc->props) { > + printf(" props:\n"); > + for (j = 0; j < _crtc->props->count_props; j++) > + dump_prop(dev, _crtc->props_info[j], > + _crtc->props->props[j], > + _crtc->props->prop_values[j]); > + } else { > + printf(" no properties found\n"); > + } > + } > + printf("\n"); > +} > + > +static void dump_framebuffers(struct device *dev) > +{ > + drmModeFB *fb; > + int i; > + > + printf("Frame buffers:\n"); > + printf("id\tsize\tpitch\n"); > + for (i = 0; i < dev->resources->res->count_fbs; i++) { > + fb = dev->resources->fbs[i].fb; > + if (!fb) > + continue; > + > + printf("%u\t(%ux%u)\t%u\n", > + fb->fb_id, > + fb->width, fb->height, > + fb->pitch); > + } > + printf("\n"); > +} > + > +static void dump_planes(struct device *dev) > +{ > + unsigned int i, j; > + > + printf("Planes:\n"); > + printf("id\tcrtc\tfb\tCRTC x,y\tx,y\tgamma size\tpossible crtcs\n"); > + > + if (!dev->resources->plane_res) > + return; > + > + for (i = 0; i < dev->resources->plane_res->count_planes; i++) { > + struct plane *plane = &dev->resources->planes[i]; > + drmModePlane *ovr = plane->plane; > + if (!ovr) > + continue; > + > + printf("%d\t%d\t%d\t%d,%d\t\t%d,%d\t%-8d\t0x%08x\n", > + ovr->plane_id, ovr->crtc_id, ovr->fb_id, > + ovr->crtc_x, ovr->crtc_y, ovr->x, ovr->y, > + ovr->gamma_size, ovr->possible_crtcs); > + > + if (!ovr->count_formats) > + continue; > + > + printf(" formats:"); > + for (j = 0; j < ovr->count_formats; j++) > + dump_fourcc(ovr->formats[j]); > + printf("\n"); > + > + if (plane->props) { > + printf(" props:\n"); > + for (j = 0; j < plane->props->count_props; j++) > + dump_prop(dev, plane->props_info[j], > + plane->props->props[j], > + plane->props->prop_values[j]); > + } else { > + printf(" no properties found\n"); > + } > + } > + printf("\n"); > + > + return; > +} > + > +static void free_resources(struct resources *res) > +{ > + int i; > + > + if (!res) > + return; > + > +#define free_resource(_res, __res, type, Type) \ > + do { \ > + if (!(_res)->type##s) \ > + break; \ > + for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \ > + if (!(_res)->type##s[i].type) \ > + break; \ > + drmModeFree##Type((_res)->type##s[i].type); \ > + } \ > + free((_res)->type##s); \ > + } while (0) > + > +#define free_properties(_res, __res, type) \ > + do { \ > + for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \ > + drmModeFreeObjectProperties(res->type##s[i].props); \ > + free(res->type##s[i].props_info); \ > + } \ > + } while (0) > + > + if (res->res) { > + free_properties(res, res, crtc); > + > + free_resource(res, res, crtc, Crtc); > + free_resource(res, res, encoder, Encoder); > + > + for (i = 0; i < res->res->count_connectors; i++) > + free(res->connectors[i].name); > + > + free_resource(res, res, connector, Connector); > + free_resource(res, res, fb, FB); > + > + drmModeFreeResources(res->res); > + } > + > + if (res->plane_res) { > + free_properties(res, plane_res, plane); > + > + free_resource(res, plane_res, plane, Plane); > + > + drmModeFreePlaneResources(res->plane_res); > + } > + > + free(res); > +} > + > +static struct resources *get_resources(struct device *dev) > +{ > + struct resources *res; > + int i; > + > + res = calloc(1, sizeof(*res)); > + if (res == 0) > + return NULL; > + > + drmSetClientCap(dev->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); > + > + res->res = drmModeGetResources(dev->fd); > + if (!res->res) { > + fprintf(stderr, "drmModeGetResources failed: %s\n", > + strerror(errno)); > + goto error; > + } > + > + res->crtcs = calloc(res->res->count_crtcs, sizeof(*res->crtcs)); > + res->encoders = calloc(res->res->count_encoders, sizeof(*res->encoders)); > + res->connectors = calloc(res->res->count_connectors, sizeof(*res->connectors)); > + res->fbs = calloc(res->res->count_fbs, sizeof(*res->fbs)); > + > + if (!res->crtcs || !res->encoders || !res->connectors || !res->fbs) > + goto error; > + > +#define get_resource(_res, __res, type, Type) \ > + do { \ > + for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \ > + (_res)->type##s[i].type = \ > + drmModeGet##Type(dev->fd, (_res)->__res->type##s[i]); \ > + if (!(_res)->type##s[i].type) \ > + fprintf(stderr, "could not get %s %i: %s\n", \ > + #type, (_res)->__res->type##s[i], \ > + strerror(errno)); \ > + } \ > + } while (0) > + > + get_resource(res, res, crtc, Crtc); > + get_resource(res, res, encoder, Encoder); > + get_resource(res, res, connector, Connector); > + get_resource(res, res, fb, FB); > + > + /* Set the name of all connectors based on the type name and the per-type ID. */ > + for (i = 0; i < res->res->count_connectors; i++) { > + struct connector *connector = &res->connectors[i]; > + drmModeConnector *conn = connector->connector; > + int num; > + > + num = asprintf(&connector->name, "%s-%u", > + util_lookup_connector_type_name(conn->connector_type), > + conn->connector_type_id); > + if (num < 0) > + goto error; > + } > + > +#define get_properties(_res, __res, type, Type) \ > + do { \ > + for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \ > + struct type *obj = &res->type##s[i]; \ > + unsigned int j; \ > + obj->props = \ > + drmModeObjectGetProperties(dev->fd, obj->type->type##_id, \ > + DRM_MODE_OBJECT_##Type); \ > + if (!obj->props) { \ > + fprintf(stderr, \ > + "could not get %s %i properties: %s\n", \ > + #type, obj->type->type##_id, \ > + strerror(errno)); \ > + continue; \ > + } \ > + obj->props_info = calloc(obj->props->count_props, \ > + sizeof(*obj->props_info)); \ > + if (!obj->props_info) \ > + continue; \ > + for (j = 0; j < obj->props->count_props; ++j) \ > + obj->props_info[j] = \ > + drmModeGetProperty(dev->fd, obj->props->props[j]); \ > + } \ > + } while (0) > + > + get_properties(res, res, crtc, CRTC); > + get_properties(res, res, connector, CONNECTOR); > + > + for (i = 0; i < res->res->count_crtcs; ++i) > + res->crtcs[i].mode = &res->crtcs[i].crtc->mode; > + > + res->plane_res = drmModeGetPlaneResources(dev->fd); > + if (!res->plane_res) { > + fprintf(stderr, "drmModeGetPlaneResources failed: %s\n", > + strerror(errno)); > + return res; > + } > + > + res->planes = calloc(res->plane_res->count_planes, sizeof(*res->planes)); > + if (!res->planes) > + goto error; > + > + get_resource(res, plane_res, plane, Plane); > + get_properties(res, plane_res, plane, PLANE); > + > + return res; > + > +error: > + free_resources(res); > + return NULL; > +} > + > +static int get_crtc_index(struct device *dev, uint32_t id) > +{ > + int i; > + > + for (i = 0; i < dev->resources->res->count_crtcs; ++i) { > + drmModeCrtc *crtc = dev->resources->crtcs[i].crtc; > + if (crtc && crtc->crtc_id == id) > + return i; > + } > + > + return -1; > +} > + > +static drmModeConnector *get_connector_by_name(struct device *dev, const char *name) > +{ > + struct connector *connector; > + int i; > + > + for (i = 0; i < dev->resources->res->count_connectors; i++) { > + connector = &dev->resources->connectors[i]; > + > + if (strcmp(connector->name, name) == 0) > + return connector->connector; > + } > + > + return NULL; > +} > + > +static drmModeConnector *get_connector_by_id(struct device *dev, uint32_t id) > +{ > + drmModeConnector *connector; > + int i; > + > + for (i = 0; i < dev->resources->res->count_connectors; i++) { > + connector = dev->resources->connectors[i].connector; > + if (connector && connector->connector_id == id) > + return connector; > + } > + > + return NULL; > +} > + > +static drmModeEncoder *get_encoder_by_id(struct device *dev, uint32_t id) > +{ > + drmModeEncoder *encoder; > + int i; > + > + for (i = 0; i < dev->resources->res->count_encoders; i++) { > + encoder = dev->resources->encoders[i].encoder; > + if (encoder && encoder->encoder_id == id) > + return encoder; > + } > + > + return NULL; > +} > + > +/* ----------------------------------------------------------------------------- > + * Pipes 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 > + * requested mode is available. > + * Then you need to find the encoder attached to that connector so you > + * can bind it with a free crtc. > + */ > +struct pipe_arg { > + const char **cons; > + uint32_t *con_ids; > + unsigned int num_cons; > + uint32_t crtc_id; > + char mode_str[64]; > + char format_str[5]; > + unsigned int vrefresh; > + unsigned int fourcc; > + drmModeModeInfo *mode; > + struct crtc *crtc; > + unsigned int fb_id[2], current_fb_id; > + struct timeval start; > + > + int swap_count; > +}; > + > +struct plane_arg { > + uint32_t plane_id; /* the id of plane to use */ > + uint32_t crtc_id; /* the id of CRTC to bind to */ > + bool has_position; > + int32_t x, y; > + uint32_t w, h; > + double scale; > + unsigned int fb_id; > + unsigned int old_fb_id; > + struct bo *bo; > + struct bo *old_bo; > + char format_str[5]; /* need to leave room for terminating \0 */ > + unsigned int fourcc; > +}; > + > +static drmModeModeInfo * > +connector_find_mode(struct device *dev, uint32_t con_id, const char *mode_str, > + const unsigned int vrefresh) > +{ > + drmModeConnector *connector; > + drmModeModeInfo *mode; > + int i; > + > + connector = get_connector_by_id(dev, con_id); > + if (!connector || !connector->count_modes) > + return NULL; > + > + for (i = 0; i < connector->count_modes; i++) { > + mode = &connector->modes[i]; > + if (!strcmp(mode->name, mode_str)) { > + /* If the vertical refresh frequency is not specified then return the > + * first mode that match with the name. Else, return the mode that match > + * the name and the specified vertical refresh frequency. > + */ > + if (vrefresh == 0) > + return mode; > + else if (mode->vrefresh == vrefresh) > + return mode; > + } > + } > + > + return NULL; > +} > + > +static struct crtc *pipe_find_crtc(struct device *dev, struct pipe_arg *pipe) > +{ > + uint32_t possible_crtcs = ~0; > + uint32_t active_crtcs = 0; > + unsigned int crtc_idx; > + unsigned int i; > + int j; > + > + for (i = 0; i < pipe->num_cons; ++i) { > + uint32_t crtcs_for_connector = 0; > + drmModeConnector *connector; > + drmModeEncoder *encoder; > + int idx; > + > + connector = get_connector_by_id(dev, pipe->con_ids[i]); > + if (!connector) > + return NULL; > + > + for (j = 0; j < connector->count_encoders; ++j) { > + encoder = get_encoder_by_id(dev, connector->encoders[j]); > + if (!encoder) > + continue; > + > + crtcs_for_connector |= encoder->possible_crtcs; > + > + idx = get_crtc_index(dev, encoder->crtc_id); > + if (idx >= 0) > + active_crtcs |= 1 << idx; > + } > + > + possible_crtcs &= crtcs_for_connector; > + } > + > + if (!possible_crtcs) > + return NULL; > + > + /* Return the first possible and active CRTC if one exists, or the first > + * possible CRTC otherwise. > + */ > + if (possible_crtcs & active_crtcs) > + crtc_idx = ffs(possible_crtcs & active_crtcs); > + else > + crtc_idx = ffs(possible_crtcs); > + > + return &dev->resources->crtcs[crtc_idx - 1]; > +} > + > +static int pipe_find_crtc_and_mode(struct device *dev, struct pipe_arg *pipe) > +{ > + drmModeModeInfo *mode = NULL; > + int i; > + > + pipe->mode = NULL; > + > + for (i = 0; i < (int)pipe->num_cons; i++) { > + mode = connector_find_mode(dev, pipe->con_ids[i], > + pipe->mode_str, pipe->vrefresh); > + if (mode == NULL) { > + fprintf(stderr, > + "failed to find mode \"%s\" for connector %s\n", > + pipe->mode_str, pipe->cons[i]); > + return -EINVAL; > + } > + } > + > + /* If the CRTC ID was specified, get the corresponding CRTC. Otherwise > + * locate a CRTC that can be attached to all the connectors. > + */ > + if (pipe->crtc_id != (uint32_t)-1) { > + for (i = 0; i < dev->resources->res->count_crtcs; i++) { > + struct crtc *crtc = &dev->resources->crtcs[i]; > + > + if (pipe->crtc_id == crtc->crtc->crtc_id) { > + pipe->crtc = crtc; > + break; > + } > + } > + } else { > + pipe->crtc = pipe_find_crtc(dev, pipe); > + } > + > + if (!pipe->crtc) { > + fprintf(stderr, "failed to find CRTC for pipe\n"); > + return -EINVAL; > + } > + > + pipe->mode = mode; > + pipe->crtc->mode = mode; > + > + return 0; > +} > + > +/* ----------------------------------------------------------------------------- > + * Properties > + */ > + > +struct property_arg { > + uint32_t obj_id; > + uint32_t obj_type; > + char name[DRM_PROP_NAME_LEN+1]; > + uint32_t prop_id; > + uint64_t value; > +}; > + > +static void set_property(struct device *dev, struct property_arg *p) > +{ > + drmModeObjectProperties *props = NULL; > + drmModePropertyRes **props_info = NULL; > + const char *obj_type; > + int ret; > + int i; > + > + p->obj_type = 0; > + p->prop_id = 0; > + > +#define find_object(_res, __res, type, Type) \ > + do { \ > + for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \ > + struct type *obj = &(_res)->type##s[i]; \ > + if (obj->type->type##_id != p->obj_id) \ > + continue; \ > + p->obj_type = DRM_MODE_OBJECT_##Type; \ > + obj_type = #Type; \ > + props = obj->props; \ > + props_info = obj->props_info; \ > + } \ > + } while(0) \ > + > + find_object(dev->resources, res, crtc, CRTC); > + if (p->obj_type == 0) > + find_object(dev->resources, res, connector, CONNECTOR); > + if (p->obj_type == 0) > + find_object(dev->resources, plane_res, plane, PLANE); > + if (p->obj_type == 0) { > + fprintf(stderr, "Object %i not found, can't set property\n", > + p->obj_id); > + return; > + } > + > + if (!props) { > + fprintf(stderr, "%s %i has no properties\n", > + obj_type, p->obj_id); > + return; > + } > + > + for (i = 0; i < (int)props->count_props; ++i) { > + if (!props_info[i]) > + continue; > + if (strcmp(props_info[i]->name, p->name) == 0) > + break; > + } > + > + if (i == (int)props->count_props) { > + fprintf(stderr, "%s %i has no %s property\n", > + obj_type, p->obj_id, p->name); > + return; > + } > + > + p->prop_id = props->props[i]; > + > + ret = drmModeAtomicAddProperty(dev->req, p->obj_id, p->prop_id, p->value); > + if (ret < 0) > + fprintf(stderr, "failed to set %s %i property %s to %" PRIu64 ": %s\n", > + obj_type, p->obj_id, p->name, p->value, strerror(errno)); > +} > + > +/* -------------------------------------------------------------------------- */ > + > +/*static bool format_support(const drmModePlanePtr ovr, uint32_t fmt) > +{ > + unsigned int i; > + > + for (i = 0; i < ovr->count_formats; ++i) { > + if (ovr->formats[i] == fmt) > + return true; > + } > + > + return false; > +}*/ > + > +static void add_property(struct device *dev, uint32_t obj_id, > + const char *name, uint64_t value) > +{ > + struct property_arg p; > + > + p.obj_id = obj_id; > + strcpy(p.name, name); > + p.value = value; > + > + set_property(dev, &p); > +} > + > +static int set_plane(struct device *dev, struct plane_arg *p, > + int pattern, bool update) > +{ > + uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0}; > + struct bo *plane_bo; > + int crtc_x, crtc_y, crtc_w, crtc_h; > + struct crtc *crtc = NULL; > + unsigned int i; > + unsigned int old_fb_id; > + > + /* Find an unused plane which can be connected to our CRTC. Find the > + * CRTC index first, then iterate over available planes. > + */ > + for (i = 0; i < (unsigned int)dev->resources->res->count_crtcs; i++) { > + if (p->crtc_id == dev->resources->res->crtcs[i]) { > + crtc = &dev->resources->crtcs[i]; > + break; > + } > + } > + > + if (!crtc) { > + fprintf(stderr, "CRTC %u not found\n", p->crtc_id); > + return -1; > + } > + > + if (!update) > + fprintf(stderr, "testing %dx%d@%s on plane %u, crtc %u\n", > + p->w, p->h, p->format_str, p->plane_id, p->crtc_id); > + > + plane_bo = p->old_bo; > + p->old_bo = p->bo; > + > + if (!plane_bo) { > + plane_bo = bo_create(dev->fd, p->fourcc, p->w, p->h, > + handles, pitches, offsets, pattern); > + > + if (plane_bo == NULL) > + return -1; > + > + if (drmModeAddFB2(dev->fd, p->w, p->h, p->fourcc, > + handles, pitches, offsets, &p->fb_id, 0)) { > + fprintf(stderr, "failed to add fb: %s\n", strerror(errno)); > + return -1; > + } > + } > + > + p->bo = plane_bo; > + > + old_fb_id = p->fb_id; > + p->old_fb_id = old_fb_id; > + > + crtc_w = p->w * p->scale; > + crtc_h = p->h * p->scale; > + if (!p->has_position) { > + /* Default to the middle of the screen */ > + crtc_x = (crtc->mode->hdisplay - crtc_w) / 2; > + crtc_y = (crtc->mode->vdisplay - crtc_h) / 2; > + } else { > + crtc_x = p->x; > + crtc_y = p->y; > + } > + > + add_property(dev, p->plane_id, "FB_ID", p->fb_id); > + add_property(dev, p->plane_id, "CRTC_ID", p->crtc_id); > + add_property(dev, p->plane_id, "SRC_X", 0); > + add_property(dev, p->plane_id, "SRC_Y", 0); > + add_property(dev, p->plane_id, "SRC_W", p->w << 16); > + add_property(dev, p->plane_id, "SRC_H", p->h << 16); > + add_property(dev, p->plane_id, "CRTC_X", crtc_x); > + add_property(dev, p->plane_id, "CRTC_Y", crtc_y); > + add_property(dev, p->plane_id, "CRTC_W", crtc_w); > + add_property(dev, p->plane_id, "CRTC_H", crtc_h); > + > + return 0; > +} > + > +static void set_planes(struct device *dev, struct plane_arg *p, > + unsigned int count, bool update) > +{ > + unsigned int i, pattern = UTIL_PATTERN_SMPTE; > + > + /* set up planes */ > + for (i = 0; i < count; i++) { > + if (i > 0) > + pattern = UTIL_PATTERN_TILES; > + > + if (set_plane(dev, &p[i], pattern, update)) > + return; > + } > +} > + > +static void clear_planes(struct device *dev, struct plane_arg *p, unsigned int count) > +{ > + unsigned int i; > + > + for (i = 0; i < count; i++) { > + add_property(dev, p[i].plane_id, "FB_ID", 0); > + add_property(dev, p[i].plane_id, "CRTC_ID", 0); > + add_property(dev, p[i].plane_id, "SRC_X", 0); > + add_property(dev, p[i].plane_id, "SRC_Y", 0); > + add_property(dev, p[i].plane_id, "SRC_W", 0); > + add_property(dev, p[i].plane_id, "SRC_H", 0); > + add_property(dev, p[i].plane_id, "CRTC_X", 0); > + add_property(dev, p[i].plane_id, "CRTC_Y", 0); > + add_property(dev, p[i].plane_id, "CRTC_W", 0); > + add_property(dev, p[i].plane_id, "CRTC_H", 0); > + } > +} > + > +static void clear_FB(struct device *dev, struct plane_arg *p, unsigned int count) > +{ > + unsigned int i; > + > + for (i = 0; i < count; i++) { > + if (p[i].fb_id) { > + drmModeRmFB(dev->fd, p[i].fb_id); > + p[i].fb_id = 0; > + } > + if (p[i].old_fb_id) { > + drmModeRmFB(dev->fd, p[i].old_fb_id); > + p[i].old_fb_id = 0; > + } > + if (p[i].bo) { > + bo_destroy(p[i].bo); > + p[i].bo = NULL; > + } > + if (p[i].old_bo) { > + bo_destroy(p[i].old_bo); > + p[i].old_bo = NULL; > + } > + > + } > +} > + > +static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count) > +{ > + unsigned int i; > + unsigned int j; > + int ret; > + > + for (i = 0; i < count; i++) { > + struct pipe_arg *pipe = &pipes[i]; > + > + ret = pipe_find_crtc_and_mode(dev, pipe); > + if (ret < 0) > + continue; > + } > + > + for (i = 0; i < count; i++) { > + struct pipe_arg *pipe = &pipes[i]; > + uint32_t blob_id; > + > + if (pipe->mode == NULL) > + continue; > + > + printf("setting mode %s-%dHz@%s on connectors ", > + pipe->mode_str, pipe->mode->vrefresh, pipe->format_str); > + for (j = 0; j < pipe->num_cons; ++j) { > + printf("%s, ", pipe->cons[j]); > + add_property(dev, pipe->con_ids[j], "CRTC_ID", pipe->crtc->crtc->crtc_id); > + } > + printf("crtc %d\n", pipe->crtc->crtc->crtc_id); > + > + drmModeCreatePropertyBlob(dev->fd, pipe->mode, sizeof(*pipe->mode), &blob_id); > + add_property(dev, pipe->crtc->crtc->crtc_id, "MODE_ID", blob_id); > + add_property(dev, pipe->crtc->crtc->crtc_id, "ACTIVE", 1); > + } > +} > + > +static void clear_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count) > +{ > + unsigned int i; > + unsigned int j; > + > + for (i = 0; i < count; i++) { > + struct pipe_arg *pipe = &pipes[i]; > + > + if (pipe->mode == NULL) > + continue; > + > + for (j = 0; j < pipe->num_cons; ++j) > + add_property(dev, pipe->con_ids[j], "CRTC_ID",0); > + > + add_property(dev, pipe->crtc->crtc->crtc_id, "MODE_ID", 0); > + add_property(dev, pipe->crtc->crtc->crtc_id, "ACTIVE", 0); > + } > + > +} > + > +#define min(a, b) ((a) < (b) ? (a) : (b)) > + > +static int parse_connector(struct pipe_arg *pipe, const char *arg) > +{ > + unsigned int len; > + unsigned int i; > + const char *p; > + char *endp; > + > + pipe->vrefresh = 0; > + pipe->crtc_id = (uint32_t)-1; > + strcpy(pipe->format_str, "XR24"); > + > + /* Count the number of connectors and allocate them. */ > + pipe->num_cons = 1; > + for (p = arg; *p && *p != ':' && *p != '@'; ++p) { > + if (*p == ',') > + pipe->num_cons++; > + } > + > + pipe->con_ids = calloc(pipe->num_cons, sizeof(*pipe->con_ids)); > + pipe->cons = calloc(pipe->num_cons, sizeof(*pipe->cons)); > + if (pipe->con_ids == NULL || pipe->cons == NULL) > + return -1; > + > + /* Parse the connectors. */ > + for (i = 0, p = arg; i < pipe->num_cons; ++i, p = endp + 1) { > + endp = strpbrk(p, ",@:"); > + if (!endp) > + break; > + > + pipe->cons[i] = strndup(p, endp - p); > + > + if (*endp != ',') > + break; > + } > + > + if (i != pipe->num_cons - 1) > + return -1; > + > + /* Parse the remaining parameters. */ > + if (*endp == '@') { > + arg = endp + 1; > + pipe->crtc_id = strtoul(arg, &endp, 10); > + } > + if (*endp != ':') > + return -1; > + > + arg = endp + 1; > + > + /* Search for the vertical refresh or the format. */ > + p = strpbrk(arg, "-@"); > + if (p == NULL) > + p = arg + strlen(arg); > + len = min(sizeof pipe->mode_str - 1, (unsigned int)(p - arg)); > + strncpy(pipe->mode_str, arg, len); > + pipe->mode_str[len] = '\0'; > + > + if (*p == '-') { > + pipe->vrefresh = strtoul(p + 1, &endp, 10); > + p = endp; > + } > + > + if (*p == '@') { > + strncpy(pipe->format_str, p + 1, 4); > + pipe->format_str[4] = '\0'; > + } > + > + pipe->fourcc = util_format_fourcc(pipe->format_str); > + if (pipe->fourcc == 0) { > + fprintf(stderr, "unknown format %s\n", pipe->format_str); > + return -1; > + } > + > + return 0; > +} > + > +static int parse_plane(struct plane_arg *plane, const char *p) > +{ > + char *end; > + > + plane->plane_id = strtoul(p, &end, 10); > + if (*end != '@') > + return -EINVAL; > + > + p = end + 1; > + plane->crtc_id = strtoul(p, &end, 10); > + if (*end != ':') > + return -EINVAL; > + > + p = end + 1; > + plane->w = strtoul(p, &end, 10); > + if (*end != 'x') > + return -EINVAL; > + > + p = end + 1; > + plane->h = strtoul(p, &end, 10); > + > + if (*end == '+' || *end == '-') { > + plane->x = strtol(end, &end, 10); > + if (*end != '+' && *end != '-') > + return -EINVAL; > + plane->y = strtol(end, &end, 10); > + > + plane->has_position = true; > + } > + > + if (*end == '*') { > + p = end + 1; > + plane->scale = strtod(p, &end); > + if (plane->scale <= 0.0) > + return -EINVAL; > + } else { > + plane->scale = 1.0; > + } > + > + if (*end == '@') { > + p = end + 1; > + if (strlen(p) != 4) > + return -EINVAL; > + > + strcpy(plane->format_str, p); > + } else { > + strcpy(plane->format_str, "XR24"); > + } > + > + plane->fourcc = util_format_fourcc(plane->format_str); > + if (plane->fourcc == 0) { > + fprintf(stderr, "unknown format %s\n", plane->format_str); > + return -EINVAL; > + } > + > + return 0; > +} > + > +static int parse_property(struct property_arg *p, const char *arg) > +{ > + if (sscanf(arg, "%d:%32[^:]:%" SCNu64, &p->obj_id, p->name, &p->value) != 3) > + return -1; > + > + p->obj_type = 0; > + p->name[DRM_PROP_NAME_LEN] = '\0'; > + > + return 0; > +} > + > +static void usage(char *name) > +{ > + fprintf(stderr, "usage: %s [-cDdefMPpsCvw]\n", name); > + > + fprintf(stderr, "\n Query options:\n\n"); > + fprintf(stderr, "\t-c\tlist connectors\n"); > + fprintf(stderr, "\t-e\tlist encoders\n"); > + fprintf(stderr, "\t-f\tlist framebuffers\n"); > + fprintf(stderr, "\t-p\tlist CRTCs and planes (pipes)\n"); > + > + fprintf(stderr, "\n Test options:\n\n"); > + fprintf(stderr, "\t-P <plane_id>@<crtc_id>:<w>x<h>[+<x>+<y>][*<scale>][@<format>]\tset a plane\n"); > + fprintf(stderr, "\t-s <connector_id>[,<connector_id>][@<crtc_id>]:<mode>[-<vrefresh>][@<format>]\tset a mode\n"); > + fprintf(stderr, "\t-v\ttest loop\n"); > + fprintf(stderr, "\t-w <obj_id>:<prop_name>:<value>\tset property\n"); > + > + fprintf(stderr, "\n Generic options:\n\n"); > + fprintf(stderr, "\t-d\tdrop master after mode set\n"); > + fprintf(stderr, "\t-M module\tuse the given driver\n"); > + fprintf(stderr, "\t-D device\tuse the given device\n"); > + > + fprintf(stderr, "\n\tDefault is to dump all info.\n"); > + exit(0); > +} > + > +static int pipe_resolve_connectors(struct device *dev, struct pipe_arg *pipe) > +{ > + drmModeConnector *connector; > + unsigned int i; > + uint32_t id; > + char *endp; > + > + for (i = 0; i < pipe->num_cons; i++) { > + id = strtoul(pipe->cons[i], &endp, 10); > + if (endp == pipe->cons[i]) { > + connector = get_connector_by_name(dev, pipe->cons[i]); > + if (!connector) { > + fprintf(stderr, "no connector named '%s'\n", > + pipe->cons[i]); > + return -ENODEV; > + } > + > + id = connector->connector_id; > + } > + > + pipe->con_ids[i] = id; > + } > + > + return 0; > +} > + > +static char optstr[] = "cdD:efM:P:ps:vw:"; > + > +int main(int argc, char **argv) > +{ > + struct device dev; > + > + int c; > + int encoders = 0, connectors = 0, crtcs = 0, planes = 0, framebuffers = 0; > + int drop_master = 0; > + int test_loop = 0; > + char *device = NULL; > + char *module = NULL; > + unsigned int i; > + unsigned int count = 0, plane_count = 0; > + unsigned int prop_count = 0; > + struct pipe_arg *pipe_args = NULL; > + struct plane_arg *plane_args = NULL; > + struct property_arg *prop_args = NULL; > + unsigned int args = 0; > + int ret; > + > + memset(&dev, 0, sizeof dev); > + > + opterr = 0; > + while ((c = getopt(argc, argv, optstr)) != -1) { > + args++; > + > + switch (c) { > + case 'c': > + connectors = 1; > + break; > + case 'D': > + device = optarg; > + args--; > + break; > + case 'd': > + drop_master = 1; > + break; > + case 'e': > + encoders = 1; > + break; > + case 'f': > + framebuffers = 1; > + break; > + case 'M': > + module = optarg; > + /* Preserve the default behaviour of dumping all information. */ > + args--; > + break; > + case 'P': > + plane_args = realloc(plane_args, > + (plane_count + 1) * sizeof *plane_args); > + if (plane_args == NULL) { > + fprintf(stderr, "memory allocation failed\n"); > + return 1; > + } > + memset(&plane_args[plane_count], 0, sizeof(*plane_args)); > + > + if (parse_plane(&plane_args[plane_count], optarg) < 0) > + usage(argv[0]); > + > + plane_count++; > + break; > + case 'p': > + crtcs = 1; > + planes = 1; > + break; > + case 's': > + pipe_args = realloc(pipe_args, > + (count + 1) * sizeof *pipe_args); > + if (pipe_args == NULL) { > + fprintf(stderr, "memory allocation failed\n"); > + return 1; > + } > + memset(&pipe_args[count], 0, sizeof(*pipe_args)); > + > + if (parse_connector(&pipe_args[count], optarg) < 0) > + usage(argv[0]); > + > + count++; > + break; > + case 'v': > + test_loop = 1; > + break; > + case 'w': > + prop_args = realloc(prop_args, > + (prop_count + 1) * sizeof *prop_args); > + if (prop_args == NULL) { > + fprintf(stderr, "memory allocation failed\n"); > + return 1; > + } > + memset(&prop_args[prop_count], 0, sizeof(*prop_args)); > + > + if (parse_property(&prop_args[prop_count], optarg) < 0) > + usage(argv[0]); > + > + prop_count++; > + break; > + default: > + usage(argv[0]); > + break; > + } > + } > + > + if (!args) > + encoders = connectors = crtcs = planes = framebuffers = 1; > + > + dev.fd = util_open(device, module); > + if (dev.fd < 0) > + return -1; > + > + ret = drmSetClientCap(dev.fd, DRM_CLIENT_CAP_ATOMIC, 1); > + if (ret) { > + fprintf(stderr, "no atomic modesetting support: %s\n", strerror(errno)); > + drmClose(dev.fd); > + return -1; > + } > + > + dev.resources = get_resources(&dev); > + if (!dev.resources) { > + drmClose(dev.fd); > + return 1; > + } > + > + for (i = 0; i < count; i++) { > + if (pipe_resolve_connectors(&dev, &pipe_args[i]) < 0) { > + free_resources(dev.resources); > + drmClose(dev.fd); > + return 1; > + } > + } > + > +#define dump_resource(dev, res) if (res) dump_##res(dev) > + > + dump_resource(&dev, encoders); > + dump_resource(&dev, connectors); > + dump_resource(&dev, crtcs); > + dump_resource(&dev, planes); > + dump_resource(&dev, framebuffers); > + > + dev.req = drmModeAtomicAlloc(); > + > + for (i = 0; i < prop_count; ++i) > + set_property(&dev, &prop_args[i]); > + > + if (count && plane_count) { > + 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"); > + drmModeAtomicFree(dev.req); > + return 1; > + } > + > + set_mode(&dev, pipe_args, count); > + set_planes(&dev, plane_args, plane_count, false); > + > + ret = drmModeAtomicCommit(dev.fd, dev.req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL); > + if (ret) { > + fprintf(stderr, "Atomic Commit failed [1]\n"); > + return 1; > + } > + > + gettimeofday(&pipe_args->start, NULL); > + pipe_args->swap_count = 0; > + > + while (test_loop) { > + drmModeAtomicFree(dev.req); > + dev.req = drmModeAtomicAlloc(); > + set_planes(&dev, plane_args, plane_count, true); > + > + ret = drmModeAtomicCommit(dev.fd, dev.req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL); > + if (ret) { > + fprintf(stderr, "Atomic Commit failed [2]\n"); > + return 1; > + } > + > + pipe_args->swap_count++; > + if (pipe_args->swap_count == 60) { > + struct timeval end; > + double t; > + > + gettimeofday(&end, NULL); > + t = end.tv_sec + end.tv_usec * 1e-6 - > + (pipe_args->start.tv_sec + pipe_args->start.tv_usec * 1e-6); > + fprintf(stderr, "freq: %.02fHz\n", pipe_args->swap_count / t); > + pipe_args->swap_count = 0; > + pipe_args->start = end; > + } > + } > + > + if (drop_master) > + drmDropMaster(dev.fd); > + > + getchar(); > + > + drmModeAtomicFree(dev.req); > + dev.req = drmModeAtomicAlloc(); > + > + clear_mode(&dev, pipe_args, count); > + clear_planes(&dev, plane_args, plane_count); > + ret = drmModeAtomicCommit(dev.fd, dev.req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL); > + if (ret) { > + fprintf(stderr, "Atomic Commit failed\n"); > + return 1; > + } > + > + clear_FB(&dev, plane_args, plane_count); > + } > + > + drmModeAtomicFree(dev.req); > + free_resources(dev.resources); > + > + return 0; > +} > -- > 2.15.0 > > _______________________________________________ > dri-devel mailing list > dri-devel@xxxxxxxxxxxxxxxxxxxxx > https://lists.freedesktop.org/mailman/listinfo/dri-devel _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel