modetest.c revision adfa0b0c
118210155Smrg/* 218210155Smrg * DRM based mode setting test program 318210155Smrg * Copyright 2008 Tungsten Graphics 418210155Smrg * Jakob Bornecrantz <jakob@tungstengraphics.com> 518210155Smrg * Copyright 2008 Intel Corporation 618210155Smrg * Jesse Barnes <jesse.barnes@intel.com> 718210155Smrg * 818210155Smrg * Permission is hereby granted, free of charge, to any person obtaining a 918210155Smrg * copy of this software and associated documentation files (the "Software"), 1018210155Smrg * to deal in the Software without restriction, including without limitation 1118210155Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 1218210155Smrg * and/or sell copies of the Software, and to permit persons to whom the 1318210155Smrg * Software is furnished to do so, subject to the following conditions: 1418210155Smrg * 1518210155Smrg * The above copyright notice and this permission notice shall be included in 1618210155Smrg * all copies or substantial portions of the Software. 1718210155Smrg * 1818210155Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1918210155Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2018210155Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 2118210155Smrg * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2218210155Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2318210155Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2418210155Smrg * IN THE SOFTWARE. 2518210155Smrg */ 2618210155Smrg 2718210155Smrg/* 2818210155Smrg * This fairly simple test program dumps output in a similar format to the 2918210155Smrg * "xrandr" tool everyone knows & loves. It's necessarily slightly different 3018210155Smrg * since the kernel separates outputs into encoder and connector structures, 3118210155Smrg * each with their own unique ID. The program also allows test testing of the 3218210155Smrg * memory management and mode setting APIs by allowing the user to specify a 3318210155Smrg * connector and mode to use for mode setting. If all works as expected, a 3418210155Smrg * blue background should be painted on the monitor attached to the specified 3518210155Smrg * connector after the selected mode is set. 3618210155Smrg * 3718210155Smrg * TODO: use cairo to write the mode info on the selected output once 3818210155Smrg * the mode has been programmed, along with possible test patterns. 3918210155Smrg */ 40fe517fc9Smrg 4118210155Smrg#include <assert.h> 42e88f27b3Smrg#include <ctype.h> 43e88f27b3Smrg#include <stdbool.h> 4418210155Smrg#include <stdio.h> 4518210155Smrg#include <stdlib.h> 4618210155Smrg#include <stdint.h> 47e88f27b3Smrg#include <inttypes.h> 4818210155Smrg#include <unistd.h> 4918210155Smrg#include <string.h> 50424e9256Smrg#include <strings.h> 5118210155Smrg#include <errno.h> 52fe517fc9Smrg#include <poll.h> 5322944501Smrg#include <sys/time.h> 5487bf8e7cSmrg#if HAVE_SYS_SELECT_H 55fe517fc9Smrg#include <sys/select.h> 56fe517fc9Smrg#endif 5787bf8e7cSmrg#include <math.h> 5818210155Smrg 5918210155Smrg#include "xf86drm.h" 6018210155Smrg#include "xf86drmMode.h" 61e88f27b3Smrg#include "drm_fourcc.h" 6218210155Smrg 63fe517fc9Smrg#include "util/common.h" 64fe517fc9Smrg#include "util/format.h" 65fe517fc9Smrg#include "util/kms.h" 66fe517fc9Smrg#include "util/pattern.h" 67fe517fc9Smrg 68e88f27b3Smrg#include "buffers.h" 69a7d7de1eSmrg#include "cursor.h" 70e88f27b3Smrg 71bf6cc7dcSmrgstatic enum util_fill_pattern primary_fill = UTIL_PATTERN_SMPTE; 72bf6cc7dcSmrgstatic enum util_fill_pattern secondary_fill = UTIL_PATTERN_TILES; 73bf6cc7dcSmrg 74e88f27b3Smrgstruct crtc { 75e88f27b3Smrg drmModeCrtc *crtc; 76e88f27b3Smrg drmModeObjectProperties *props; 77e88f27b3Smrg drmModePropertyRes **props_info; 78e88f27b3Smrg drmModeModeInfo *mode; 79e88f27b3Smrg}; 80e88f27b3Smrg 81e88f27b3Smrgstruct encoder { 82e88f27b3Smrg drmModeEncoder *encoder; 83e88f27b3Smrg}; 84e88f27b3Smrg 85e88f27b3Smrgstruct connector { 86e88f27b3Smrg drmModeConnector *connector; 87e88f27b3Smrg drmModeObjectProperties *props; 88e88f27b3Smrg drmModePropertyRes **props_info; 89fe517fc9Smrg char *name; 90e88f27b3Smrg}; 9118210155Smrg 92e88f27b3Smrgstruct fb { 93e88f27b3Smrg drmModeFB *fb; 94e88f27b3Smrg}; 95e88f27b3Smrg 96e88f27b3Smrgstruct plane { 97e88f27b3Smrg drmModePlane *plane; 98e88f27b3Smrg drmModeObjectProperties *props; 99e88f27b3Smrg drmModePropertyRes **props_info; 100e88f27b3Smrg}; 101e88f27b3Smrg 102e88f27b3Smrgstruct resources { 103e88f27b3Smrg struct crtc *crtcs; 10487bf8e7cSmrg int count_crtcs; 105e88f27b3Smrg struct encoder *encoders; 10687bf8e7cSmrg int count_encoders; 107e88f27b3Smrg struct connector *connectors; 10887bf8e7cSmrg int count_connectors; 109e88f27b3Smrg struct fb *fbs; 11087bf8e7cSmrg int count_fbs; 111e88f27b3Smrg struct plane *planes; 11287bf8e7cSmrg uint32_t count_planes; 113e88f27b3Smrg}; 114e88f27b3Smrg 115e88f27b3Smrgstruct device { 116e88f27b3Smrg int fd; 117e88f27b3Smrg 118e88f27b3Smrg struct resources *resources; 119e88f27b3Smrg 120e88f27b3Smrg struct { 121e88f27b3Smrg unsigned int width; 122e88f27b3Smrg unsigned int height; 123e88f27b3Smrg 124e88f27b3Smrg unsigned int fb_id; 1253c748557Ssnj struct bo *bo; 126424e9256Smrg struct bo *cursor_bo; 127e88f27b3Smrg } mode; 1286260e5d5Smrg 1296260e5d5Smrg int use_atomic; 1306260e5d5Smrg drmModeAtomicReq *req; 131e88f27b3Smrg}; 13218210155Smrg 1333c748557Ssnjstatic inline int64_t U642I64(uint64_t val) 1343c748557Ssnj{ 1353c748557Ssnj return (int64_t)*((int64_t *)&val); 1363c748557Ssnj} 13718210155Smrg 13887bf8e7cSmrgstatic float mode_vrefresh(drmModeModeInfo *mode) 13987bf8e7cSmrg{ 14087bf8e7cSmrg return mode->clock * 1000.00 14187bf8e7cSmrg / (mode->htotal * mode->vtotal); 14287bf8e7cSmrg} 14387bf8e7cSmrg 144e88f27b3Smrg#define bit_name_fn(res) \ 145e88f27b3Smrgconst char * res##_str(int type) { \ 146e88f27b3Smrg unsigned int i; \ 147e88f27b3Smrg const char *sep = ""; \ 148e88f27b3Smrg for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \ 149e88f27b3Smrg if (type & (1 << i)) { \ 150e88f27b3Smrg printf("%s%s", sep, res##_names[i]); \ 151e88f27b3Smrg sep = ", "; \ 152e88f27b3Smrg } \ 153e88f27b3Smrg } \ 154e88f27b3Smrg return NULL; \ 155e88f27b3Smrg} 156e88f27b3Smrg 157e88f27b3Smrgstatic const char *mode_type_names[] = { 158e88f27b3Smrg "builtin", 159e88f27b3Smrg "clock_c", 160e88f27b3Smrg "crtc_c", 161e88f27b3Smrg "preferred", 162e88f27b3Smrg "default", 163e88f27b3Smrg "userdef", 164e88f27b3Smrg "driver", 165e88f27b3Smrg}; 166e88f27b3Smrg 167e88f27b3Smrgstatic bit_name_fn(mode_type) 168e88f27b3Smrg 169e88f27b3Smrgstatic const char *mode_flag_names[] = { 170e88f27b3Smrg "phsync", 171e88f27b3Smrg "nhsync", 172e88f27b3Smrg "pvsync", 173e88f27b3Smrg "nvsync", 174e88f27b3Smrg "interlace", 175e88f27b3Smrg "dblscan", 176e88f27b3Smrg "csync", 177e88f27b3Smrg "pcsync", 178e88f27b3Smrg "ncsync", 179e88f27b3Smrg "hskew", 180e88f27b3Smrg "bcast", 181e88f27b3Smrg "pixmux", 182e88f27b3Smrg "dblclk", 183e88f27b3Smrg "clkdiv2" 184e88f27b3Smrg}; 185e88f27b3Smrg 186e88f27b3Smrgstatic bit_name_fn(mode_flag) 18718210155Smrg 1880655efefSmrgstatic void dump_fourcc(uint32_t fourcc) 1890655efefSmrg{ 1900655efefSmrg printf(" %c%c%c%c", 1910655efefSmrg fourcc, 1920655efefSmrg fourcc >> 8, 1930655efefSmrg fourcc >> 16, 1940655efefSmrg fourcc >> 24); 1950655efefSmrg} 1960655efefSmrg 197e88f27b3Smrgstatic void dump_encoders(struct device *dev) 19818210155Smrg{ 19918210155Smrg drmModeEncoder *encoder; 20018210155Smrg int i; 20118210155Smrg 20218210155Smrg printf("Encoders:\n"); 20318210155Smrg printf("id\tcrtc\ttype\tpossible crtcs\tpossible clones\t\n"); 20487bf8e7cSmrg for (i = 0; i < dev->resources->count_encoders; i++) { 205e88f27b3Smrg encoder = dev->resources->encoders[i].encoder; 206e88f27b3Smrg if (!encoder) 20718210155Smrg continue; 208e88f27b3Smrg 20918210155Smrg printf("%d\t%d\t%s\t0x%08x\t0x%08x\n", 21018210155Smrg encoder->encoder_id, 21118210155Smrg encoder->crtc_id, 212fe517fc9Smrg util_lookup_encoder_type_name(encoder->encoder_type), 21318210155Smrg encoder->possible_crtcs, 21418210155Smrg encoder->possible_clones); 21518210155Smrg } 21618210155Smrg printf("\n"); 21718210155Smrg} 21818210155Smrg 21987bf8e7cSmrgstatic void dump_mode(drmModeModeInfo *mode, int index) 22018210155Smrg{ 22187bf8e7cSmrg printf(" #%i %s %.2f %d %d %d %d %d %d %d %d %d", 22287bf8e7cSmrg index, 22318210155Smrg mode->name, 22487bf8e7cSmrg mode_vrefresh(mode), 22518210155Smrg mode->hdisplay, 22618210155Smrg mode->hsync_start, 22718210155Smrg mode->hsync_end, 22818210155Smrg mode->htotal, 22918210155Smrg mode->vdisplay, 23018210155Smrg mode->vsync_start, 23118210155Smrg mode->vsync_end, 2322ee35494Smrg mode->vtotal, 2332ee35494Smrg mode->clock); 234e88f27b3Smrg 235e88f27b3Smrg printf(" flags: "); 236e88f27b3Smrg mode_flag_str(mode->flags); 237e88f27b3Smrg printf("; type: "); 238e88f27b3Smrg mode_type_str(mode->type); 239e88f27b3Smrg printf("\n"); 24018210155Smrg} 24118210155Smrg 242e88f27b3Smrgstatic void dump_blob(struct device *dev, uint32_t blob_id) 243e88f27b3Smrg{ 244e88f27b3Smrg uint32_t i; 245e88f27b3Smrg unsigned char *blob_data; 246e88f27b3Smrg drmModePropertyBlobPtr blob; 247e88f27b3Smrg 248e88f27b3Smrg blob = drmModeGetPropertyBlob(dev->fd, blob_id); 2493c748557Ssnj if (!blob) { 2503c748557Ssnj printf("\n"); 251e88f27b3Smrg return; 2523c748557Ssnj } 253e88f27b3Smrg 254e88f27b3Smrg blob_data = blob->data; 255e88f27b3Smrg 256e88f27b3Smrg for (i = 0; i < blob->length; i++) { 257e88f27b3Smrg if (i % 16 == 0) 258e88f27b3Smrg printf("\n\t\t\t"); 259e88f27b3Smrg printf("%.2hhx", blob_data[i]); 260e88f27b3Smrg } 261e88f27b3Smrg printf("\n"); 262e88f27b3Smrg 263e88f27b3Smrg drmModeFreePropertyBlob(blob); 264e88f27b3Smrg} 265e88f27b3Smrg 2662b90624aSmrgstatic const char *modifier_to_string(uint64_t modifier) 2672b90624aSmrg{ 268636d5e9fSmrg static char mod_string[4096]; 269636d5e9fSmrg 270636d5e9fSmrg char *modifier_name = drmGetFormatModifierName(modifier); 271636d5e9fSmrg char *vendor_name = drmGetFormatModifierVendor(modifier); 272636d5e9fSmrg memset(mod_string, 0x00, sizeof(mod_string)); 273636d5e9fSmrg 274636d5e9fSmrg if (!modifier_name) { 275636d5e9fSmrg if (vendor_name) 276636d5e9fSmrg snprintf(mod_string, sizeof(mod_string), "%s_%s", 277636d5e9fSmrg vendor_name, "UNKNOWN_MODIFIER"); 278636d5e9fSmrg else 279636d5e9fSmrg snprintf(mod_string, sizeof(mod_string), "%s_%s", 280636d5e9fSmrg "UNKNOWN_VENDOR", "UNKNOWN_MODIFIER"); 281636d5e9fSmrg /* safe, as free is no-op for NULL */ 282636d5e9fSmrg free(vendor_name); 283636d5e9fSmrg return mod_string; 2842b90624aSmrg } 285636d5e9fSmrg 286636d5e9fSmrg if (modifier == DRM_FORMAT_MOD_LINEAR) { 287636d5e9fSmrg snprintf(mod_string, sizeof(mod_string), "%s", modifier_name); 288636d5e9fSmrg free(modifier_name); 289636d5e9fSmrg free(vendor_name); 290636d5e9fSmrg return mod_string; 291636d5e9fSmrg } 292636d5e9fSmrg 293636d5e9fSmrg snprintf(mod_string, sizeof(mod_string), "%s_%s", 294636d5e9fSmrg vendor_name, modifier_name); 295636d5e9fSmrg 296636d5e9fSmrg free(modifier_name); 297636d5e9fSmrg free(vendor_name); 298636d5e9fSmrg return mod_string; 2992b90624aSmrg} 3002b90624aSmrg 3012b90624aSmrgstatic void dump_in_formats(struct device *dev, uint32_t blob_id) 3022b90624aSmrg{ 303adfa0b0cSmrg drmModeFormatModifierIterator iter = {0}; 3042b90624aSmrg drmModePropertyBlobPtr blob; 305adfa0b0cSmrg uint32_t fmt = 0; 3062b90624aSmrg 3072b90624aSmrg printf("\t\tin_formats blob decoded:\n"); 3082b90624aSmrg blob = drmModeGetPropertyBlob(dev->fd, blob_id); 3092b90624aSmrg if (!blob) { 3102b90624aSmrg printf("\n"); 3112b90624aSmrg return; 3122b90624aSmrg } 3132b90624aSmrg 314adfa0b0cSmrg while (drmModeFormatModifierBlobIterNext(blob, &iter)) { 315adfa0b0cSmrg if (!fmt || fmt != iter.fmt) { 316adfa0b0cSmrg printf("%s\t\t\t", !fmt ? "" : "\n"); 317adfa0b0cSmrg fmt = iter.fmt; 318adfa0b0cSmrg dump_fourcc(fmt); 319adfa0b0cSmrg printf(": "); 3202b90624aSmrg } 321adfa0b0cSmrg 322adfa0b0cSmrg printf(" %s", modifier_to_string(iter.mod)); 3232b90624aSmrg } 3242b90624aSmrg 325adfa0b0cSmrg printf("\n"); 326adfa0b0cSmrg 3272b90624aSmrg drmModeFreePropertyBlob(blob); 3282b90624aSmrg} 3292b90624aSmrg 330e88f27b3Smrgstatic void dump_prop(struct device *dev, drmModePropertyPtr prop, 331e88f27b3Smrg uint32_t prop_id, uint64_t value) 33218210155Smrg{ 33318210155Smrg int i; 334e88f27b3Smrg printf("\t%d", prop_id); 335e88f27b3Smrg if (!prop) { 336e88f27b3Smrg printf("\n"); 337e88f27b3Smrg return; 338e88f27b3Smrg } 339e88f27b3Smrg 340e88f27b3Smrg printf(" %s:\n", prop->name); 341e88f27b3Smrg 342e88f27b3Smrg printf("\t\tflags:"); 343e88f27b3Smrg if (prop->flags & DRM_MODE_PROP_PENDING) 344e88f27b3Smrg printf(" pending"); 345e88f27b3Smrg if (prop->flags & DRM_MODE_PROP_IMMUTABLE) 346e88f27b3Smrg printf(" immutable"); 3473c748557Ssnj if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE)) 3483c748557Ssnj printf(" signed range"); 3493c748557Ssnj if (drm_property_type_is(prop, DRM_MODE_PROP_RANGE)) 3503c748557Ssnj printf(" range"); 3513c748557Ssnj if (drm_property_type_is(prop, DRM_MODE_PROP_ENUM)) 352e88f27b3Smrg printf(" enum"); 3533c748557Ssnj if (drm_property_type_is(prop, DRM_MODE_PROP_BITMASK)) 354e88f27b3Smrg printf(" bitmask"); 3553c748557Ssnj if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB)) 356e88f27b3Smrg printf(" blob"); 3573c748557Ssnj if (drm_property_type_is(prop, DRM_MODE_PROP_OBJECT)) 3583c748557Ssnj printf(" object"); 359e88f27b3Smrg printf("\n"); 360e88f27b3Smrg 3613c748557Ssnj if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE)) { 3623c748557Ssnj printf("\t\tvalues:"); 3633c748557Ssnj for (i = 0; i < prop->count_values; i++) 3643c748557Ssnj printf(" %"PRId64, U642I64(prop->values[i])); 3653c748557Ssnj printf("\n"); 3663c748557Ssnj } 3673c748557Ssnj 3683c748557Ssnj if (drm_property_type_is(prop, DRM_MODE_PROP_RANGE)) { 369e88f27b3Smrg printf("\t\tvalues:"); 370e88f27b3Smrg for (i = 0; i < prop->count_values; i++) 371e88f27b3Smrg printf(" %"PRIu64, prop->values[i]); 372e88f27b3Smrg printf("\n"); 373e88f27b3Smrg } 37418210155Smrg 3753c748557Ssnj if (drm_property_type_is(prop, DRM_MODE_PROP_ENUM)) { 376e88f27b3Smrg printf("\t\tenums:"); 377e88f27b3Smrg for (i = 0; i < prop->count_enums; i++) 378adfa0b0cSmrg printf(" %s=%"PRIu64, prop->enums[i].name, 379e88f27b3Smrg prop->enums[i].value); 380e88f27b3Smrg printf("\n"); 3813c748557Ssnj } else if (drm_property_type_is(prop, DRM_MODE_PROP_BITMASK)) { 382e88f27b3Smrg printf("\t\tvalues:"); 383e88f27b3Smrg for (i = 0; i < prop->count_enums; i++) 384e88f27b3Smrg printf(" %s=0x%llx", prop->enums[i].name, 385e88f27b3Smrg (1LL << prop->enums[i].value)); 386e88f27b3Smrg printf("\n"); 387e88f27b3Smrg } else { 388e88f27b3Smrg assert(prop->count_enums == 0); 389e88f27b3Smrg } 390e88f27b3Smrg 3913c748557Ssnj if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB)) { 392e88f27b3Smrg printf("\t\tblobs:\n"); 393e88f27b3Smrg for (i = 0; i < prop->count_blobs; i++) 394e88f27b3Smrg dump_blob(dev, prop->blob_ids[i]); 395e88f27b3Smrg printf("\n"); 396e88f27b3Smrg } else { 397e88f27b3Smrg assert(prop->count_blobs == 0); 39818210155Smrg } 399e88f27b3Smrg 400e88f27b3Smrg printf("\t\tvalue:"); 4013c748557Ssnj if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB)) 402e88f27b3Smrg dump_blob(dev, value); 403fe517fc9Smrg else if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE)) 404fe517fc9Smrg printf(" %"PRId64"\n", value); 405e88f27b3Smrg else 406e88f27b3Smrg printf(" %"PRIu64"\n", value); 4072b90624aSmrg 4082b90624aSmrg if (strcmp(prop->name, "IN_FORMATS") == 0) 4092b90624aSmrg dump_in_formats(dev, value); 41018210155Smrg} 41118210155Smrg 412e88f27b3Smrgstatic void dump_connectors(struct device *dev) 41318210155Smrg{ 41418210155Smrg int i, j; 41518210155Smrg 41618210155Smrg printf("Connectors:\n"); 417fe517fc9Smrg printf("id\tencoder\tstatus\t\tname\t\tsize (mm)\tmodes\tencoders\n"); 41887bf8e7cSmrg for (i = 0; i < dev->resources->count_connectors; i++) { 419e88f27b3Smrg struct connector *_connector = &dev->resources->connectors[i]; 420e88f27b3Smrg drmModeConnector *connector = _connector->connector; 421e88f27b3Smrg if (!connector) 42218210155Smrg continue; 42318210155Smrg 424fe517fc9Smrg printf("%d\t%d\t%s\t%-15s\t%dx%d\t\t%d\t", 42518210155Smrg connector->connector_id, 42618210155Smrg connector->encoder_id, 427fe517fc9Smrg util_lookup_connector_status_name(connector->connection), 428fe517fc9Smrg _connector->name, 42918210155Smrg connector->mmWidth, connector->mmHeight, 43018210155Smrg connector->count_modes); 43118210155Smrg 43222944501Smrg for (j = 0; j < connector->count_encoders; j++) 43322944501Smrg printf("%s%d", j > 0 ? ", " : "", connector->encoders[j]); 43422944501Smrg printf("\n"); 43522944501Smrg 436e88f27b3Smrg if (connector->count_modes) { 437e88f27b3Smrg printf(" modes:\n"); 43887bf8e7cSmrg printf("\tindex name refresh (Hz) hdisp hss hse htot vdisp " 4394b3d3f37Smrg "vss vse vtot\n"); 440e88f27b3Smrg for (j = 0; j < connector->count_modes; j++) 44187bf8e7cSmrg dump_mode(&connector->modes[j], j); 442e88f27b3Smrg } 44322944501Smrg 444e88f27b3Smrg if (_connector->props) { 445e88f27b3Smrg printf(" props:\n"); 446e88f27b3Smrg for (j = 0; j < (int)_connector->props->count_props; j++) 447e88f27b3Smrg dump_prop(dev, _connector->props_info[j], 448e88f27b3Smrg _connector->props->props[j], 449e88f27b3Smrg _connector->props->prop_values[j]); 450e88f27b3Smrg } 45118210155Smrg } 45218210155Smrg printf("\n"); 45318210155Smrg} 45418210155Smrg 455e88f27b3Smrgstatic void dump_crtcs(struct device *dev) 45618210155Smrg{ 45718210155Smrg int i; 458e88f27b3Smrg uint32_t j; 45918210155Smrg 46018210155Smrg printf("CRTCs:\n"); 46118210155Smrg printf("id\tfb\tpos\tsize\n"); 46287bf8e7cSmrg for (i = 0; i < dev->resources->count_crtcs; i++) { 463e88f27b3Smrg struct crtc *_crtc = &dev->resources->crtcs[i]; 464e88f27b3Smrg drmModeCrtc *crtc = _crtc->crtc; 465e88f27b3Smrg if (!crtc) 46618210155Smrg continue; 467e88f27b3Smrg 46818210155Smrg printf("%d\t%d\t(%d,%d)\t(%dx%d)\n", 46918210155Smrg crtc->crtc_id, 47018210155Smrg crtc->buffer_id, 47118210155Smrg crtc->x, crtc->y, 47218210155Smrg crtc->width, crtc->height); 47387bf8e7cSmrg dump_mode(&crtc->mode, 0); 47418210155Smrg 475e88f27b3Smrg if (_crtc->props) { 476e88f27b3Smrg printf(" props:\n"); 477e88f27b3Smrg for (j = 0; j < _crtc->props->count_props; j++) 478e88f27b3Smrg dump_prop(dev, _crtc->props_info[j], 479e88f27b3Smrg _crtc->props->props[j], 480e88f27b3Smrg _crtc->props->prop_values[j]); 481e88f27b3Smrg } else { 482e88f27b3Smrg printf(" no properties found\n"); 483e88f27b3Smrg } 48418210155Smrg } 48518210155Smrg printf("\n"); 48618210155Smrg} 48718210155Smrg 488e88f27b3Smrgstatic void dump_framebuffers(struct device *dev) 48918210155Smrg{ 49018210155Smrg drmModeFB *fb; 49118210155Smrg int i; 49218210155Smrg 49318210155Smrg printf("Frame buffers:\n"); 49418210155Smrg printf("id\tsize\tpitch\n"); 49587bf8e7cSmrg for (i = 0; i < dev->resources->count_fbs; i++) { 496e88f27b3Smrg fb = dev->resources->fbs[i].fb; 497e88f27b3Smrg if (!fb) 49818210155Smrg continue; 499e88f27b3Smrg 50022944501Smrg printf("%u\t(%ux%u)\t%u\n", 50118210155Smrg fb->fb_id, 50222944501Smrg fb->width, fb->height, 50322944501Smrg fb->pitch); 50418210155Smrg } 50518210155Smrg printf("\n"); 50618210155Smrg} 50718210155Smrg 508e88f27b3Smrgstatic void dump_planes(struct device *dev) 50918210155Smrg{ 510e88f27b3Smrg unsigned int i, j; 51118210155Smrg 512e88f27b3Smrg printf("Planes:\n"); 513e88f27b3Smrg printf("id\tcrtc\tfb\tCRTC x,y\tx,y\tgamma size\tpossible crtcs\n"); 51418210155Smrg 51587bf8e7cSmrg for (i = 0; i < dev->resources->count_planes; i++) { 516e88f27b3Smrg struct plane *plane = &dev->resources->planes[i]; 517e88f27b3Smrg drmModePlane *ovr = plane->plane; 518e88f27b3Smrg if (!ovr) 51918210155Smrg continue; 52018210155Smrg 521e88f27b3Smrg printf("%d\t%d\t%d\t%d,%d\t\t%d,%d\t%-8d\t0x%08x\n", 522e88f27b3Smrg ovr->plane_id, ovr->crtc_id, ovr->fb_id, 523e88f27b3Smrg ovr->crtc_x, ovr->crtc_y, ovr->x, ovr->y, 524e88f27b3Smrg ovr->gamma_size, ovr->possible_crtcs); 525e88f27b3Smrg 526e88f27b3Smrg if (!ovr->count_formats) 52718210155Smrg continue; 52818210155Smrg 529e88f27b3Smrg printf(" formats:"); 530e88f27b3Smrg for (j = 0; j < ovr->count_formats; j++) 5310655efefSmrg dump_fourcc(ovr->formats[j]); 532e88f27b3Smrg printf("\n"); 533e88f27b3Smrg 534e88f27b3Smrg if (plane->props) { 535e88f27b3Smrg printf(" props:\n"); 536e88f27b3Smrg for (j = 0; j < plane->props->count_props; j++) 537e88f27b3Smrg dump_prop(dev, plane->props_info[j], 538e88f27b3Smrg plane->props->props[j], 539e88f27b3Smrg plane->props->prop_values[j]); 540e88f27b3Smrg } else { 541e88f27b3Smrg printf(" no properties found\n"); 54218210155Smrg } 543e88f27b3Smrg } 544e88f27b3Smrg printf("\n"); 54518210155Smrg 546e88f27b3Smrg return; 547e88f27b3Smrg} 548e88f27b3Smrg 549e88f27b3Smrgstatic void free_resources(struct resources *res) 550e88f27b3Smrg{ 551fe517fc9Smrg int i; 552fe517fc9Smrg 553e88f27b3Smrg if (!res) 554e88f27b3Smrg return; 55518210155Smrg 55687bf8e7cSmrg#define free_resource(_res, type, Type) \ 557e88f27b3Smrg do { \ 558e88f27b3Smrg if (!(_res)->type##s) \ 559e88f27b3Smrg break; \ 56087bf8e7cSmrg for (i = 0; i < (int)(_res)->count_##type##s; ++i) { \ 561e88f27b3Smrg if (!(_res)->type##s[i].type) \ 562e88f27b3Smrg break; \ 563e88f27b3Smrg drmModeFree##Type((_res)->type##s[i].type); \ 564e88f27b3Smrg } \ 565e88f27b3Smrg free((_res)->type##s); \ 566e88f27b3Smrg } while (0) 567e88f27b3Smrg 56887bf8e7cSmrg#define free_properties(_res, type) \ 569e88f27b3Smrg do { \ 57087bf8e7cSmrg for (i = 0; i < (int)(_res)->count_##type##s; ++i) { \ 57187bf8e7cSmrg unsigned int j; \ 57287bf8e7cSmrg for (j = 0; j < res->type##s[i].props->count_props; ++j)\ 57387bf8e7cSmrg drmModeFreeProperty(res->type##s[i].props_info[j]);\ 574e88f27b3Smrg free(res->type##s[i].props_info); \ 57587bf8e7cSmrg drmModeFreeObjectProperties(res->type##s[i].props); \ 576e88f27b3Smrg } \ 577e88f27b3Smrg } while (0) 578e88f27b3Smrg 57987bf8e7cSmrg free_properties(res, plane); 58087bf8e7cSmrg free_resource(res, plane, Plane); 581fe517fc9Smrg 58287bf8e7cSmrg free_properties(res, connector); 58387bf8e7cSmrg free_properties(res, crtc); 584fe517fc9Smrg 58587bf8e7cSmrg for (i = 0; i < res->count_connectors; i++) 58687bf8e7cSmrg free(res->connectors[i].name); 587e88f27b3Smrg 58887bf8e7cSmrg free_resource(res, fb, FB); 58987bf8e7cSmrg free_resource(res, connector, Connector); 59087bf8e7cSmrg free_resource(res, encoder, Encoder); 59187bf8e7cSmrg free_resource(res, crtc, Crtc); 59218210155Smrg 593e88f27b3Smrg free(res); 594e88f27b3Smrg} 59518210155Smrg 596e88f27b3Smrgstatic struct resources *get_resources(struct device *dev) 597e88f27b3Smrg{ 59887bf8e7cSmrg drmModeRes *_res; 59987bf8e7cSmrg drmModePlaneRes *plane_res; 600e88f27b3Smrg struct resources *res; 601e88f27b3Smrg int i; 60218210155Smrg 603424e9256Smrg res = calloc(1, sizeof(*res)); 604e88f27b3Smrg if (res == 0) 605e88f27b3Smrg return NULL; 606e88f27b3Smrg 607424e9256Smrg drmSetClientCap(dev->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); 608e88f27b3Smrg 60987bf8e7cSmrg _res = drmModeGetResources(dev->fd); 61087bf8e7cSmrg if (!_res) { 611e88f27b3Smrg fprintf(stderr, "drmModeGetResources failed: %s\n", 612e88f27b3Smrg strerror(errno)); 61387bf8e7cSmrg free(res); 61487bf8e7cSmrg return NULL; 615e88f27b3Smrg } 61618210155Smrg 61787bf8e7cSmrg res->count_crtcs = _res->count_crtcs; 61887bf8e7cSmrg res->count_encoders = _res->count_encoders; 61987bf8e7cSmrg res->count_connectors = _res->count_connectors; 62087bf8e7cSmrg res->count_fbs = _res->count_fbs; 621e88f27b3Smrg 62287bf8e7cSmrg res->crtcs = calloc(res->count_crtcs, sizeof(*res->crtcs)); 62387bf8e7cSmrg res->encoders = calloc(res->count_encoders, sizeof(*res->encoders)); 62487bf8e7cSmrg res->connectors = calloc(res->count_connectors, sizeof(*res->connectors)); 62587bf8e7cSmrg res->fbs = calloc(res->count_fbs, sizeof(*res->fbs)); 62687bf8e7cSmrg 62787bf8e7cSmrg if (!res->crtcs || !res->encoders || !res->connectors || !res->fbs) { 62887bf8e7cSmrg drmModeFreeResources(_res); 629e88f27b3Smrg goto error; 63087bf8e7cSmrg } 631e88f27b3Smrg 632e88f27b3Smrg#define get_resource(_res, __res, type, Type) \ 633e88f27b3Smrg do { \ 63487bf8e7cSmrg for (i = 0; i < (int)(_res)->count_##type##s; ++i) { \ 63587bf8e7cSmrg uint32_t type##id = (__res)->type##s[i]; \ 63687bf8e7cSmrg (_res)->type##s[i].type = \ 63787bf8e7cSmrg drmModeGet##Type(dev->fd, type##id); \ 63887bf8e7cSmrg if (!(_res)->type##s[i].type) \ 639e88f27b3Smrg fprintf(stderr, "could not get %s %i: %s\n", \ 64087bf8e7cSmrg #type, type##id, \ 641e88f27b3Smrg strerror(errno)); \ 642e88f27b3Smrg } \ 643e88f27b3Smrg } while (0) 644e88f27b3Smrg 64587bf8e7cSmrg get_resource(res, _res, crtc, Crtc); 64687bf8e7cSmrg get_resource(res, _res, encoder, Encoder); 64787bf8e7cSmrg get_resource(res, _res, connector, Connector); 64887bf8e7cSmrg get_resource(res, _res, fb, FB); 64987bf8e7cSmrg 65087bf8e7cSmrg drmModeFreeResources(_res); 651e88f27b3Smrg 652fe517fc9Smrg /* Set the name of all connectors based on the type name and the per-type ID. */ 65387bf8e7cSmrg for (i = 0; i < res->count_connectors; i++) { 654fe517fc9Smrg struct connector *connector = &res->connectors[i]; 655fe517fc9Smrg drmModeConnector *conn = connector->connector; 6562b90624aSmrg int num; 657fe517fc9Smrg 6582b90624aSmrg num = asprintf(&connector->name, "%s-%u", 659fe517fc9Smrg util_lookup_connector_type_name(conn->connector_type), 660fe517fc9Smrg conn->connector_type_id); 6612b90624aSmrg if (num < 0) 6622b90624aSmrg goto error; 663fe517fc9Smrg } 664fe517fc9Smrg 66587bf8e7cSmrg#define get_properties(_res, type, Type) \ 666e88f27b3Smrg do { \ 66787bf8e7cSmrg for (i = 0; i < (int)(_res)->count_##type##s; ++i) { \ 668e88f27b3Smrg struct type *obj = &res->type##s[i]; \ 669e88f27b3Smrg unsigned int j; \ 670e88f27b3Smrg obj->props = \ 671e88f27b3Smrg drmModeObjectGetProperties(dev->fd, obj->type->type##_id, \ 672e88f27b3Smrg DRM_MODE_OBJECT_##Type); \ 673e88f27b3Smrg if (!obj->props) { \ 674e88f27b3Smrg fprintf(stderr, \ 675e88f27b3Smrg "could not get %s %i properties: %s\n", \ 676e88f27b3Smrg #type, obj->type->type##_id, \ 677e88f27b3Smrg strerror(errno)); \ 678e88f27b3Smrg continue; \ 679e88f27b3Smrg } \ 680424e9256Smrg obj->props_info = calloc(obj->props->count_props, \ 681424e9256Smrg sizeof(*obj->props_info)); \ 682e88f27b3Smrg if (!obj->props_info) \ 683e88f27b3Smrg continue; \ 684e88f27b3Smrg for (j = 0; j < obj->props->count_props; ++j) \ 685e88f27b3Smrg obj->props_info[j] = \ 686e88f27b3Smrg drmModeGetProperty(dev->fd, obj->props->props[j]); \ 687e88f27b3Smrg } \ 688e88f27b3Smrg } while (0) 689e88f27b3Smrg 69087bf8e7cSmrg get_properties(res, crtc, CRTC); 69187bf8e7cSmrg get_properties(res, connector, CONNECTOR); 692e88f27b3Smrg 69387bf8e7cSmrg for (i = 0; i < res->count_crtcs; ++i) 694e88f27b3Smrg res->crtcs[i].mode = &res->crtcs[i].crtc->mode; 695e88f27b3Smrg 69687bf8e7cSmrg plane_res = drmModeGetPlaneResources(dev->fd); 69787bf8e7cSmrg if (!plane_res) { 698e88f27b3Smrg fprintf(stderr, "drmModeGetPlaneResources failed: %s\n", 699e88f27b3Smrg strerror(errno)); 700e88f27b3Smrg return res; 70118210155Smrg } 70218210155Smrg 70387bf8e7cSmrg res->count_planes = plane_res->count_planes; 70487bf8e7cSmrg 70587bf8e7cSmrg res->planes = calloc(res->count_planes, sizeof(*res->planes)); 70687bf8e7cSmrg if (!res->planes) { 70787bf8e7cSmrg drmModeFreePlaneResources(plane_res); 708e88f27b3Smrg goto error; 70987bf8e7cSmrg } 710e88f27b3Smrg 711e88f27b3Smrg get_resource(res, plane_res, plane, Plane); 71287bf8e7cSmrg drmModeFreePlaneResources(plane_res); 71387bf8e7cSmrg get_properties(res, plane, PLANE); 714e88f27b3Smrg 715e88f27b3Smrg return res; 716e88f27b3Smrg 717e88f27b3Smrgerror: 718e88f27b3Smrg free_resources(res); 719e88f27b3Smrg return NULL; 72018210155Smrg} 72118210155Smrg 72287bf8e7cSmrgstatic struct crtc *get_crtc_by_id(struct device *dev, uint32_t id) 723d049871aSmrg{ 724e88f27b3Smrg int i; 72518210155Smrg 72687bf8e7cSmrg for (i = 0; i < dev->resources->count_crtcs; ++i) { 727e88f27b3Smrg drmModeCrtc *crtc = dev->resources->crtcs[i].crtc; 728e88f27b3Smrg if (crtc && crtc->crtc_id == id) 72987bf8e7cSmrg return &dev->resources->crtcs[i]; 730e88f27b3Smrg } 731d049871aSmrg 73287bf8e7cSmrg return NULL; 73387bf8e7cSmrg} 73487bf8e7cSmrg 73587bf8e7cSmrgstatic uint32_t get_crtc_mask(struct device *dev, struct crtc *crtc) 73687bf8e7cSmrg{ 73787bf8e7cSmrg unsigned int i; 73887bf8e7cSmrg 73987bf8e7cSmrg for (i = 0; i < (unsigned int)dev->resources->count_crtcs; i++) { 74087bf8e7cSmrg if (crtc->crtc->crtc_id == dev->resources->crtcs[i].crtc->crtc_id) 74187bf8e7cSmrg return 1 << i; 74287bf8e7cSmrg } 74387bf8e7cSmrg /* Unreachable: crtc->crtc is one of resources->crtcs[] */ 74487bf8e7cSmrg /* Don't return zero or static analysers will complain */ 74587bf8e7cSmrg abort(); 74687bf8e7cSmrg return 0; 747d049871aSmrg} 748d049871aSmrg 749fe517fc9Smrgstatic drmModeConnector *get_connector_by_name(struct device *dev, const char *name) 750fe517fc9Smrg{ 751fe517fc9Smrg struct connector *connector; 752fe517fc9Smrg int i; 753fe517fc9Smrg 75487bf8e7cSmrg for (i = 0; i < dev->resources->count_connectors; i++) { 755fe517fc9Smrg connector = &dev->resources->connectors[i]; 756fe517fc9Smrg 757fe517fc9Smrg if (strcmp(connector->name, name) == 0) 758fe517fc9Smrg return connector->connector; 759fe517fc9Smrg } 760fe517fc9Smrg 761fe517fc9Smrg return NULL; 762fe517fc9Smrg} 763fe517fc9Smrg 764e88f27b3Smrgstatic drmModeConnector *get_connector_by_id(struct device *dev, uint32_t id) 76518210155Smrg{ 766e88f27b3Smrg drmModeConnector *connector; 767e88f27b3Smrg int i; 768e88f27b3Smrg 76987bf8e7cSmrg for (i = 0; i < dev->resources->count_connectors; i++) { 770e88f27b3Smrg connector = dev->resources->connectors[i].connector; 771e88f27b3Smrg if (connector && connector->connector_id == id) 772e88f27b3Smrg return connector; 773e88f27b3Smrg } 774e88f27b3Smrg 775e88f27b3Smrg return NULL; 776e88f27b3Smrg} 777e88f27b3Smrg 778e88f27b3Smrgstatic drmModeEncoder *get_encoder_by_id(struct device *dev, uint32_t id) 779e88f27b3Smrg{ 780e88f27b3Smrg drmModeEncoder *encoder; 781e88f27b3Smrg int i; 782e88f27b3Smrg 78387bf8e7cSmrg for (i = 0; i < dev->resources->count_encoders; i++) { 784e88f27b3Smrg encoder = dev->resources->encoders[i].encoder; 785e88f27b3Smrg if (encoder && encoder->encoder_id == id) 786e88f27b3Smrg return encoder; 787e88f27b3Smrg } 788e88f27b3Smrg 789e88f27b3Smrg return NULL; 790e88f27b3Smrg} 791e88f27b3Smrg 792e88f27b3Smrg/* ----------------------------------------------------------------------------- 793e88f27b3Smrg * Pipes and planes 794e88f27b3Smrg */ 795e88f27b3Smrg 796e88f27b3Smrg/* 797e88f27b3Smrg * Mode setting with the kernel interfaces is a bit of a chore. 798e88f27b3Smrg * First you have to find the connector in question and make sure the 799e88f27b3Smrg * requested mode is available. 800e88f27b3Smrg * Then you need to find the encoder attached to that connector so you 801e88f27b3Smrg * can bind it with a free crtc. 802e88f27b3Smrg */ 803e88f27b3Smrgstruct pipe_arg { 804fe517fc9Smrg const char **cons; 805e88f27b3Smrg uint32_t *con_ids; 806e88f27b3Smrg unsigned int num_cons; 807e88f27b3Smrg uint32_t crtc_id; 808e88f27b3Smrg char mode_str[64]; 809e88f27b3Smrg char format_str[5]; 81087bf8e7cSmrg float vrefresh; 811e88f27b3Smrg unsigned int fourcc; 812e88f27b3Smrg drmModeModeInfo *mode; 813e88f27b3Smrg struct crtc *crtc; 814e88f27b3Smrg unsigned int fb_id[2], current_fb_id; 815e88f27b3Smrg struct timeval start; 816e88f27b3Smrg 817e88f27b3Smrg int swap_count; 818e88f27b3Smrg}; 819e88f27b3Smrg 820e88f27b3Smrgstruct plane_arg { 8212ee35494Smrg uint32_t plane_id; /* the id of plane to use */ 822e88f27b3Smrg uint32_t crtc_id; /* the id of CRTC to bind to */ 823e88f27b3Smrg bool has_position; 824e88f27b3Smrg int32_t x, y; 825e88f27b3Smrg uint32_t w, h; 826e88f27b3Smrg double scale; 827e88f27b3Smrg unsigned int fb_id; 8286260e5d5Smrg unsigned int old_fb_id; 829424e9256Smrg struct bo *bo; 8306260e5d5Smrg struct bo *old_bo; 831e88f27b3Smrg char format_str[5]; /* need to leave room for terminating \0 */ 832e88f27b3Smrg unsigned int fourcc; 833e88f27b3Smrg}; 834e88f27b3Smrg 835e88f27b3Smrgstatic drmModeModeInfo * 836e88f27b3Smrgconnector_find_mode(struct device *dev, uint32_t con_id, const char *mode_str, 83787bf8e7cSmrg const float vrefresh) 838e88f27b3Smrg{ 839e88f27b3Smrg drmModeConnector *connector; 840e88f27b3Smrg drmModeModeInfo *mode; 841e88f27b3Smrg int i; 842e88f27b3Smrg 843e88f27b3Smrg connector = get_connector_by_id(dev, con_id); 844e88f27b3Smrg if (!connector || !connector->count_modes) 845e88f27b3Smrg return NULL; 846e88f27b3Smrg 84787bf8e7cSmrg /* Pick by Index */ 84887bf8e7cSmrg if (mode_str[0] == '#') { 84987bf8e7cSmrg int index = atoi(mode_str + 1); 85087bf8e7cSmrg 85187bf8e7cSmrg if (index >= connector->count_modes || index < 0) 85287bf8e7cSmrg return NULL; 85387bf8e7cSmrg return &connector->modes[index]; 85487bf8e7cSmrg } 85587bf8e7cSmrg 85687bf8e7cSmrg /* Pick by Name */ 857e88f27b3Smrg for (i = 0; i < connector->count_modes; i++) { 858e88f27b3Smrg mode = &connector->modes[i]; 859e88f27b3Smrg if (!strcmp(mode->name, mode_str)) { 86087bf8e7cSmrg /* If the vertical refresh frequency is not specified 86187bf8e7cSmrg * then return the first mode that match with the name. 86287bf8e7cSmrg * Else, return the mode that match the name and 86387bf8e7cSmrg * the specified vertical refresh frequency. 864e88f27b3Smrg */ 865e88f27b3Smrg if (vrefresh == 0) 866e88f27b3Smrg return mode; 86787bf8e7cSmrg else if (fabs(mode_vrefresh(mode) - vrefresh) < 0.005) 868e88f27b3Smrg return mode; 86918210155Smrg } 870e88f27b3Smrg } 87118210155Smrg 872e88f27b3Smrg return NULL; 87318210155Smrg} 87418210155Smrg 875e88f27b3Smrgstatic struct crtc *pipe_find_crtc(struct device *dev, struct pipe_arg *pipe) 87618210155Smrg{ 877e88f27b3Smrg uint32_t possible_crtcs = ~0; 878e88f27b3Smrg uint32_t active_crtcs = 0; 879e88f27b3Smrg unsigned int crtc_idx; 880e88f27b3Smrg unsigned int i; 881e88f27b3Smrg int j; 882e88f27b3Smrg 883e88f27b3Smrg for (i = 0; i < pipe->num_cons; ++i) { 884e88f27b3Smrg uint32_t crtcs_for_connector = 0; 885e88f27b3Smrg drmModeConnector *connector; 886e88f27b3Smrg drmModeEncoder *encoder; 88787bf8e7cSmrg struct crtc *crtc; 888e88f27b3Smrg 889e88f27b3Smrg connector = get_connector_by_id(dev, pipe->con_ids[i]); 890e88f27b3Smrg if (!connector) 891e88f27b3Smrg return NULL; 892e88f27b3Smrg 893e88f27b3Smrg for (j = 0; j < connector->count_encoders; ++j) { 894e88f27b3Smrg encoder = get_encoder_by_id(dev, connector->encoders[j]); 895e88f27b3Smrg if (!encoder) 896e88f27b3Smrg continue; 897e88f27b3Smrg 898e88f27b3Smrg crtcs_for_connector |= encoder->possible_crtcs; 89987bf8e7cSmrg crtc = get_crtc_by_id(dev, encoder->crtc_id); 90087bf8e7cSmrg if (!crtc) 90187bf8e7cSmrg continue; 90287bf8e7cSmrg active_crtcs |= get_crtc_mask(dev, crtc); 903e88f27b3Smrg } 90418210155Smrg 905e88f27b3Smrg possible_crtcs &= crtcs_for_connector; 90618210155Smrg } 90718210155Smrg 908e88f27b3Smrg if (!possible_crtcs) 909e88f27b3Smrg return NULL; 910e88f27b3Smrg 911e88f27b3Smrg /* Return the first possible and active CRTC if one exists, or the first 912e88f27b3Smrg * possible CRTC otherwise. 913e88f27b3Smrg */ 914e88f27b3Smrg if (possible_crtcs & active_crtcs) 915e88f27b3Smrg crtc_idx = ffs(possible_crtcs & active_crtcs); 916e88f27b3Smrg else 917e88f27b3Smrg crtc_idx = ffs(possible_crtcs); 918e88f27b3Smrg 919e88f27b3Smrg return &dev->resources->crtcs[crtc_idx - 1]; 920e88f27b3Smrg} 921e88f27b3Smrg 922e88f27b3Smrgstatic int pipe_find_crtc_and_mode(struct device *dev, struct pipe_arg *pipe) 923e88f27b3Smrg{ 924e88f27b3Smrg drmModeModeInfo *mode = NULL; 925e88f27b3Smrg int i; 926e88f27b3Smrg 927e88f27b3Smrg pipe->mode = NULL; 928e88f27b3Smrg 929e88f27b3Smrg for (i = 0; i < (int)pipe->num_cons; i++) { 930e88f27b3Smrg mode = connector_find_mode(dev, pipe->con_ids[i], 931e88f27b3Smrg pipe->mode_str, pipe->vrefresh); 932e88f27b3Smrg if (mode == NULL) { 93387bf8e7cSmrg if (pipe->vrefresh) 93487bf8e7cSmrg fprintf(stderr, 93587bf8e7cSmrg "failed to find mode " 93687bf8e7cSmrg "\"%s-%.2fHz\" for connector %s\n", 93787bf8e7cSmrg pipe->mode_str, pipe->vrefresh, pipe->cons[i]); 93887bf8e7cSmrg else 93987bf8e7cSmrg fprintf(stderr, 940fe517fc9Smrg "failed to find mode \"%s\" for connector %s\n", 941fe517fc9Smrg pipe->mode_str, pipe->cons[i]); 942e88f27b3Smrg return -EINVAL; 943e88f27b3Smrg } 94418210155Smrg } 94518210155Smrg 946e88f27b3Smrg /* If the CRTC ID was specified, get the corresponding CRTC. Otherwise 947e88f27b3Smrg * locate a CRTC that can be attached to all the connectors. 948e88f27b3Smrg */ 949e88f27b3Smrg if (pipe->crtc_id != (uint32_t)-1) { 95087bf8e7cSmrg pipe->crtc = get_crtc_by_id(dev, pipe->crtc_id); 951e88f27b3Smrg } else { 952e88f27b3Smrg pipe->crtc = pipe_find_crtc(dev, pipe); 95387bf8e7cSmrg pipe->crtc_id = pipe->crtc->crtc->crtc_id; 95418210155Smrg } 955d049871aSmrg 956e88f27b3Smrg if (!pipe->crtc) { 957e88f27b3Smrg fprintf(stderr, "failed to find CRTC for pipe\n"); 958e88f27b3Smrg return -EINVAL; 959e88f27b3Smrg } 960d049871aSmrg 961e88f27b3Smrg pipe->mode = mode; 962e88f27b3Smrg pipe->crtc->mode = mode; 96318210155Smrg 96418210155Smrg return 0; 96518210155Smrg} 96618210155Smrg 967e88f27b3Smrg/* ----------------------------------------------------------------------------- 968e88f27b3Smrg * Properties 969e88f27b3Smrg */ 970e88f27b3Smrg 971e88f27b3Smrgstruct property_arg { 972e88f27b3Smrg uint32_t obj_id; 973e88f27b3Smrg uint32_t obj_type; 974e88f27b3Smrg char name[DRM_PROP_NAME_LEN+1]; 975e88f27b3Smrg uint32_t prop_id; 976e88f27b3Smrg uint64_t value; 977bf6cc7dcSmrg bool optional; 978e88f27b3Smrg}; 979e88f27b3Smrg 980bf6cc7dcSmrgstatic bool set_property(struct device *dev, struct property_arg *p) 98122944501Smrg{ 982e88f27b3Smrg drmModeObjectProperties *props = NULL; 983e88f27b3Smrg drmModePropertyRes **props_info = NULL; 984e88f27b3Smrg const char *obj_type; 985e88f27b3Smrg int ret; 986e88f27b3Smrg int i; 98722944501Smrg 988e88f27b3Smrg p->obj_type = 0; 989e88f27b3Smrg p->prop_id = 0; 990e88f27b3Smrg 99187bf8e7cSmrg#define find_object(_res, type, Type) \ 992e88f27b3Smrg do { \ 99387bf8e7cSmrg for (i = 0; i < (int)(_res)->count_##type##s; ++i) { \ 994e88f27b3Smrg struct type *obj = &(_res)->type##s[i]; \ 995e88f27b3Smrg if (obj->type->type##_id != p->obj_id) \ 996e88f27b3Smrg continue; \ 997e88f27b3Smrg p->obj_type = DRM_MODE_OBJECT_##Type; \ 998e88f27b3Smrg obj_type = #Type; \ 999e88f27b3Smrg props = obj->props; \ 1000e88f27b3Smrg props_info = obj->props_info; \ 1001e88f27b3Smrg } \ 1002e88f27b3Smrg } while(0) \ 1003e88f27b3Smrg 100487bf8e7cSmrg find_object(dev->resources, crtc, CRTC); 1005e88f27b3Smrg if (p->obj_type == 0) 100687bf8e7cSmrg find_object(dev->resources, connector, CONNECTOR); 1007e88f27b3Smrg if (p->obj_type == 0) 100887bf8e7cSmrg find_object(dev->resources, plane, PLANE); 1009e88f27b3Smrg if (p->obj_type == 0) { 1010e88f27b3Smrg fprintf(stderr, "Object %i not found, can't set property\n", 1011e88f27b3Smrg p->obj_id); 1012bf6cc7dcSmrg return false; 1013e88f27b3Smrg } 101422944501Smrg 1015e88f27b3Smrg if (!props) { 1016e88f27b3Smrg fprintf(stderr, "%s %i has no properties\n", 1017e88f27b3Smrg obj_type, p->obj_id); 1018bf6cc7dcSmrg return false; 101922944501Smrg } 102022944501Smrg 1021e88f27b3Smrg for (i = 0; i < (int)props->count_props; ++i) { 1022e88f27b3Smrg if (!props_info[i]) 1023e88f27b3Smrg continue; 1024e88f27b3Smrg if (strcmp(props_info[i]->name, p->name) == 0) 1025e88f27b3Smrg break; 102622944501Smrg } 102722944501Smrg 1028e88f27b3Smrg if (i == (int)props->count_props) { 1029bf6cc7dcSmrg if (!p->optional) 1030bf6cc7dcSmrg fprintf(stderr, "%s %i has no %s property\n", 1031bf6cc7dcSmrg obj_type, p->obj_id, p->name); 1032bf6cc7dcSmrg return false; 1033e88f27b3Smrg } 103422944501Smrg 1035e88f27b3Smrg p->prop_id = props->props[i]; 103622944501Smrg 10376260e5d5Smrg if (!dev->use_atomic) 10386260e5d5Smrg ret = drmModeObjectSetProperty(dev->fd, p->obj_id, p->obj_type, 10396260e5d5Smrg p->prop_id, p->value); 10406260e5d5Smrg else 10416260e5d5Smrg ret = drmModeAtomicAddProperty(dev->req, p->obj_id, p->prop_id, p->value); 10426260e5d5Smrg 1043e88f27b3Smrg if (ret < 0) 1044e88f27b3Smrg fprintf(stderr, "failed to set %s %i property %s to %" PRIu64 ": %s\n", 1045e88f27b3Smrg obj_type, p->obj_id, p->name, p->value, strerror(errno)); 1046bf6cc7dcSmrg 1047bf6cc7dcSmrg return true; 104822944501Smrg} 104922944501Smrg 1050e88f27b3Smrg/* -------------------------------------------------------------------------- */ 1051e88f27b3Smrg 1052e88f27b3Smrgstatic void 105322944501Smrgpage_flip_handler(int fd, unsigned int frame, 105422944501Smrg unsigned int sec, unsigned int usec, void *data) 105522944501Smrg{ 1056e88f27b3Smrg struct pipe_arg *pipe; 105722944501Smrg unsigned int new_fb_id; 105822944501Smrg struct timeval end; 105922944501Smrg double t; 106022944501Smrg 1061e88f27b3Smrg pipe = data; 1062e88f27b3Smrg if (pipe->current_fb_id == pipe->fb_id[0]) 1063e88f27b3Smrg new_fb_id = pipe->fb_id[1]; 106422944501Smrg else 1065e88f27b3Smrg new_fb_id = pipe->fb_id[0]; 1066e88f27b3Smrg 106787bf8e7cSmrg drmModePageFlip(fd, pipe->crtc_id, new_fb_id, 1068e88f27b3Smrg DRM_MODE_PAGE_FLIP_EVENT, pipe); 1069e88f27b3Smrg pipe->current_fb_id = new_fb_id; 1070e88f27b3Smrg pipe->swap_count++; 1071e88f27b3Smrg if (pipe->swap_count == 60) { 107222944501Smrg gettimeofday(&end, NULL); 107322944501Smrg t = end.tv_sec + end.tv_usec * 1e-6 - 1074e88f27b3Smrg (pipe->start.tv_sec + pipe->start.tv_usec * 1e-6); 1075e88f27b3Smrg fprintf(stderr, "freq: %.02fHz\n", pipe->swap_count / t); 1076e88f27b3Smrg pipe->swap_count = 0; 1077e88f27b3Smrg pipe->start = end; 107822944501Smrg } 107922944501Smrg} 108022944501Smrg 1081424e9256Smrgstatic bool format_support(const drmModePlanePtr ovr, uint32_t fmt) 1082424e9256Smrg{ 1083424e9256Smrg unsigned int i; 1084424e9256Smrg 1085424e9256Smrg for (i = 0; i < ovr->count_formats; ++i) { 1086424e9256Smrg if (ovr->formats[i] == fmt) 1087424e9256Smrg return true; 1088424e9256Smrg } 1089424e9256Smrg 1090424e9256Smrg return false; 1091424e9256Smrg} 1092424e9256Smrg 10936260e5d5Smrgstatic void add_property(struct device *dev, uint32_t obj_id, 10946260e5d5Smrg const char *name, uint64_t value) 10956260e5d5Smrg{ 10966260e5d5Smrg struct property_arg p; 10976260e5d5Smrg 10986260e5d5Smrg p.obj_id = obj_id; 10996260e5d5Smrg strcpy(p.name, name); 11006260e5d5Smrg p.value = value; 11016260e5d5Smrg 11026260e5d5Smrg set_property(dev, &p); 11036260e5d5Smrg} 11046260e5d5Smrg 1105bf6cc7dcSmrgstatic bool add_property_optional(struct device *dev, uint32_t obj_id, 1106bf6cc7dcSmrg const char *name, uint64_t value) 1107bf6cc7dcSmrg{ 1108bf6cc7dcSmrg struct property_arg p; 1109bf6cc7dcSmrg 1110bf6cc7dcSmrg p.obj_id = obj_id; 1111bf6cc7dcSmrg strcpy(p.name, name); 1112bf6cc7dcSmrg p.value = value; 1113bf6cc7dcSmrg p.optional = true; 1114bf6cc7dcSmrg 1115bf6cc7dcSmrg return set_property(dev, &p); 1116bf6cc7dcSmrg} 1117bf6cc7dcSmrg 1118bf6cc7dcSmrgstatic void set_gamma(struct device *dev, unsigned crtc_id, unsigned fourcc) 1119bf6cc7dcSmrg{ 1120bf6cc7dcSmrg unsigned blob_id = 0; 1121bf6cc7dcSmrg /* TODO: support 1024-sized LUTs, when the use-case arises */ 1122bf6cc7dcSmrg struct drm_color_lut gamma_lut[256]; 1123bf6cc7dcSmrg int i, ret; 1124bf6cc7dcSmrg 1125bf6cc7dcSmrg if (fourcc == DRM_FORMAT_C8) { 1126bf6cc7dcSmrg /* TODO: Add C8 support for more patterns */ 1127bf6cc7dcSmrg util_smpte_c8_gamma(256, gamma_lut); 1128bf6cc7dcSmrg drmModeCreatePropertyBlob(dev->fd, gamma_lut, sizeof(gamma_lut), &blob_id); 1129bf6cc7dcSmrg } else { 1130bf6cc7dcSmrg for (i = 0; i < 256; i++) { 1131bf6cc7dcSmrg gamma_lut[i].red = 1132bf6cc7dcSmrg gamma_lut[i].green = 1133bf6cc7dcSmrg gamma_lut[i].blue = i << 8; 1134bf6cc7dcSmrg } 1135bf6cc7dcSmrg } 1136bf6cc7dcSmrg 1137bf6cc7dcSmrg add_property_optional(dev, crtc_id, "DEGAMMA_LUT", 0); 1138bf6cc7dcSmrg add_property_optional(dev, crtc_id, "CTM", 0); 1139bf6cc7dcSmrg if (!add_property_optional(dev, crtc_id, "GAMMA_LUT", blob_id)) { 1140bf6cc7dcSmrg uint16_t r[256], g[256], b[256]; 1141bf6cc7dcSmrg 1142bf6cc7dcSmrg for (i = 0; i < 256; i++) { 1143bf6cc7dcSmrg r[i] = gamma_lut[i].red; 1144bf6cc7dcSmrg g[i] = gamma_lut[i].green; 1145bf6cc7dcSmrg b[i] = gamma_lut[i].blue; 1146bf6cc7dcSmrg } 1147bf6cc7dcSmrg 1148bf6cc7dcSmrg ret = drmModeCrtcSetGamma(dev->fd, crtc_id, 256, r, g, b); 1149bf6cc7dcSmrg if (ret) 1150bf6cc7dcSmrg fprintf(stderr, "failed to set gamma: %s\n", strerror(errno)); 1151bf6cc7dcSmrg } 1152bf6cc7dcSmrg} 1153bf6cc7dcSmrg 115487bf8e7cSmrgstatic int 115587bf8e7cSmrgbo_fb_create(int fd, unsigned int fourcc, const uint32_t w, const uint32_t h, 115687bf8e7cSmrg enum util_fill_pattern pat, struct bo **out_bo, unsigned int *out_fb_id) 115787bf8e7cSmrg{ 115887bf8e7cSmrg uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0}; 115987bf8e7cSmrg struct bo *bo; 116087bf8e7cSmrg unsigned int fb_id; 116187bf8e7cSmrg 116287bf8e7cSmrg bo = bo_create(fd, fourcc, w, h, handles, pitches, offsets, pat); 116387bf8e7cSmrg 116487bf8e7cSmrg if (bo == NULL) 116587bf8e7cSmrg return -1; 116687bf8e7cSmrg 116787bf8e7cSmrg if (drmModeAddFB2(fd, w, h, fourcc, handles, pitches, offsets, &fb_id, 0)) { 116887bf8e7cSmrg fprintf(stderr, "failed to add fb (%ux%u): %s\n", w, h, strerror(errno)); 116987bf8e7cSmrg bo_destroy(bo); 117087bf8e7cSmrg return -1; 117187bf8e7cSmrg } 117287bf8e7cSmrg *out_bo = bo; 117387bf8e7cSmrg *out_fb_id = fb_id; 117487bf8e7cSmrg return 0; 117587bf8e7cSmrg} 117687bf8e7cSmrg 11776260e5d5Smrgstatic int atomic_set_plane(struct device *dev, struct plane_arg *p, 11786260e5d5Smrg int pattern, bool update) 11796260e5d5Smrg{ 11806260e5d5Smrg struct bo *plane_bo; 11816260e5d5Smrg int crtc_x, crtc_y, crtc_w, crtc_h; 11826260e5d5Smrg struct crtc *crtc = NULL; 11836260e5d5Smrg unsigned int old_fb_id; 11846260e5d5Smrg 11856260e5d5Smrg /* Find an unused plane which can be connected to our CRTC. Find the 11866260e5d5Smrg * CRTC index first, then iterate over available planes. 11876260e5d5Smrg */ 118887bf8e7cSmrg crtc = get_crtc_by_id(dev, p->crtc_id); 11896260e5d5Smrg if (!crtc) { 11906260e5d5Smrg fprintf(stderr, "CRTC %u not found\n", p->crtc_id); 11916260e5d5Smrg return -1; 11926260e5d5Smrg } 11936260e5d5Smrg 11946260e5d5Smrg if (!update) 11956260e5d5Smrg fprintf(stderr, "testing %dx%d@%s on plane %u, crtc %u\n", 11966260e5d5Smrg p->w, p->h, p->format_str, p->plane_id, p->crtc_id); 11976260e5d5Smrg 11986260e5d5Smrg plane_bo = p->old_bo; 11996260e5d5Smrg p->old_bo = p->bo; 12006260e5d5Smrg 12016260e5d5Smrg if (!plane_bo) { 120287bf8e7cSmrg if (bo_fb_create(dev->fd, p->fourcc, p->w, p->h, 120387bf8e7cSmrg pattern, &plane_bo, &p->fb_id)) 12046260e5d5Smrg return -1; 12056260e5d5Smrg } 12066260e5d5Smrg 12076260e5d5Smrg p->bo = plane_bo; 12086260e5d5Smrg 12096260e5d5Smrg old_fb_id = p->fb_id; 12106260e5d5Smrg p->old_fb_id = old_fb_id; 12116260e5d5Smrg 12126260e5d5Smrg crtc_w = p->w * p->scale; 12136260e5d5Smrg crtc_h = p->h * p->scale; 12146260e5d5Smrg if (!p->has_position) { 12156260e5d5Smrg /* Default to the middle of the screen */ 12166260e5d5Smrg crtc_x = (crtc->mode->hdisplay - crtc_w) / 2; 12176260e5d5Smrg crtc_y = (crtc->mode->vdisplay - crtc_h) / 2; 12186260e5d5Smrg } else { 12196260e5d5Smrg crtc_x = p->x; 12206260e5d5Smrg crtc_y = p->y; 12216260e5d5Smrg } 12226260e5d5Smrg 12236260e5d5Smrg add_property(dev, p->plane_id, "FB_ID", p->fb_id); 12246260e5d5Smrg add_property(dev, p->plane_id, "CRTC_ID", p->crtc_id); 12256260e5d5Smrg add_property(dev, p->plane_id, "SRC_X", 0); 12266260e5d5Smrg add_property(dev, p->plane_id, "SRC_Y", 0); 12276260e5d5Smrg add_property(dev, p->plane_id, "SRC_W", p->w << 16); 12286260e5d5Smrg add_property(dev, p->plane_id, "SRC_H", p->h << 16); 12296260e5d5Smrg add_property(dev, p->plane_id, "CRTC_X", crtc_x); 12306260e5d5Smrg add_property(dev, p->plane_id, "CRTC_Y", crtc_y); 12316260e5d5Smrg add_property(dev, p->plane_id, "CRTC_W", crtc_w); 12326260e5d5Smrg add_property(dev, p->plane_id, "CRTC_H", crtc_h); 12336260e5d5Smrg 12346260e5d5Smrg return 0; 12356260e5d5Smrg} 12366260e5d5Smrg 1237e88f27b3Smrgstatic int set_plane(struct device *dev, struct plane_arg *p) 123818210155Smrg{ 1239e88f27b3Smrg drmModePlane *ovr; 12402ee35494Smrg uint32_t plane_id; 1241e88f27b3Smrg int crtc_x, crtc_y, crtc_w, crtc_h; 1242e88f27b3Smrg struct crtc *crtc = NULL; 124387bf8e7cSmrg unsigned int i, crtc_mask; 1244e88f27b3Smrg 1245e88f27b3Smrg /* Find an unused plane which can be connected to our CRTC. Find the 1246e88f27b3Smrg * CRTC index first, then iterate over available planes. 1247e88f27b3Smrg */ 124887bf8e7cSmrg crtc = get_crtc_by_id(dev, p->crtc_id); 1249e88f27b3Smrg if (!crtc) { 1250e88f27b3Smrg fprintf(stderr, "CRTC %u not found\n", p->crtc_id); 1251e88f27b3Smrg return -1; 1252e88f27b3Smrg } 125387bf8e7cSmrg crtc_mask = get_crtc_mask(dev, crtc); 12542ee35494Smrg plane_id = p->plane_id; 12552ee35494Smrg 125687bf8e7cSmrg for (i = 0; i < dev->resources->count_planes; i++) { 1257e88f27b3Smrg ovr = dev->resources->planes[i].plane; 12582ee35494Smrg if (!ovr) 12592ee35494Smrg continue; 12602ee35494Smrg 12612ee35494Smrg if (plane_id && plane_id != ovr->plane_id) 12622ee35494Smrg continue; 12632ee35494Smrg 12642ee35494Smrg if (!format_support(ovr, p->fourcc)) 126518210155Smrg continue; 1266e88f27b3Smrg 126787bf8e7cSmrg if ((ovr->possible_crtcs & crtc_mask) && 12682b90624aSmrg (ovr->crtc_id == 0 || ovr->crtc_id == p->crtc_id)) { 1269e88f27b3Smrg plane_id = ovr->plane_id; 12702ee35494Smrg break; 12712ee35494Smrg } 127218210155Smrg } 127318210155Smrg 127487bf8e7cSmrg if (i == dev->resources->count_planes) { 1275e88f27b3Smrg fprintf(stderr, "no unused plane available for CRTC %u\n", 127687bf8e7cSmrg p->crtc_id); 1277e88f27b3Smrg return -1; 1278e88f27b3Smrg } 1279e88f27b3Smrg 1280e88f27b3Smrg fprintf(stderr, "testing %dx%d@%s overlay plane %u\n", 1281e88f27b3Smrg p->w, p->h, p->format_str, plane_id); 1282e88f27b3Smrg 1283e88f27b3Smrg /* just use single plane format for now.. */ 128487bf8e7cSmrg if (bo_fb_create(dev->fd, p->fourcc, p->w, p->h, 128587bf8e7cSmrg secondary_fill, &p->bo, &p->fb_id)) 1286e88f27b3Smrg return -1; 1287e88f27b3Smrg 1288e88f27b3Smrg crtc_w = p->w * p->scale; 1289e88f27b3Smrg crtc_h = p->h * p->scale; 1290e88f27b3Smrg if (!p->has_position) { 1291e88f27b3Smrg /* Default to the middle of the screen */ 1292e88f27b3Smrg crtc_x = (crtc->mode->hdisplay - crtc_w) / 2; 1293e88f27b3Smrg crtc_y = (crtc->mode->vdisplay - crtc_h) / 2; 1294e88f27b3Smrg } else { 1295e88f27b3Smrg crtc_x = p->x; 1296e88f27b3Smrg crtc_y = p->y; 129718210155Smrg } 129818210155Smrg 1299e88f27b3Smrg /* note src coords (last 4 args) are in Q16 format */ 130087bf8e7cSmrg if (drmModeSetPlane(dev->fd, plane_id, p->crtc_id, p->fb_id, 130187bf8e7cSmrg 0, crtc_x, crtc_y, crtc_w, crtc_h, 1302e88f27b3Smrg 0, 0, p->w << 16, p->h << 16)) { 1303e88f27b3Smrg fprintf(stderr, "failed to enable plane: %s\n", 1304e88f27b3Smrg strerror(errno)); 1305e88f27b3Smrg return -1; 1306e88f27b3Smrg } 1307e88f27b3Smrg 130887bf8e7cSmrg ovr->crtc_id = p->crtc_id; 1309e88f27b3Smrg 1310e88f27b3Smrg return 0; 1311e88f27b3Smrg} 1312e88f27b3Smrg 13136260e5d5Smrgstatic void atomic_set_planes(struct device *dev, struct plane_arg *p, 13146260e5d5Smrg unsigned int count, bool update) 13156260e5d5Smrg{ 1316bf6cc7dcSmrg unsigned int i, pattern = primary_fill; 13176260e5d5Smrg 13186260e5d5Smrg /* set up planes */ 13196260e5d5Smrg for (i = 0; i < count; i++) { 13206260e5d5Smrg if (i > 0) 1321bf6cc7dcSmrg pattern = secondary_fill; 1322bf6cc7dcSmrg else 1323bf6cc7dcSmrg set_gamma(dev, p[i].crtc_id, p[i].fourcc); 13246260e5d5Smrg 13256260e5d5Smrg if (atomic_set_plane(dev, &p[i], pattern, update)) 13266260e5d5Smrg return; 13276260e5d5Smrg } 13286260e5d5Smrg} 13296260e5d5Smrg 133087bf8e7cSmrgstatic void 133187bf8e7cSmrgatomic_test_page_flip(struct device *dev, struct pipe_arg *pipe_args, 133287bf8e7cSmrg struct plane_arg *plane_args, unsigned int plane_count) 133387bf8e7cSmrg{ 133487bf8e7cSmrg int ret; 133587bf8e7cSmrg 133687bf8e7cSmrg gettimeofday(&pipe_args->start, NULL); 133787bf8e7cSmrg pipe_args->swap_count = 0; 133887bf8e7cSmrg 133987bf8e7cSmrg while (true) { 134087bf8e7cSmrg drmModeAtomicFree(dev->req); 134187bf8e7cSmrg dev->req = drmModeAtomicAlloc(); 134287bf8e7cSmrg atomic_set_planes(dev, plane_args, plane_count, true); 134387bf8e7cSmrg 134487bf8e7cSmrg ret = drmModeAtomicCommit(dev->fd, dev->req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL); 134587bf8e7cSmrg if (ret) { 134687bf8e7cSmrg fprintf(stderr, "Atomic Commit failed [2]\n"); 134787bf8e7cSmrg return; 134887bf8e7cSmrg } 134987bf8e7cSmrg 135087bf8e7cSmrg pipe_args->swap_count++; 135187bf8e7cSmrg if (pipe_args->swap_count == 60) { 135287bf8e7cSmrg struct timeval end; 135387bf8e7cSmrg double t; 135487bf8e7cSmrg 135587bf8e7cSmrg gettimeofday(&end, NULL); 135687bf8e7cSmrg t = end.tv_sec + end.tv_usec * 1e-6 - 135787bf8e7cSmrg (pipe_args->start.tv_sec + pipe_args->start.tv_usec * 1e-6); 135887bf8e7cSmrg fprintf(stderr, "freq: %.02fHz\n", pipe_args->swap_count / t); 135987bf8e7cSmrg pipe_args->swap_count = 0; 136087bf8e7cSmrg pipe_args->start = end; 136187bf8e7cSmrg } 136287bf8e7cSmrg } 136387bf8e7cSmrg} 136487bf8e7cSmrg 13656260e5d5Smrgstatic void atomic_clear_planes(struct device *dev, struct plane_arg *p, unsigned int count) 13666260e5d5Smrg{ 13676260e5d5Smrg unsigned int i; 13686260e5d5Smrg 13696260e5d5Smrg for (i = 0; i < count; i++) { 13706260e5d5Smrg add_property(dev, p[i].plane_id, "FB_ID", 0); 13716260e5d5Smrg add_property(dev, p[i].plane_id, "CRTC_ID", 0); 13726260e5d5Smrg add_property(dev, p[i].plane_id, "SRC_X", 0); 13736260e5d5Smrg add_property(dev, p[i].plane_id, "SRC_Y", 0); 13746260e5d5Smrg add_property(dev, p[i].plane_id, "SRC_W", 0); 13756260e5d5Smrg add_property(dev, p[i].plane_id, "SRC_H", 0); 13766260e5d5Smrg add_property(dev, p[i].plane_id, "CRTC_X", 0); 13776260e5d5Smrg add_property(dev, p[i].plane_id, "CRTC_Y", 0); 13786260e5d5Smrg add_property(dev, p[i].plane_id, "CRTC_W", 0); 13796260e5d5Smrg add_property(dev, p[i].plane_id, "CRTC_H", 0); 13806260e5d5Smrg } 13816260e5d5Smrg} 13826260e5d5Smrg 13836260e5d5Smrgstatic void atomic_clear_FB(struct device *dev, struct plane_arg *p, unsigned int count) 13846260e5d5Smrg{ 13856260e5d5Smrg unsigned int i; 13866260e5d5Smrg 13876260e5d5Smrg for (i = 0; i < count; i++) { 13886260e5d5Smrg if (p[i].fb_id) { 13896260e5d5Smrg drmModeRmFB(dev->fd, p[i].fb_id); 13906260e5d5Smrg p[i].fb_id = 0; 13916260e5d5Smrg } 13926260e5d5Smrg if (p[i].old_fb_id) { 13936260e5d5Smrg drmModeRmFB(dev->fd, p[i].old_fb_id); 13946260e5d5Smrg p[i].old_fb_id = 0; 13956260e5d5Smrg } 13966260e5d5Smrg if (p[i].bo) { 13976260e5d5Smrg bo_destroy(p[i].bo); 13986260e5d5Smrg p[i].bo = NULL; 13996260e5d5Smrg } 14006260e5d5Smrg if (p[i].old_bo) { 14016260e5d5Smrg bo_destroy(p[i].old_bo); 14026260e5d5Smrg p[i].old_bo = NULL; 14036260e5d5Smrg } 14046260e5d5Smrg 14056260e5d5Smrg } 14066260e5d5Smrg} 14076260e5d5Smrg 1408424e9256Smrgstatic void clear_planes(struct device *dev, struct plane_arg *p, unsigned int count) 1409424e9256Smrg{ 1410424e9256Smrg unsigned int i; 1411424e9256Smrg 1412424e9256Smrg for (i = 0; i < count; i++) { 1413424e9256Smrg if (p[i].fb_id) 1414424e9256Smrg drmModeRmFB(dev->fd, p[i].fb_id); 1415424e9256Smrg if (p[i].bo) 1416424e9256Smrg bo_destroy(p[i].bo); 1417424e9256Smrg } 1418424e9256Smrg} 1419424e9256Smrg 142087bf8e7cSmrgstatic int pipe_resolve_connectors(struct device *dev, struct pipe_arg *pipe) 14216260e5d5Smrg{ 142287bf8e7cSmrg drmModeConnector *connector; 14236260e5d5Smrg unsigned int i; 142487bf8e7cSmrg uint32_t id; 142587bf8e7cSmrg char *endp; 14266260e5d5Smrg 142787bf8e7cSmrg for (i = 0; i < pipe->num_cons; i++) { 142887bf8e7cSmrg id = strtoul(pipe->cons[i], &endp, 10); 142987bf8e7cSmrg if (endp == pipe->cons[i]) { 143087bf8e7cSmrg connector = get_connector_by_name(dev, pipe->cons[i]); 143187bf8e7cSmrg if (!connector) { 143287bf8e7cSmrg fprintf(stderr, "no connector named '%s'\n", 143387bf8e7cSmrg pipe->cons[i]); 143487bf8e7cSmrg return -ENODEV; 143587bf8e7cSmrg } 14366260e5d5Smrg 143787bf8e7cSmrg id = connector->connector_id; 143887bf8e7cSmrg } 143987bf8e7cSmrg 144087bf8e7cSmrg pipe->con_ids[i] = id; 144187bf8e7cSmrg } 144287bf8e7cSmrg 144387bf8e7cSmrg return 0; 144487bf8e7cSmrg} 144587bf8e7cSmrg 144687bf8e7cSmrgstatic int pipe_attempt_connector(struct device *dev, drmModeConnector *con, 144787bf8e7cSmrg struct pipe_arg *pipe) 144887bf8e7cSmrg{ 144987bf8e7cSmrg char *con_str; 145087bf8e7cSmrg int i; 145187bf8e7cSmrg 145287bf8e7cSmrg con_str = calloc(8, sizeof(char)); 145387bf8e7cSmrg if (!con_str) 145487bf8e7cSmrg return -1; 145587bf8e7cSmrg 145687bf8e7cSmrg sprintf(con_str, "%d", con->connector_id); 145787bf8e7cSmrg strcpy(pipe->format_str, "XR24"); 145887bf8e7cSmrg pipe->fourcc = util_format_fourcc(pipe->format_str); 145987bf8e7cSmrg pipe->num_cons = 1; 146087bf8e7cSmrg pipe->con_ids = calloc(1, sizeof(*pipe->con_ids)); 146187bf8e7cSmrg pipe->cons = calloc(1, sizeof(*pipe->cons)); 146287bf8e7cSmrg 146387bf8e7cSmrg if (!pipe->con_ids || !pipe->cons) 146487bf8e7cSmrg goto free_con_str; 146587bf8e7cSmrg 146687bf8e7cSmrg pipe->con_ids[0] = con->connector_id; 146787bf8e7cSmrg pipe->cons[0] = (const char*)con_str; 146887bf8e7cSmrg 146987bf8e7cSmrg pipe->crtc = pipe_find_crtc(dev, pipe); 147087bf8e7cSmrg if (!pipe->crtc) 147187bf8e7cSmrg goto free_all; 147287bf8e7cSmrg 147387bf8e7cSmrg pipe->crtc_id = pipe->crtc->crtc->crtc_id; 147487bf8e7cSmrg 147587bf8e7cSmrg /* Return the first mode if no preferred. */ 147687bf8e7cSmrg pipe->mode = &con->modes[0]; 147787bf8e7cSmrg 147887bf8e7cSmrg for (i = 0; i < con->count_modes; i++) { 147987bf8e7cSmrg drmModeModeInfo *current_mode = &con->modes[i]; 148087bf8e7cSmrg 148187bf8e7cSmrg if (current_mode->type & DRM_MODE_TYPE_PREFERRED) { 148287bf8e7cSmrg pipe->mode = current_mode; 148387bf8e7cSmrg break; 148487bf8e7cSmrg } 148587bf8e7cSmrg } 148687bf8e7cSmrg 148787bf8e7cSmrg sprintf(pipe->mode_str, "%dx%d", pipe->mode->hdisplay, pipe->mode->vdisplay); 148887bf8e7cSmrg 148987bf8e7cSmrg return 0; 149087bf8e7cSmrg 149187bf8e7cSmrgfree_all: 149287bf8e7cSmrg free(pipe->cons); 149387bf8e7cSmrg free(pipe->con_ids); 149487bf8e7cSmrgfree_con_str: 149587bf8e7cSmrg free(con_str); 149687bf8e7cSmrg return -1; 149787bf8e7cSmrg} 149887bf8e7cSmrg 149987bf8e7cSmrgstatic int pipe_find_preferred(struct device *dev, struct pipe_arg **out_pipes) 150087bf8e7cSmrg{ 150187bf8e7cSmrg struct pipe_arg *pipes; 150287bf8e7cSmrg struct resources *res = dev->resources; 150387bf8e7cSmrg drmModeConnector *con = NULL; 150487bf8e7cSmrg int i, connected = 0, attempted = 0; 150587bf8e7cSmrg 150687bf8e7cSmrg for (i = 0; i < res->count_connectors; i++) { 150787bf8e7cSmrg con = res->connectors[i].connector; 150887bf8e7cSmrg if (!con || con->connection != DRM_MODE_CONNECTED) 15096260e5d5Smrg continue; 151087bf8e7cSmrg connected++; 151187bf8e7cSmrg } 151287bf8e7cSmrg if (!connected) { 151387bf8e7cSmrg printf("no connected connector!\n"); 151487bf8e7cSmrg return 0; 15156260e5d5Smrg } 15166260e5d5Smrg 151787bf8e7cSmrg pipes = calloc(connected, sizeof(struct pipe_arg)); 151887bf8e7cSmrg if (!pipes) 151987bf8e7cSmrg return 0; 15206260e5d5Smrg 152187bf8e7cSmrg for (i = 0; i < res->count_connectors && attempted < connected; i++) { 152287bf8e7cSmrg con = res->connectors[i].connector; 152387bf8e7cSmrg if (!con || con->connection != DRM_MODE_CONNECTED) 15246260e5d5Smrg continue; 15256260e5d5Smrg 152687bf8e7cSmrg if (pipe_attempt_connector(dev, con, &pipes[attempted]) < 0) { 152787bf8e7cSmrg printf("failed fetching preferred mode for connector\n"); 152887bf8e7cSmrg continue; 15296260e5d5Smrg } 153087bf8e7cSmrg attempted++; 15316260e5d5Smrg } 153287bf8e7cSmrg 153387bf8e7cSmrg *out_pipes = pipes; 153487bf8e7cSmrg return attempted; 15356260e5d5Smrg} 15366260e5d5Smrg 153787bf8e7cSmrgstatic struct plane *get_primary_plane_by_crtc(struct device *dev, struct crtc *crtc) 15386260e5d5Smrg{ 15396260e5d5Smrg unsigned int i; 15406260e5d5Smrg 154187bf8e7cSmrg for (i = 0; i < dev->resources->count_planes; i++) { 154287bf8e7cSmrg struct plane *plane = &dev->resources->planes[i]; 154387bf8e7cSmrg drmModePlane *ovr = plane->plane; 154487bf8e7cSmrg if (!ovr) 15456260e5d5Smrg continue; 15466260e5d5Smrg 154787bf8e7cSmrg // XXX: add is_primary_plane and (?) format checks 15486260e5d5Smrg 154987bf8e7cSmrg if (ovr->possible_crtcs & get_crtc_mask(dev, crtc)) 155087bf8e7cSmrg return plane; 15516260e5d5Smrg } 155287bf8e7cSmrg return NULL; 15536260e5d5Smrg} 1554424e9256Smrg 1555e88f27b3Smrgstatic void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count) 1556e88f27b3Smrg{ 155787bf8e7cSmrg unsigned int i, j; 155887bf8e7cSmrg int ret, x = 0; 155987bf8e7cSmrg int preferred = count == 0; 1560e88f27b3Smrg 1561e88f27b3Smrg for (i = 0; i < count; i++) { 1562e88f27b3Smrg struct pipe_arg *pipe = &pipes[i]; 1563e88f27b3Smrg 156487bf8e7cSmrg ret = pipe_resolve_connectors(dev, pipe); 156587bf8e7cSmrg if (ret < 0) 156687bf8e7cSmrg return; 156787bf8e7cSmrg 1568e88f27b3Smrg ret = pipe_find_crtc_and_mode(dev, pipe); 1569e88f27b3Smrg if (ret < 0) 1570e88f27b3Smrg continue; 157187bf8e7cSmrg } 157287bf8e7cSmrg if (preferred) { 157387bf8e7cSmrg struct pipe_arg *pipe_args; 1574e88f27b3Smrg 157587bf8e7cSmrg count = pipe_find_preferred(dev, &pipe_args); 157687bf8e7cSmrg if (!count) { 157787bf8e7cSmrg fprintf(stderr, "can't find any preferred connector/mode.\n"); 157887bf8e7cSmrg return; 157987bf8e7cSmrg } 158087bf8e7cSmrg pipes = pipe_args; 1581e88f27b3Smrg } 1582e88f27b3Smrg 158387bf8e7cSmrg if (!dev->use_atomic) { 158487bf8e7cSmrg for (i = 0; i < count; i++) { 158587bf8e7cSmrg struct pipe_arg *pipe = &pipes[i]; 158618210155Smrg 158787bf8e7cSmrg if (pipe->mode == NULL) 158887bf8e7cSmrg continue; 1589424e9256Smrg 159087bf8e7cSmrg if (!preferred) { 159187bf8e7cSmrg dev->mode.width += pipe->mode->hdisplay; 159287bf8e7cSmrg if (dev->mode.height < pipe->mode->vdisplay) 159387bf8e7cSmrg dev->mode.height = pipe->mode->vdisplay; 159487bf8e7cSmrg } else { 159587bf8e7cSmrg /* XXX: Use a clone mode, more like atomic. We could do per 159687bf8e7cSmrg * connector bo/fb, so we don't have the stretched image. 159787bf8e7cSmrg */ 159887bf8e7cSmrg if (dev->mode.width < pipe->mode->hdisplay) 159987bf8e7cSmrg dev->mode.width = pipe->mode->hdisplay; 160087bf8e7cSmrg if (dev->mode.height < pipe->mode->vdisplay) 160187bf8e7cSmrg dev->mode.height = pipe->mode->vdisplay; 160287bf8e7cSmrg } 160387bf8e7cSmrg } 160418210155Smrg 160587bf8e7cSmrg if (bo_fb_create(dev->fd, pipes[0].fourcc, dev->mode.width, dev->mode.height, 160687bf8e7cSmrg primary_fill, &dev->mode.bo, &dev->mode.fb_id)) 160787bf8e7cSmrg return; 160887bf8e7cSmrg } 1609424e9256Smrg 161018210155Smrg for (i = 0; i < count; i++) { 1611e88f27b3Smrg struct pipe_arg *pipe = &pipes[i]; 161287bf8e7cSmrg uint32_t blob_id; 1613e88f27b3Smrg 1614e88f27b3Smrg if (pipe->mode == NULL) 161518210155Smrg continue; 161618210155Smrg 161787bf8e7cSmrg printf("setting mode %s-%.2fHz on connectors ", 161887bf8e7cSmrg pipe->mode->name, mode_vrefresh(pipe->mode)); 161987bf8e7cSmrg for (j = 0; j < pipe->num_cons; ++j) { 1620fe517fc9Smrg printf("%s, ", pipe->cons[j]); 162187bf8e7cSmrg if (dev->use_atomic) 162287bf8e7cSmrg add_property(dev, pipe->con_ids[j], "CRTC_ID", pipe->crtc_id); 162387bf8e7cSmrg } 162487bf8e7cSmrg printf("crtc %d\n", pipe->crtc_id); 1625e88f27b3Smrg 162687bf8e7cSmrg if (!dev->use_atomic) { 162787bf8e7cSmrg ret = drmModeSetCrtc(dev->fd, pipe->crtc_id, dev->mode.fb_id, 162887bf8e7cSmrg x, 0, pipe->con_ids, pipe->num_cons, 162987bf8e7cSmrg pipe->mode); 1630e88f27b3Smrg 163187bf8e7cSmrg /* XXX: Actually check if this is needed */ 163287bf8e7cSmrg drmModeDirtyFB(dev->fd, dev->mode.fb_id, NULL, 0); 163318210155Smrg 163487bf8e7cSmrg if (!preferred) 163587bf8e7cSmrg x += pipe->mode->hdisplay; 163618210155Smrg 163787bf8e7cSmrg if (ret) { 163887bf8e7cSmrg fprintf(stderr, "failed to set mode: %s\n", strerror(errno)); 163987bf8e7cSmrg return; 164087bf8e7cSmrg } 164187bf8e7cSmrg 164287bf8e7cSmrg set_gamma(dev, pipe->crtc_id, pipe->fourcc); 164387bf8e7cSmrg } else { 164487bf8e7cSmrg drmModeCreatePropertyBlob(dev->fd, pipe->mode, sizeof(*pipe->mode), &blob_id); 164587bf8e7cSmrg add_property(dev, pipe->crtc_id, "MODE_ID", blob_id); 164687bf8e7cSmrg add_property(dev, pipe->crtc_id, "ACTIVE", 1); 164787bf8e7cSmrg 164887bf8e7cSmrg /* By default atomic modeset does not set a primary plane, shrug */ 164987bf8e7cSmrg if (preferred) { 165087bf8e7cSmrg struct plane *plane = get_primary_plane_by_crtc(dev, pipe->crtc); 165187bf8e7cSmrg struct plane_arg plane_args = { 165287bf8e7cSmrg .plane_id = plane->plane->plane_id, 165387bf8e7cSmrg .crtc_id = pipe->crtc_id, 165487bf8e7cSmrg .w = pipe->mode->hdisplay, 165587bf8e7cSmrg .h = pipe->mode->vdisplay, 165687bf8e7cSmrg .scale = 1.0, 165787bf8e7cSmrg .format_str = "XR24", 165887bf8e7cSmrg .fourcc = util_format_fourcc(pipe->format_str), 165987bf8e7cSmrg }; 166087bf8e7cSmrg 166187bf8e7cSmrg atomic_set_planes(dev, &plane_args, 1, false); 166287bf8e7cSmrg } 166318210155Smrg } 166487bf8e7cSmrg } 166587bf8e7cSmrg} 166687bf8e7cSmrg 166787bf8e7cSmrgstatic void atomic_clear_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count) 166887bf8e7cSmrg{ 166987bf8e7cSmrg unsigned int i; 167087bf8e7cSmrg unsigned int j; 167187bf8e7cSmrg 167287bf8e7cSmrg for (i = 0; i < count; i++) { 167387bf8e7cSmrg struct pipe_arg *pipe = &pipes[i]; 1674bf6cc7dcSmrg 167587bf8e7cSmrg if (pipe->mode == NULL) 167687bf8e7cSmrg continue; 167787bf8e7cSmrg 167887bf8e7cSmrg for (j = 0; j < pipe->num_cons; ++j) 167987bf8e7cSmrg add_property(dev, pipe->con_ids[j], "CRTC_ID",0); 168087bf8e7cSmrg 168187bf8e7cSmrg add_property(dev, pipe->crtc_id, "MODE_ID", 0); 168287bf8e7cSmrg add_property(dev, pipe->crtc_id, "ACTIVE", 0); 168318210155Smrg } 1684424e9256Smrg} 168522944501Smrg 1686424e9256Smrgstatic void clear_mode(struct device *dev) 1687424e9256Smrg{ 1688424e9256Smrg if (dev->mode.fb_id) 1689424e9256Smrg drmModeRmFB(dev->fd, dev->mode.fb_id); 1690424e9256Smrg if (dev->mode.bo) 1691424e9256Smrg bo_destroy(dev->mode.bo); 1692e88f27b3Smrg} 169322944501Smrg 1694e88f27b3Smrgstatic void set_planes(struct device *dev, struct plane_arg *p, unsigned int count) 1695e88f27b3Smrg{ 1696e88f27b3Smrg unsigned int i; 1697e88f27b3Smrg 1698e88f27b3Smrg /* set up planes/overlays */ 1699e88f27b3Smrg for (i = 0; i < count; i++) 1700e88f27b3Smrg if (set_plane(dev, &p[i])) 1701e88f27b3Smrg return; 1702e88f27b3Smrg} 1703e88f27b3Smrg 1704a7d7de1eSmrgstatic void set_cursors(struct device *dev, struct pipe_arg *pipes, unsigned int count) 1705a7d7de1eSmrg{ 1706424e9256Smrg uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0}; 1707adfa0b0cSmrg uint32_t cw = 64; 1708adfa0b0cSmrg uint32_t ch = 64; 17093c748557Ssnj struct bo *bo; 1710adfa0b0cSmrg uint64_t value; 1711a7d7de1eSmrg unsigned int i; 1712a7d7de1eSmrg int ret; 1713a7d7de1eSmrg 1714adfa0b0cSmrg ret = drmGetCap(dev->fd, DRM_CAP_CURSOR_WIDTH, &value); 1715adfa0b0cSmrg if (!ret) 1716adfa0b0cSmrg cw = value; 1717adfa0b0cSmrg 1718adfa0b0cSmrg ret = drmGetCap(dev->fd, DRM_CAP_CURSOR_HEIGHT, &value); 1719adfa0b0cSmrg if (!ret) 1720adfa0b0cSmrg ch = value; 1721adfa0b0cSmrg 1722a7d7de1eSmrg 1723a7d7de1eSmrg /* create cursor bo.. just using PATTERN_PLAIN as it has 1724a7d7de1eSmrg * translucent alpha 1725a7d7de1eSmrg */ 17263c748557Ssnj bo = bo_create(dev->fd, DRM_FORMAT_ARGB8888, cw, ch, handles, pitches, 1727fe517fc9Smrg offsets, UTIL_PATTERN_PLAIN); 1728a7d7de1eSmrg if (bo == NULL) 1729a7d7de1eSmrg return; 1730a7d7de1eSmrg 1731424e9256Smrg dev->mode.cursor_bo = bo; 1732424e9256Smrg 1733a7d7de1eSmrg for (i = 0; i < count; i++) { 1734a7d7de1eSmrg struct pipe_arg *pipe = &pipes[i]; 1735a7d7de1eSmrg ret = cursor_init(dev->fd, handles[0], 173687bf8e7cSmrg pipe->crtc_id, 1737a7d7de1eSmrg pipe->mode->hdisplay, pipe->mode->vdisplay, 1738a7d7de1eSmrg cw, ch); 1739a7d7de1eSmrg if (ret) { 1740a7d7de1eSmrg fprintf(stderr, "failed to init cursor for CRTC[%u]\n", 1741a7d7de1eSmrg pipe->crtc_id); 1742a7d7de1eSmrg return; 1743a7d7de1eSmrg } 1744a7d7de1eSmrg } 1745a7d7de1eSmrg 1746a7d7de1eSmrg cursor_start(); 1747a7d7de1eSmrg} 1748a7d7de1eSmrg 1749a7d7de1eSmrgstatic void clear_cursors(struct device *dev) 1750a7d7de1eSmrg{ 1751a7d7de1eSmrg cursor_stop(); 1752424e9256Smrg 1753424e9256Smrg if (dev->mode.cursor_bo) 1754424e9256Smrg bo_destroy(dev->mode.cursor_bo); 1755a7d7de1eSmrg} 1756a7d7de1eSmrg 1757e88f27b3Smrgstatic void test_page_flip(struct device *dev, struct pipe_arg *pipes, unsigned int count) 1758e88f27b3Smrg{ 1759e88f27b3Smrg unsigned int other_fb_id; 17603c748557Ssnj struct bo *other_bo; 1761e88f27b3Smrg drmEventContext evctx; 1762e88f27b3Smrg unsigned int i; 1763e88f27b3Smrg int ret; 1764e88f27b3Smrg 176587bf8e7cSmrg if (bo_fb_create(dev->fd, pipes[0].fourcc, dev->mode.width, dev->mode.height, 176687bf8e7cSmrg UTIL_PATTERN_PLAIN, &other_bo, &other_fb_id)) 176722944501Smrg return; 176822944501Smrg 176922944501Smrg for (i = 0; i < count; i++) { 1770e88f27b3Smrg struct pipe_arg *pipe = &pipes[i]; 1771e88f27b3Smrg 1772e88f27b3Smrg if (pipe->mode == NULL) 177322944501Smrg continue; 177422944501Smrg 177587bf8e7cSmrg ret = drmModePageFlip(dev->fd, pipe->crtc_id, 1776e88f27b3Smrg other_fb_id, DRM_MODE_PAGE_FLIP_EVENT, 1777e88f27b3Smrg pipe); 1778e88f27b3Smrg if (ret) { 1779e88f27b3Smrg fprintf(stderr, "failed to page flip: %s\n", strerror(errno)); 1780424e9256Smrg goto err_rmfb; 1781e88f27b3Smrg } 1782e88f27b3Smrg gettimeofday(&pipe->start, NULL); 1783e88f27b3Smrg pipe->swap_count = 0; 1784e88f27b3Smrg pipe->fb_id[0] = dev->mode.fb_id; 1785e88f27b3Smrg pipe->fb_id[1] = other_fb_id; 1786e88f27b3Smrg pipe->current_fb_id = other_fb_id; 178722944501Smrg } 178822944501Smrg 178922944501Smrg memset(&evctx, 0, sizeof evctx); 179022944501Smrg evctx.version = DRM_EVENT_CONTEXT_VERSION; 179122944501Smrg evctx.vblank_handler = NULL; 179222944501Smrg evctx.page_flip_handler = page_flip_handler; 1793fe517fc9Smrg 179422944501Smrg while (1) { 179522944501Smrg#if 0 179622944501Smrg struct pollfd pfd[2]; 179722944501Smrg 179822944501Smrg pfd[0].fd = 0; 179922944501Smrg pfd[0].events = POLLIN; 180022944501Smrg pfd[1].fd = fd; 180122944501Smrg pfd[1].events = POLLIN; 180222944501Smrg 180322944501Smrg if (poll(pfd, 2, -1) < 0) { 180422944501Smrg fprintf(stderr, "poll error\n"); 180522944501Smrg break; 180622944501Smrg } 180722944501Smrg 180822944501Smrg if (pfd[0].revents) 180922944501Smrg break; 181022944501Smrg#else 181122944501Smrg struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 }; 181222944501Smrg fd_set fds; 181322944501Smrg 181422944501Smrg FD_ZERO(&fds); 181522944501Smrg FD_SET(0, &fds); 1816e88f27b3Smrg FD_SET(dev->fd, &fds); 1817e88f27b3Smrg ret = select(dev->fd + 1, &fds, NULL, NULL, &timeout); 181822944501Smrg 181922944501Smrg if (ret <= 0) { 182022944501Smrg fprintf(stderr, "select timed out or error (ret %d)\n", 182122944501Smrg ret); 182222944501Smrg continue; 182322944501Smrg } else if (FD_ISSET(0, &fds)) { 182422944501Smrg break; 182522944501Smrg } 182622944501Smrg#endif 182722944501Smrg 1828e88f27b3Smrg drmHandleEvent(dev->fd, &evctx); 182922944501Smrg } 1830e88f27b3Smrg 1831424e9256Smrgerr_rmfb: 1832424e9256Smrg drmModeRmFB(dev->fd, other_fb_id); 18333c748557Ssnj bo_destroy(other_bo); 183418210155Smrg} 183518210155Smrg 1836e88f27b3Smrg#define min(a, b) ((a) < (b) ? (a) : (b)) 183718210155Smrg 1838e88f27b3Smrgstatic int parse_connector(struct pipe_arg *pipe, const char *arg) 183918210155Smrg{ 1840e88f27b3Smrg unsigned int len; 1841e88f27b3Smrg unsigned int i; 1842e88f27b3Smrg const char *p; 1843e88f27b3Smrg char *endp; 1844e88f27b3Smrg 1845e88f27b3Smrg pipe->vrefresh = 0; 1846e88f27b3Smrg pipe->crtc_id = (uint32_t)-1; 1847e88f27b3Smrg strcpy(pipe->format_str, "XR24"); 1848e88f27b3Smrg 1849e88f27b3Smrg /* Count the number of connectors and allocate them. */ 1850e88f27b3Smrg pipe->num_cons = 1; 1851fe517fc9Smrg for (p = arg; *p && *p != ':' && *p != '@'; ++p) { 1852e88f27b3Smrg if (*p == ',') 1853e88f27b3Smrg pipe->num_cons++; 1854e88f27b3Smrg } 1855e88f27b3Smrg 1856424e9256Smrg pipe->con_ids = calloc(pipe->num_cons, sizeof(*pipe->con_ids)); 1857fe517fc9Smrg pipe->cons = calloc(pipe->num_cons, sizeof(*pipe->cons)); 1858fe517fc9Smrg if (pipe->con_ids == NULL || pipe->cons == NULL) 1859e88f27b3Smrg return -1; 1860e88f27b3Smrg 1861e88f27b3Smrg /* Parse the connectors. */ 1862e88f27b3Smrg for (i = 0, p = arg; i < pipe->num_cons; ++i, p = endp + 1) { 1863fe517fc9Smrg endp = strpbrk(p, ",@:"); 1864fe517fc9Smrg if (!endp) 1865fe517fc9Smrg break; 1866fe517fc9Smrg 1867fe517fc9Smrg pipe->cons[i] = strndup(p, endp - p); 1868fe517fc9Smrg 1869e88f27b3Smrg if (*endp != ',') 1870e88f27b3Smrg break; 1871e88f27b3Smrg } 1872e88f27b3Smrg 1873e88f27b3Smrg if (i != pipe->num_cons - 1) 1874e88f27b3Smrg return -1; 1875e88f27b3Smrg 1876e88f27b3Smrg /* Parse the remaining parameters. */ 187787bf8e7cSmrg if (!endp) 187887bf8e7cSmrg return -1; 1879e88f27b3Smrg if (*endp == '@') { 1880e88f27b3Smrg arg = endp + 1; 1881e88f27b3Smrg pipe->crtc_id = strtoul(arg, &endp, 10); 1882e88f27b3Smrg } 1883e88f27b3Smrg if (*endp != ':') 1884e88f27b3Smrg return -1; 1885e88f27b3Smrg 1886e88f27b3Smrg arg = endp + 1; 1887e88f27b3Smrg 1888e88f27b3Smrg /* Search for the vertical refresh or the format. */ 1889e88f27b3Smrg p = strpbrk(arg, "-@"); 1890e88f27b3Smrg if (p == NULL) 1891e88f27b3Smrg p = arg + strlen(arg); 1892e88f27b3Smrg len = min(sizeof pipe->mode_str - 1, (unsigned int)(p - arg)); 1893e88f27b3Smrg strncpy(pipe->mode_str, arg, len); 1894e88f27b3Smrg pipe->mode_str[len] = '\0'; 1895e88f27b3Smrg 1896e88f27b3Smrg if (*p == '-') { 189787bf8e7cSmrg pipe->vrefresh = strtof(p + 1, &endp); 1898e88f27b3Smrg p = endp; 1899e88f27b3Smrg } 1900e88f27b3Smrg 1901e88f27b3Smrg if (*p == '@') { 1902e88f27b3Smrg strncpy(pipe->format_str, p + 1, 4); 1903e88f27b3Smrg pipe->format_str[4] = '\0'; 1904e88f27b3Smrg } 1905e88f27b3Smrg 1906fe517fc9Smrg pipe->fourcc = util_format_fourcc(pipe->format_str); 1907e88f27b3Smrg if (pipe->fourcc == 0) { 1908e88f27b3Smrg fprintf(stderr, "unknown format %s\n", pipe->format_str); 1909e88f27b3Smrg return -1; 1910e88f27b3Smrg } 1911e88f27b3Smrg 1912e88f27b3Smrg return 0; 1913e88f27b3Smrg} 1914e88f27b3Smrg 1915e88f27b3Smrgstatic int parse_plane(struct plane_arg *plane, const char *p) 1916e88f27b3Smrg{ 1917e88f27b3Smrg char *end; 1918e88f27b3Smrg 19192ee35494Smrg plane->plane_id = strtoul(p, &end, 10); 19202ee35494Smrg if (*end != '@') 19212ee35494Smrg return -EINVAL; 19222ee35494Smrg 19232ee35494Smrg p = end + 1; 1924e88f27b3Smrg plane->crtc_id = strtoul(p, &end, 10); 1925e88f27b3Smrg if (*end != ':') 1926e88f27b3Smrg return -EINVAL; 1927e88f27b3Smrg 1928e88f27b3Smrg p = end + 1; 1929e88f27b3Smrg plane->w = strtoul(p, &end, 10); 1930e88f27b3Smrg if (*end != 'x') 1931e88f27b3Smrg return -EINVAL; 1932e88f27b3Smrg 1933e88f27b3Smrg p = end + 1; 1934e88f27b3Smrg plane->h = strtoul(p, &end, 10); 1935e88f27b3Smrg 1936e88f27b3Smrg if (*end == '+' || *end == '-') { 1937e88f27b3Smrg plane->x = strtol(end, &end, 10); 1938e88f27b3Smrg if (*end != '+' && *end != '-') 1939e88f27b3Smrg return -EINVAL; 1940e88f27b3Smrg plane->y = strtol(end, &end, 10); 1941e88f27b3Smrg 1942e88f27b3Smrg plane->has_position = true; 1943e88f27b3Smrg } 1944e88f27b3Smrg 1945e88f27b3Smrg if (*end == '*') { 1946e88f27b3Smrg p = end + 1; 1947e88f27b3Smrg plane->scale = strtod(p, &end); 1948e88f27b3Smrg if (plane->scale <= 0.0) 1949e88f27b3Smrg return -EINVAL; 1950e88f27b3Smrg } else { 1951e88f27b3Smrg plane->scale = 1.0; 1952e88f27b3Smrg } 1953e88f27b3Smrg 1954e88f27b3Smrg if (*end == '@') { 1955bf6cc7dcSmrg strncpy(plane->format_str, end + 1, 4); 1956bf6cc7dcSmrg plane->format_str[4] = '\0'; 1957e88f27b3Smrg } else { 1958e88f27b3Smrg strcpy(plane->format_str, "XR24"); 1959e88f27b3Smrg } 1960e88f27b3Smrg 1961fe517fc9Smrg plane->fourcc = util_format_fourcc(plane->format_str); 1962e88f27b3Smrg if (plane->fourcc == 0) { 1963e88f27b3Smrg fprintf(stderr, "unknown format %s\n", plane->format_str); 1964e88f27b3Smrg return -EINVAL; 1965e88f27b3Smrg } 1966e88f27b3Smrg 1967e88f27b3Smrg return 0; 1968e88f27b3Smrg} 1969e88f27b3Smrg 1970e88f27b3Smrgstatic int parse_property(struct property_arg *p, const char *arg) 1971e88f27b3Smrg{ 1972e88f27b3Smrg if (sscanf(arg, "%d:%32[^:]:%" SCNu64, &p->obj_id, p->name, &p->value) != 3) 1973e88f27b3Smrg return -1; 1974e88f27b3Smrg 1975e88f27b3Smrg p->obj_type = 0; 1976e88f27b3Smrg p->name[DRM_PROP_NAME_LEN] = '\0'; 1977e88f27b3Smrg 1978e88f27b3Smrg return 0; 1979e88f27b3Smrg} 1980e88f27b3Smrg 1981bf6cc7dcSmrgstatic void parse_fill_patterns(char *arg) 1982bf6cc7dcSmrg{ 1983bf6cc7dcSmrg char *fill = strtok(arg, ","); 1984bf6cc7dcSmrg if (!fill) 1985bf6cc7dcSmrg return; 1986bf6cc7dcSmrg primary_fill = util_pattern_enum(fill); 1987bf6cc7dcSmrg fill = strtok(NULL, ","); 1988bf6cc7dcSmrg if (!fill) 1989bf6cc7dcSmrg return; 1990bf6cc7dcSmrg secondary_fill = util_pattern_enum(fill); 1991bf6cc7dcSmrg} 1992bf6cc7dcSmrg 1993e88f27b3Smrgstatic void usage(char *name) 1994e88f27b3Smrg{ 199587bf8e7cSmrg fprintf(stderr, "usage: %s [-acDdefMPpsCvrw]\n", name); 1996e88f27b3Smrg 1997e88f27b3Smrg fprintf(stderr, "\n Query options:\n\n"); 199818210155Smrg fprintf(stderr, "\t-c\tlist connectors\n"); 1999e88f27b3Smrg fprintf(stderr, "\t-e\tlist encoders\n"); 200018210155Smrg fprintf(stderr, "\t-f\tlist framebuffers\n"); 2001e88f27b3Smrg fprintf(stderr, "\t-p\tlist CRTCs and planes (pipes)\n"); 2002e88f27b3Smrg 2003e88f27b3Smrg fprintf(stderr, "\n Test options:\n\n"); 20042ee35494Smrg fprintf(stderr, "\t-P <plane_id>@<crtc_id>:<w>x<h>[+<x>+<y>][*<scale>][@<format>]\tset a plane\n"); 200587bf8e7cSmrg fprintf(stderr, "\t-s <connector_id>[,<connector_id>][@<crtc_id>]:[#<mode index>]<mode>[-<vrefresh>][@<format>]\tset a mode\n"); 2006a7d7de1eSmrg fprintf(stderr, "\t-C\ttest hw cursor\n"); 200722944501Smrg fprintf(stderr, "\t-v\ttest vsynced page flipping\n"); 200887bf8e7cSmrg fprintf(stderr, "\t-r\tset the preferred mode for all connectors\n"); 2009e88f27b3Smrg fprintf(stderr, "\t-w <obj_id>:<prop_name>:<value>\tset property\n"); 20106260e5d5Smrg fprintf(stderr, "\t-a \tuse atomic API\n"); 2011bf6cc7dcSmrg fprintf(stderr, "\t-F pattern1,pattern2\tspecify fill patterns\n"); 2012e88f27b3Smrg 2013e88f27b3Smrg fprintf(stderr, "\n Generic options:\n\n"); 2014e88f27b3Smrg fprintf(stderr, "\t-d\tdrop master after mode set\n"); 2015e88f27b3Smrg fprintf(stderr, "\t-M module\tuse the given driver\n"); 2016e88f27b3Smrg fprintf(stderr, "\t-D device\tuse the given device\n"); 2017e88f27b3Smrg 201818210155Smrg fprintf(stderr, "\n\tDefault is to dump all info.\n"); 201918210155Smrg exit(0); 202018210155Smrg} 202118210155Smrg 202287bf8e7cSmrgstatic char optstr[] = "acdD:efF:M:P:ps:Cvrw:"; 2023e88f27b3Smrg 202418210155Smrgint main(int argc, char **argv) 202518210155Smrg{ 2026e88f27b3Smrg struct device dev; 2027e88f27b3Smrg 202818210155Smrg int c; 2029e88f27b3Smrg int encoders = 0, connectors = 0, crtcs = 0, planes = 0, framebuffers = 0; 2030e88f27b3Smrg int drop_master = 0; 203122944501Smrg int test_vsync = 0; 2032a7d7de1eSmrg int test_cursor = 0; 203387bf8e7cSmrg int set_preferred = 0; 20346260e5d5Smrg int use_atomic = 0; 2035e88f27b3Smrg char *device = NULL; 2036e88f27b3Smrg char *module = NULL; 2037e88f27b3Smrg unsigned int i; 2038fe517fc9Smrg unsigned int count = 0, plane_count = 0; 2039e88f27b3Smrg unsigned int prop_count = 0; 2040e88f27b3Smrg struct pipe_arg *pipe_args = NULL; 2041e88f27b3Smrg struct plane_arg *plane_args = NULL; 2042e88f27b3Smrg struct property_arg *prop_args = NULL; 2043e88f27b3Smrg unsigned int args = 0; 2044e88f27b3Smrg int ret; 2045e88f27b3Smrg 2046e88f27b3Smrg memset(&dev, 0, sizeof dev); 2047e88f27b3Smrg 204818210155Smrg opterr = 0; 204918210155Smrg while ((c = getopt(argc, argv, optstr)) != -1) { 2050e88f27b3Smrg args++; 2051e88f27b3Smrg 205218210155Smrg switch (c) { 20536260e5d5Smrg case 'a': 20546260e5d5Smrg use_atomic = 1; 205587bf8e7cSmrg /* Preserve the default behaviour of dumping all information. */ 205687bf8e7cSmrg args--; 20576260e5d5Smrg break; 205818210155Smrg case 'c': 205918210155Smrg connectors = 1; 206018210155Smrg break; 2061e88f27b3Smrg case 'D': 2062e88f27b3Smrg device = optarg; 206387bf8e7cSmrg /* Preserve the default behaviour of dumping all information. */ 2064e88f27b3Smrg args--; 2065e88f27b3Smrg break; 2066e88f27b3Smrg case 'd': 2067e88f27b3Smrg drop_master = 1; 206818210155Smrg break; 2069e88f27b3Smrg case 'e': 2070e88f27b3Smrg encoders = 1; 207118210155Smrg break; 207218210155Smrg case 'f': 207318210155Smrg framebuffers = 1; 207418210155Smrg break; 2075bf6cc7dcSmrg case 'F': 2076bf6cc7dcSmrg parse_fill_patterns(optarg); 2077bf6cc7dcSmrg break; 2078e88f27b3Smrg case 'M': 2079e88f27b3Smrg module = optarg; 2080e88f27b3Smrg /* Preserve the default behaviour of dumping all information. */ 2081e88f27b3Smrg args--; 2082e88f27b3Smrg break; 2083e88f27b3Smrg case 'P': 2084e88f27b3Smrg plane_args = realloc(plane_args, 2085e88f27b3Smrg (plane_count + 1) * sizeof *plane_args); 2086e88f27b3Smrg if (plane_args == NULL) { 2087e88f27b3Smrg fprintf(stderr, "memory allocation failed\n"); 2088e88f27b3Smrg return 1; 2089e88f27b3Smrg } 2090424e9256Smrg memset(&plane_args[plane_count], 0, sizeof(*plane_args)); 2091e88f27b3Smrg 2092e88f27b3Smrg if (parse_plane(&plane_args[plane_count], optarg) < 0) 2093e88f27b3Smrg usage(argv[0]); 2094e88f27b3Smrg 2095e88f27b3Smrg plane_count++; 2096e88f27b3Smrg break; 2097e88f27b3Smrg case 'p': 2098e88f27b3Smrg crtcs = 1; 2099e88f27b3Smrg planes = 1; 210022944501Smrg break; 210118210155Smrg case 's': 2102e88f27b3Smrg pipe_args = realloc(pipe_args, 2103e88f27b3Smrg (count + 1) * sizeof *pipe_args); 2104e88f27b3Smrg if (pipe_args == NULL) { 2105e88f27b3Smrg fprintf(stderr, "memory allocation failed\n"); 2106e88f27b3Smrg return 1; 2107e88f27b3Smrg } 2108424e9256Smrg memset(&pipe_args[count], 0, sizeof(*pipe_args)); 2109e88f27b3Smrg 2110e88f27b3Smrg if (parse_connector(&pipe_args[count], optarg) < 0) 211118210155Smrg usage(argv[0]); 2112e88f27b3Smrg 2113fe517fc9Smrg count++; 211418210155Smrg break; 2115a7d7de1eSmrg case 'C': 2116a7d7de1eSmrg test_cursor = 1; 2117a7d7de1eSmrg break; 2118e88f27b3Smrg case 'v': 2119e88f27b3Smrg test_vsync = 1; 2120e88f27b3Smrg break; 212187bf8e7cSmrg case 'r': 212287bf8e7cSmrg set_preferred = 1; 212387bf8e7cSmrg break; 2124e88f27b3Smrg case 'w': 2125e88f27b3Smrg prop_args = realloc(prop_args, 2126e88f27b3Smrg (prop_count + 1) * sizeof *prop_args); 2127e88f27b3Smrg if (prop_args == NULL) { 2128e88f27b3Smrg fprintf(stderr, "memory allocation failed\n"); 2129e88f27b3Smrg return 1; 2130e88f27b3Smrg } 2131424e9256Smrg memset(&prop_args[prop_count], 0, sizeof(*prop_args)); 2132e88f27b3Smrg 2133e88f27b3Smrg if (parse_property(&prop_args[prop_count], optarg) < 0) 2134e88f27b3Smrg usage(argv[0]); 2135e88f27b3Smrg 2136e88f27b3Smrg prop_count++; 2137e88f27b3Smrg break; 213818210155Smrg default: 213918210155Smrg usage(argv[0]); 214018210155Smrg break; 214118210155Smrg } 214218210155Smrg } 214318210155Smrg 214487bf8e7cSmrg /* Dump all the details when no* arguments are provided. */ 214587bf8e7cSmrg if (!args) 2146e88f27b3Smrg encoders = connectors = crtcs = planes = framebuffers = 1; 214718210155Smrg 214887bf8e7cSmrg if (test_vsync && !count) { 214987bf8e7cSmrg fprintf(stderr, "page flipping requires at least one -s option.\n"); 21506260e5d5Smrg return -1; 21516260e5d5Smrg } 215287bf8e7cSmrg if (set_preferred && count) { 215387bf8e7cSmrg fprintf(stderr, "cannot use -r (preferred) when -s (mode) is set\n"); 215422944501Smrg return -1; 215522944501Smrg } 215622944501Smrg 215787bf8e7cSmrg if (set_preferred && plane_count) { 215887bf8e7cSmrg fprintf(stderr, "cannot use -r (preferred) when -P (plane) is set\n"); 215918210155Smrg return -1; 216018210155Smrg } 216118210155Smrg 216287bf8e7cSmrg dev.fd = util_open(device, module); 216387bf8e7cSmrg if (dev.fd < 0) 2164a7d7de1eSmrg return -1; 216587bf8e7cSmrg 216687bf8e7cSmrg if (use_atomic) { 216787bf8e7cSmrg ret = drmSetClientCap(dev.fd, DRM_CLIENT_CAP_ATOMIC, 1); 216887bf8e7cSmrg if (ret) { 216987bf8e7cSmrg fprintf(stderr, "no atomic modesetting support: %s\n", strerror(errno)); 217087bf8e7cSmrg drmClose(dev.fd); 217187bf8e7cSmrg return -1; 217287bf8e7cSmrg } 2173a7d7de1eSmrg } 2174a7d7de1eSmrg 217587bf8e7cSmrg dev.use_atomic = use_atomic; 217687bf8e7cSmrg 2177e88f27b3Smrg dev.resources = get_resources(&dev); 2178e88f27b3Smrg if (!dev.resources) { 2179e88f27b3Smrg drmClose(dev.fd); 218018210155Smrg return 1; 218118210155Smrg } 218218210155Smrg 2183e88f27b3Smrg#define dump_resource(dev, res) if (res) dump_##res(dev) 2184e88f27b3Smrg 2185e88f27b3Smrg dump_resource(&dev, encoders); 2186e88f27b3Smrg dump_resource(&dev, connectors); 2187e88f27b3Smrg dump_resource(&dev, crtcs); 2188e88f27b3Smrg dump_resource(&dev, planes); 2189e88f27b3Smrg dump_resource(&dev, framebuffers); 2190e88f27b3Smrg 2191e88f27b3Smrg for (i = 0; i < prop_count; ++i) 2192e88f27b3Smrg set_property(&dev, &prop_args[i]); 2193e88f27b3Smrg 21946260e5d5Smrg if (dev.use_atomic) { 21956260e5d5Smrg dev.req = drmModeAtomicAlloc(); 21963c748557Ssnj 219787bf8e7cSmrg if (set_preferred || (count && plane_count)) { 21986260e5d5Smrg uint64_t cap = 0; 21996260e5d5Smrg 22006260e5d5Smrg ret = drmGetCap(dev.fd, DRM_CAP_DUMB_BUFFER, &cap); 22016260e5d5Smrg if (ret || cap == 0) { 22026260e5d5Smrg fprintf(stderr, "driver doesn't support the dumb buffer API\n"); 22036260e5d5Smrg return 1; 22046260e5d5Smrg } 22056260e5d5Smrg 220687bf8e7cSmrg if (set_preferred || count) 220787bf8e7cSmrg set_mode(&dev, pipe_args, count); 220887bf8e7cSmrg 220987bf8e7cSmrg if (plane_count) 221087bf8e7cSmrg atomic_set_planes(&dev, plane_args, plane_count, false); 22116260e5d5Smrg 22126260e5d5Smrg ret = drmModeAtomicCommit(dev.fd, dev.req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL); 22136260e5d5Smrg if (ret) { 22146260e5d5Smrg fprintf(stderr, "Atomic Commit failed [1]\n"); 22156260e5d5Smrg return 1; 22166260e5d5Smrg } 22176260e5d5Smrg 221887bf8e7cSmrg if (test_vsync) 221987bf8e7cSmrg atomic_test_page_flip(&dev, pipe_args, plane_args, plane_count); 22206260e5d5Smrg 22216260e5d5Smrg if (drop_master) 22226260e5d5Smrg drmDropMaster(dev.fd); 22236260e5d5Smrg 22246260e5d5Smrg getchar(); 22256260e5d5Smrg 22266260e5d5Smrg drmModeAtomicFree(dev.req); 22276260e5d5Smrg dev.req = drmModeAtomicAlloc(); 22286260e5d5Smrg 222987bf8e7cSmrg /* XXX: properly teardown the preferred mode/plane state */ 223087bf8e7cSmrg if (plane_count) 223187bf8e7cSmrg atomic_clear_planes(&dev, plane_args, plane_count); 223287bf8e7cSmrg 223387bf8e7cSmrg if (count) 223487bf8e7cSmrg atomic_clear_mode(&dev, pipe_args, count); 223587bf8e7cSmrg 22366260e5d5Smrg ret = drmModeAtomicCommit(dev.fd, dev.req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL); 223787bf8e7cSmrg if (ret) 22386260e5d5Smrg fprintf(stderr, "Atomic Commit failed\n"); 22396260e5d5Smrg 224087bf8e7cSmrg if (plane_count) 224187bf8e7cSmrg atomic_clear_FB(&dev, plane_args, plane_count); 2242e88f27b3Smrg } 2243e88f27b3Smrg 22446260e5d5Smrg drmModeAtomicFree(dev.req); 22456260e5d5Smrg } else { 224687bf8e7cSmrg if (set_preferred || count || plane_count) { 22476260e5d5Smrg uint64_t cap = 0; 22486260e5d5Smrg 22496260e5d5Smrg ret = drmGetCap(dev.fd, DRM_CAP_DUMB_BUFFER, &cap); 22506260e5d5Smrg if (ret || cap == 0) { 22516260e5d5Smrg fprintf(stderr, "driver doesn't support the dumb buffer API\n"); 22526260e5d5Smrg return 1; 22536260e5d5Smrg } 22546260e5d5Smrg 225587bf8e7cSmrg if (set_preferred || count) 22566260e5d5Smrg set_mode(&dev, pipe_args, count); 2257e88f27b3Smrg 22586260e5d5Smrg if (plane_count) 22596260e5d5Smrg set_planes(&dev, plane_args, plane_count); 2260e88f27b3Smrg 22616260e5d5Smrg if (test_cursor) 22626260e5d5Smrg set_cursors(&dev, pipe_args, count); 2263a7d7de1eSmrg 22646260e5d5Smrg if (test_vsync) 22656260e5d5Smrg test_page_flip(&dev, pipe_args, count); 2266e88f27b3Smrg 22676260e5d5Smrg if (drop_master) 22686260e5d5Smrg drmDropMaster(dev.fd); 2269e88f27b3Smrg 22706260e5d5Smrg getchar(); 2271a7d7de1eSmrg 22726260e5d5Smrg if (test_cursor) 22736260e5d5Smrg clear_cursors(&dev); 2274a7d7de1eSmrg 22756260e5d5Smrg if (plane_count) 22766260e5d5Smrg clear_planes(&dev, plane_args, plane_count); 22776260e5d5Smrg 227887bf8e7cSmrg if (set_preferred || count) 22796260e5d5Smrg clear_mode(&dev); 22806260e5d5Smrg } 228118210155Smrg } 228218210155Smrg 2283e88f27b3Smrg free_resources(dev.resources); 228487bf8e7cSmrg drmClose(dev.fd); 228518210155Smrg 228618210155Smrg return 0; 228718210155Smrg} 2288