modetest.c revision 3b115362
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{ 1903b115362Smrg char *name = drmGetFormatName(fourcc); 1913b115362Smrg printf(" %s", name); 1923b115362Smrg free(name); 1930655efefSmrg} 1940655efefSmrg 195e88f27b3Smrgstatic void dump_encoders(struct device *dev) 19618210155Smrg{ 19718210155Smrg drmModeEncoder *encoder; 19818210155Smrg int i; 19918210155Smrg 20018210155Smrg printf("Encoders:\n"); 20118210155Smrg printf("id\tcrtc\ttype\tpossible crtcs\tpossible clones\t\n"); 20287bf8e7cSmrg for (i = 0; i < dev->resources->count_encoders; i++) { 203e88f27b3Smrg encoder = dev->resources->encoders[i].encoder; 204e88f27b3Smrg if (!encoder) 20518210155Smrg continue; 206e88f27b3Smrg 20718210155Smrg printf("%d\t%d\t%s\t0x%08x\t0x%08x\n", 20818210155Smrg encoder->encoder_id, 20918210155Smrg encoder->crtc_id, 210fe517fc9Smrg util_lookup_encoder_type_name(encoder->encoder_type), 21118210155Smrg encoder->possible_crtcs, 21218210155Smrg encoder->possible_clones); 21318210155Smrg } 21418210155Smrg printf("\n"); 21518210155Smrg} 21618210155Smrg 21787bf8e7cSmrgstatic void dump_mode(drmModeModeInfo *mode, int index) 21818210155Smrg{ 21987bf8e7cSmrg printf(" #%i %s %.2f %d %d %d %d %d %d %d %d %d", 22087bf8e7cSmrg index, 22118210155Smrg mode->name, 22287bf8e7cSmrg mode_vrefresh(mode), 22318210155Smrg mode->hdisplay, 22418210155Smrg mode->hsync_start, 22518210155Smrg mode->hsync_end, 22618210155Smrg mode->htotal, 22718210155Smrg mode->vdisplay, 22818210155Smrg mode->vsync_start, 22918210155Smrg mode->vsync_end, 2302ee35494Smrg mode->vtotal, 2312ee35494Smrg mode->clock); 232e88f27b3Smrg 233e88f27b3Smrg printf(" flags: "); 234e88f27b3Smrg mode_flag_str(mode->flags); 235e88f27b3Smrg printf("; type: "); 236e88f27b3Smrg mode_type_str(mode->type); 237e88f27b3Smrg printf("\n"); 23818210155Smrg} 23918210155Smrg 240e88f27b3Smrgstatic void dump_blob(struct device *dev, uint32_t blob_id) 241e88f27b3Smrg{ 242e88f27b3Smrg uint32_t i; 243e88f27b3Smrg unsigned char *blob_data; 244e88f27b3Smrg drmModePropertyBlobPtr blob; 245e88f27b3Smrg 246e88f27b3Smrg blob = drmModeGetPropertyBlob(dev->fd, blob_id); 2473c748557Ssnj if (!blob) { 2483c748557Ssnj printf("\n"); 249e88f27b3Smrg return; 2503c748557Ssnj } 251e88f27b3Smrg 252e88f27b3Smrg blob_data = blob->data; 253e88f27b3Smrg 254e88f27b3Smrg for (i = 0; i < blob->length; i++) { 255e88f27b3Smrg if (i % 16 == 0) 256e88f27b3Smrg printf("\n\t\t\t"); 257e88f27b3Smrg printf("%.2hhx", blob_data[i]); 258e88f27b3Smrg } 259e88f27b3Smrg printf("\n"); 260e88f27b3Smrg 261e88f27b3Smrg drmModeFreePropertyBlob(blob); 262e88f27b3Smrg} 263e88f27b3Smrg 2642b90624aSmrgstatic const char *modifier_to_string(uint64_t modifier) 2652b90624aSmrg{ 266636d5e9fSmrg static char mod_string[4096]; 267636d5e9fSmrg 268636d5e9fSmrg char *modifier_name = drmGetFormatModifierName(modifier); 269636d5e9fSmrg char *vendor_name = drmGetFormatModifierVendor(modifier); 270636d5e9fSmrg memset(mod_string, 0x00, sizeof(mod_string)); 271636d5e9fSmrg 272636d5e9fSmrg if (!modifier_name) { 273636d5e9fSmrg if (vendor_name) 274636d5e9fSmrg snprintf(mod_string, sizeof(mod_string), "%s_%s", 275636d5e9fSmrg vendor_name, "UNKNOWN_MODIFIER"); 276636d5e9fSmrg else 277636d5e9fSmrg snprintf(mod_string, sizeof(mod_string), "%s_%s", 278636d5e9fSmrg "UNKNOWN_VENDOR", "UNKNOWN_MODIFIER"); 279636d5e9fSmrg /* safe, as free is no-op for NULL */ 280636d5e9fSmrg free(vendor_name); 281636d5e9fSmrg return mod_string; 2822b90624aSmrg } 283636d5e9fSmrg 284636d5e9fSmrg if (modifier == DRM_FORMAT_MOD_LINEAR) { 285636d5e9fSmrg snprintf(mod_string, sizeof(mod_string), "%s", modifier_name); 286636d5e9fSmrg free(modifier_name); 287636d5e9fSmrg free(vendor_name); 288636d5e9fSmrg return mod_string; 289636d5e9fSmrg } 290636d5e9fSmrg 291636d5e9fSmrg snprintf(mod_string, sizeof(mod_string), "%s_%s", 292636d5e9fSmrg vendor_name, modifier_name); 293636d5e9fSmrg 294636d5e9fSmrg free(modifier_name); 295636d5e9fSmrg free(vendor_name); 296636d5e9fSmrg return mod_string; 2972b90624aSmrg} 2982b90624aSmrg 2992b90624aSmrgstatic void dump_in_formats(struct device *dev, uint32_t blob_id) 3002b90624aSmrg{ 301adfa0b0cSmrg drmModeFormatModifierIterator iter = {0}; 3022b90624aSmrg drmModePropertyBlobPtr blob; 303adfa0b0cSmrg uint32_t fmt = 0; 3042b90624aSmrg 3052b90624aSmrg printf("\t\tin_formats blob decoded:\n"); 3062b90624aSmrg blob = drmModeGetPropertyBlob(dev->fd, blob_id); 3072b90624aSmrg if (!blob) { 3082b90624aSmrg printf("\n"); 3092b90624aSmrg return; 3102b90624aSmrg } 3112b90624aSmrg 312adfa0b0cSmrg while (drmModeFormatModifierBlobIterNext(blob, &iter)) { 313adfa0b0cSmrg if (!fmt || fmt != iter.fmt) { 314adfa0b0cSmrg printf("%s\t\t\t", !fmt ? "" : "\n"); 315adfa0b0cSmrg fmt = iter.fmt; 316adfa0b0cSmrg dump_fourcc(fmt); 317adfa0b0cSmrg printf(": "); 3182b90624aSmrg } 319adfa0b0cSmrg 320adfa0b0cSmrg printf(" %s", modifier_to_string(iter.mod)); 3212b90624aSmrg } 3222b90624aSmrg 323adfa0b0cSmrg printf("\n"); 324adfa0b0cSmrg 3252b90624aSmrg drmModeFreePropertyBlob(blob); 3262b90624aSmrg} 3272b90624aSmrg 328e88f27b3Smrgstatic void dump_prop(struct device *dev, drmModePropertyPtr prop, 329e88f27b3Smrg uint32_t prop_id, uint64_t value) 33018210155Smrg{ 33118210155Smrg int i; 332e88f27b3Smrg printf("\t%d", prop_id); 333e88f27b3Smrg if (!prop) { 334e88f27b3Smrg printf("\n"); 335e88f27b3Smrg return; 336e88f27b3Smrg } 337e88f27b3Smrg 338e88f27b3Smrg printf(" %s:\n", prop->name); 339e88f27b3Smrg 340e88f27b3Smrg printf("\t\tflags:"); 341e88f27b3Smrg if (prop->flags & DRM_MODE_PROP_PENDING) 342e88f27b3Smrg printf(" pending"); 343e88f27b3Smrg if (prop->flags & DRM_MODE_PROP_IMMUTABLE) 344e88f27b3Smrg printf(" immutable"); 3453c748557Ssnj if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE)) 3463c748557Ssnj printf(" signed range"); 3473c748557Ssnj if (drm_property_type_is(prop, DRM_MODE_PROP_RANGE)) 3483c748557Ssnj printf(" range"); 3493c748557Ssnj if (drm_property_type_is(prop, DRM_MODE_PROP_ENUM)) 350e88f27b3Smrg printf(" enum"); 3513c748557Ssnj if (drm_property_type_is(prop, DRM_MODE_PROP_BITMASK)) 352e88f27b3Smrg printf(" bitmask"); 3533c748557Ssnj if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB)) 354e88f27b3Smrg printf(" blob"); 3553c748557Ssnj if (drm_property_type_is(prop, DRM_MODE_PROP_OBJECT)) 3563c748557Ssnj printf(" object"); 357e88f27b3Smrg printf("\n"); 358e88f27b3Smrg 3593c748557Ssnj if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE)) { 3603c748557Ssnj printf("\t\tvalues:"); 3613c748557Ssnj for (i = 0; i < prop->count_values; i++) 3623c748557Ssnj printf(" %"PRId64, U642I64(prop->values[i])); 3633c748557Ssnj printf("\n"); 3643c748557Ssnj } 3653c748557Ssnj 3663c748557Ssnj if (drm_property_type_is(prop, DRM_MODE_PROP_RANGE)) { 367e88f27b3Smrg printf("\t\tvalues:"); 368e88f27b3Smrg for (i = 0; i < prop->count_values; i++) 369e88f27b3Smrg printf(" %"PRIu64, prop->values[i]); 370e88f27b3Smrg printf("\n"); 371e88f27b3Smrg } 37218210155Smrg 3733c748557Ssnj if (drm_property_type_is(prop, DRM_MODE_PROP_ENUM)) { 374e88f27b3Smrg printf("\t\tenums:"); 375e88f27b3Smrg for (i = 0; i < prop->count_enums; i++) 376adfa0b0cSmrg printf(" %s=%"PRIu64, prop->enums[i].name, 37750027b5bSmrg (uint64_t)prop->enums[i].value); 378e88f27b3Smrg printf("\n"); 3793c748557Ssnj } else if (drm_property_type_is(prop, DRM_MODE_PROP_BITMASK)) { 380e88f27b3Smrg printf("\t\tvalues:"); 381e88f27b3Smrg for (i = 0; i < prop->count_enums; i++) 382e88f27b3Smrg printf(" %s=0x%llx", prop->enums[i].name, 383e88f27b3Smrg (1LL << prop->enums[i].value)); 384e88f27b3Smrg printf("\n"); 385e88f27b3Smrg } else { 386e88f27b3Smrg assert(prop->count_enums == 0); 387e88f27b3Smrg } 388e88f27b3Smrg 3893c748557Ssnj if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB)) { 390e88f27b3Smrg printf("\t\tblobs:\n"); 391e88f27b3Smrg for (i = 0; i < prop->count_blobs; i++) 392e88f27b3Smrg dump_blob(dev, prop->blob_ids[i]); 393e88f27b3Smrg printf("\n"); 394e88f27b3Smrg } else { 395e88f27b3Smrg assert(prop->count_blobs == 0); 39618210155Smrg } 397e88f27b3Smrg 398e88f27b3Smrg printf("\t\tvalue:"); 3993c748557Ssnj if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB)) 400e88f27b3Smrg dump_blob(dev, value); 401fe517fc9Smrg else if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE)) 402fe517fc9Smrg printf(" %"PRId64"\n", value); 403e88f27b3Smrg else 404e88f27b3Smrg printf(" %"PRIu64"\n", value); 4052b90624aSmrg 4062b90624aSmrg if (strcmp(prop->name, "IN_FORMATS") == 0) 4072b90624aSmrg dump_in_formats(dev, value); 40818210155Smrg} 40918210155Smrg 410e88f27b3Smrgstatic void dump_connectors(struct device *dev) 41118210155Smrg{ 41218210155Smrg int i, j; 41318210155Smrg 41418210155Smrg printf("Connectors:\n"); 415fe517fc9Smrg printf("id\tencoder\tstatus\t\tname\t\tsize (mm)\tmodes\tencoders\n"); 41687bf8e7cSmrg for (i = 0; i < dev->resources->count_connectors; i++) { 417e88f27b3Smrg struct connector *_connector = &dev->resources->connectors[i]; 418e88f27b3Smrg drmModeConnector *connector = _connector->connector; 419e88f27b3Smrg if (!connector) 42018210155Smrg continue; 42118210155Smrg 422fe517fc9Smrg printf("%d\t%d\t%s\t%-15s\t%dx%d\t\t%d\t", 42318210155Smrg connector->connector_id, 42418210155Smrg connector->encoder_id, 425fe517fc9Smrg util_lookup_connector_status_name(connector->connection), 426fe517fc9Smrg _connector->name, 42718210155Smrg connector->mmWidth, connector->mmHeight, 42818210155Smrg connector->count_modes); 42918210155Smrg 43022944501Smrg for (j = 0; j < connector->count_encoders; j++) 43122944501Smrg printf("%s%d", j > 0 ? ", " : "", connector->encoders[j]); 43222944501Smrg printf("\n"); 43322944501Smrg 434e88f27b3Smrg if (connector->count_modes) { 435e88f27b3Smrg printf(" modes:\n"); 43687bf8e7cSmrg printf("\tindex name refresh (Hz) hdisp hss hse htot vdisp " 4374b3d3f37Smrg "vss vse vtot\n"); 438e88f27b3Smrg for (j = 0; j < connector->count_modes; j++) 43987bf8e7cSmrg dump_mode(&connector->modes[j], j); 440e88f27b3Smrg } 44122944501Smrg 442e88f27b3Smrg if (_connector->props) { 443e88f27b3Smrg printf(" props:\n"); 444e88f27b3Smrg for (j = 0; j < (int)_connector->props->count_props; j++) 445e88f27b3Smrg dump_prop(dev, _connector->props_info[j], 446e88f27b3Smrg _connector->props->props[j], 447e88f27b3Smrg _connector->props->prop_values[j]); 448e88f27b3Smrg } 44918210155Smrg } 45018210155Smrg printf("\n"); 45118210155Smrg} 45218210155Smrg 453e88f27b3Smrgstatic void dump_crtcs(struct device *dev) 45418210155Smrg{ 45518210155Smrg int i; 456e88f27b3Smrg uint32_t j; 45718210155Smrg 45818210155Smrg printf("CRTCs:\n"); 45918210155Smrg printf("id\tfb\tpos\tsize\n"); 46087bf8e7cSmrg for (i = 0; i < dev->resources->count_crtcs; i++) { 461e88f27b3Smrg struct crtc *_crtc = &dev->resources->crtcs[i]; 462e88f27b3Smrg drmModeCrtc *crtc = _crtc->crtc; 463e88f27b3Smrg if (!crtc) 46418210155Smrg continue; 465e88f27b3Smrg 46618210155Smrg printf("%d\t%d\t(%d,%d)\t(%dx%d)\n", 46718210155Smrg crtc->crtc_id, 46818210155Smrg crtc->buffer_id, 46918210155Smrg crtc->x, crtc->y, 47018210155Smrg crtc->width, crtc->height); 47187bf8e7cSmrg dump_mode(&crtc->mode, 0); 47218210155Smrg 473e88f27b3Smrg if (_crtc->props) { 474e88f27b3Smrg printf(" props:\n"); 475e88f27b3Smrg for (j = 0; j < _crtc->props->count_props; j++) 476e88f27b3Smrg dump_prop(dev, _crtc->props_info[j], 477e88f27b3Smrg _crtc->props->props[j], 478e88f27b3Smrg _crtc->props->prop_values[j]); 479e88f27b3Smrg } else { 480e88f27b3Smrg printf(" no properties found\n"); 481e88f27b3Smrg } 48218210155Smrg } 48318210155Smrg printf("\n"); 48418210155Smrg} 48518210155Smrg 486e88f27b3Smrgstatic void dump_framebuffers(struct device *dev) 48718210155Smrg{ 48818210155Smrg drmModeFB *fb; 48918210155Smrg int i; 49018210155Smrg 49118210155Smrg printf("Frame buffers:\n"); 49218210155Smrg printf("id\tsize\tpitch\n"); 49387bf8e7cSmrg for (i = 0; i < dev->resources->count_fbs; i++) { 494e88f27b3Smrg fb = dev->resources->fbs[i].fb; 495e88f27b3Smrg if (!fb) 49618210155Smrg continue; 497e88f27b3Smrg 49822944501Smrg printf("%u\t(%ux%u)\t%u\n", 49918210155Smrg fb->fb_id, 50022944501Smrg fb->width, fb->height, 50122944501Smrg fb->pitch); 50218210155Smrg } 50318210155Smrg printf("\n"); 50418210155Smrg} 50518210155Smrg 506e88f27b3Smrgstatic void dump_planes(struct device *dev) 50718210155Smrg{ 508e88f27b3Smrg unsigned int i, j; 50918210155Smrg 510e88f27b3Smrg printf("Planes:\n"); 511e88f27b3Smrg printf("id\tcrtc\tfb\tCRTC x,y\tx,y\tgamma size\tpossible crtcs\n"); 51218210155Smrg 51387bf8e7cSmrg for (i = 0; i < dev->resources->count_planes; i++) { 514e88f27b3Smrg struct plane *plane = &dev->resources->planes[i]; 515e88f27b3Smrg drmModePlane *ovr = plane->plane; 516e88f27b3Smrg if (!ovr) 51718210155Smrg continue; 51818210155Smrg 519e88f27b3Smrg printf("%d\t%d\t%d\t%d,%d\t\t%d,%d\t%-8d\t0x%08x\n", 520e88f27b3Smrg ovr->plane_id, ovr->crtc_id, ovr->fb_id, 521e88f27b3Smrg ovr->crtc_x, ovr->crtc_y, ovr->x, ovr->y, 522e88f27b3Smrg ovr->gamma_size, ovr->possible_crtcs); 523e88f27b3Smrg 524e88f27b3Smrg if (!ovr->count_formats) 52518210155Smrg continue; 52618210155Smrg 527e88f27b3Smrg printf(" formats:"); 528e88f27b3Smrg for (j = 0; j < ovr->count_formats; j++) 5290655efefSmrg dump_fourcc(ovr->formats[j]); 530e88f27b3Smrg printf("\n"); 531e88f27b3Smrg 532e88f27b3Smrg if (plane->props) { 533e88f27b3Smrg printf(" props:\n"); 534e88f27b3Smrg for (j = 0; j < plane->props->count_props; j++) 535e88f27b3Smrg dump_prop(dev, plane->props_info[j], 536e88f27b3Smrg plane->props->props[j], 537e88f27b3Smrg plane->props->prop_values[j]); 538e88f27b3Smrg } else { 539e88f27b3Smrg printf(" no properties found\n"); 54018210155Smrg } 541e88f27b3Smrg } 542e88f27b3Smrg printf("\n"); 54318210155Smrg 544e88f27b3Smrg return; 545e88f27b3Smrg} 546e88f27b3Smrg 547e88f27b3Smrgstatic void free_resources(struct resources *res) 548e88f27b3Smrg{ 549fe517fc9Smrg int i; 550fe517fc9Smrg 551e88f27b3Smrg if (!res) 552e88f27b3Smrg return; 55318210155Smrg 55487bf8e7cSmrg#define free_resource(_res, type, Type) \ 555e88f27b3Smrg do { \ 556e88f27b3Smrg if (!(_res)->type##s) \ 557e88f27b3Smrg break; \ 55887bf8e7cSmrg for (i = 0; i < (int)(_res)->count_##type##s; ++i) { \ 559e88f27b3Smrg if (!(_res)->type##s[i].type) \ 560e88f27b3Smrg break; \ 561e88f27b3Smrg drmModeFree##Type((_res)->type##s[i].type); \ 562e88f27b3Smrg } \ 563e88f27b3Smrg free((_res)->type##s); \ 564e88f27b3Smrg } while (0) 565e88f27b3Smrg 56687bf8e7cSmrg#define free_properties(_res, type) \ 567e88f27b3Smrg do { \ 56887bf8e7cSmrg for (i = 0; i < (int)(_res)->count_##type##s; ++i) { \ 56987bf8e7cSmrg unsigned int j; \ 57087bf8e7cSmrg for (j = 0; j < res->type##s[i].props->count_props; ++j)\ 57187bf8e7cSmrg drmModeFreeProperty(res->type##s[i].props_info[j]);\ 572e88f27b3Smrg free(res->type##s[i].props_info); \ 57387bf8e7cSmrg drmModeFreeObjectProperties(res->type##s[i].props); \ 574e88f27b3Smrg } \ 575e88f27b3Smrg } while (0) 576e88f27b3Smrg 57787bf8e7cSmrg free_properties(res, plane); 57887bf8e7cSmrg free_resource(res, plane, Plane); 579fe517fc9Smrg 58087bf8e7cSmrg free_properties(res, connector); 58187bf8e7cSmrg free_properties(res, crtc); 582fe517fc9Smrg 58387bf8e7cSmrg for (i = 0; i < res->count_connectors; i++) 58487bf8e7cSmrg free(res->connectors[i].name); 585e88f27b3Smrg 58687bf8e7cSmrg free_resource(res, fb, FB); 58787bf8e7cSmrg free_resource(res, connector, Connector); 58887bf8e7cSmrg free_resource(res, encoder, Encoder); 58987bf8e7cSmrg free_resource(res, crtc, Crtc); 59018210155Smrg 591e88f27b3Smrg free(res); 592e88f27b3Smrg} 59318210155Smrg 594e88f27b3Smrgstatic struct resources *get_resources(struct device *dev) 595e88f27b3Smrg{ 59687bf8e7cSmrg drmModeRes *_res; 59787bf8e7cSmrg drmModePlaneRes *plane_res; 598e88f27b3Smrg struct resources *res; 599e88f27b3Smrg int i; 60018210155Smrg 601424e9256Smrg res = calloc(1, sizeof(*res)); 602e88f27b3Smrg if (res == 0) 603e88f27b3Smrg return NULL; 604e88f27b3Smrg 605424e9256Smrg drmSetClientCap(dev->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); 606e88f27b3Smrg 60787bf8e7cSmrg _res = drmModeGetResources(dev->fd); 60887bf8e7cSmrg if (!_res) { 609e88f27b3Smrg fprintf(stderr, "drmModeGetResources failed: %s\n", 610e88f27b3Smrg strerror(errno)); 61187bf8e7cSmrg free(res); 61287bf8e7cSmrg return NULL; 613e88f27b3Smrg } 61418210155Smrg 61587bf8e7cSmrg res->count_crtcs = _res->count_crtcs; 61687bf8e7cSmrg res->count_encoders = _res->count_encoders; 61787bf8e7cSmrg res->count_connectors = _res->count_connectors; 61887bf8e7cSmrg res->count_fbs = _res->count_fbs; 619e88f27b3Smrg 62087bf8e7cSmrg res->crtcs = calloc(res->count_crtcs, sizeof(*res->crtcs)); 62187bf8e7cSmrg res->encoders = calloc(res->count_encoders, sizeof(*res->encoders)); 62287bf8e7cSmrg res->connectors = calloc(res->count_connectors, sizeof(*res->connectors)); 62387bf8e7cSmrg res->fbs = calloc(res->count_fbs, sizeof(*res->fbs)); 62487bf8e7cSmrg 62587bf8e7cSmrg if (!res->crtcs || !res->encoders || !res->connectors || !res->fbs) { 62687bf8e7cSmrg drmModeFreeResources(_res); 627e88f27b3Smrg goto error; 62887bf8e7cSmrg } 629e88f27b3Smrg 630e88f27b3Smrg#define get_resource(_res, __res, type, Type) \ 631e88f27b3Smrg do { \ 63287bf8e7cSmrg for (i = 0; i < (int)(_res)->count_##type##s; ++i) { \ 63387bf8e7cSmrg uint32_t type##id = (__res)->type##s[i]; \ 63487bf8e7cSmrg (_res)->type##s[i].type = \ 63587bf8e7cSmrg drmModeGet##Type(dev->fd, type##id); \ 63687bf8e7cSmrg if (!(_res)->type##s[i].type) \ 637e88f27b3Smrg fprintf(stderr, "could not get %s %i: %s\n", \ 63887bf8e7cSmrg #type, type##id, \ 639e88f27b3Smrg strerror(errno)); \ 640e88f27b3Smrg } \ 641e88f27b3Smrg } while (0) 642e88f27b3Smrg 64387bf8e7cSmrg get_resource(res, _res, crtc, Crtc); 64487bf8e7cSmrg get_resource(res, _res, encoder, Encoder); 64587bf8e7cSmrg get_resource(res, _res, connector, Connector); 64687bf8e7cSmrg get_resource(res, _res, fb, FB); 64787bf8e7cSmrg 64887bf8e7cSmrg drmModeFreeResources(_res); 649e88f27b3Smrg 650fe517fc9Smrg /* Set the name of all connectors based on the type name and the per-type ID. */ 65187bf8e7cSmrg for (i = 0; i < res->count_connectors; i++) { 652fe517fc9Smrg struct connector *connector = &res->connectors[i]; 653fe517fc9Smrg drmModeConnector *conn = connector->connector; 6542b90624aSmrg int num; 655fe517fc9Smrg 6562b90624aSmrg num = asprintf(&connector->name, "%s-%u", 65750027b5bSmrg drmModeGetConnectorTypeName(conn->connector_type), 658fe517fc9Smrg conn->connector_type_id); 6592b90624aSmrg if (num < 0) 6602b90624aSmrg goto error; 661fe517fc9Smrg } 662fe517fc9Smrg 66387bf8e7cSmrg#define get_properties(_res, type, Type) \ 664e88f27b3Smrg do { \ 66587bf8e7cSmrg for (i = 0; i < (int)(_res)->count_##type##s; ++i) { \ 666e88f27b3Smrg struct type *obj = &res->type##s[i]; \ 667e88f27b3Smrg unsigned int j; \ 668e88f27b3Smrg obj->props = \ 669e88f27b3Smrg drmModeObjectGetProperties(dev->fd, obj->type->type##_id, \ 670e88f27b3Smrg DRM_MODE_OBJECT_##Type); \ 671e88f27b3Smrg if (!obj->props) { \ 672e88f27b3Smrg fprintf(stderr, \ 673e88f27b3Smrg "could not get %s %i properties: %s\n", \ 674e88f27b3Smrg #type, obj->type->type##_id, \ 675e88f27b3Smrg strerror(errno)); \ 676e88f27b3Smrg continue; \ 677e88f27b3Smrg } \ 678424e9256Smrg obj->props_info = calloc(obj->props->count_props, \ 679424e9256Smrg sizeof(*obj->props_info)); \ 680e88f27b3Smrg if (!obj->props_info) \ 681e88f27b3Smrg continue; \ 682e88f27b3Smrg for (j = 0; j < obj->props->count_props; ++j) \ 683e88f27b3Smrg obj->props_info[j] = \ 684e88f27b3Smrg drmModeGetProperty(dev->fd, obj->props->props[j]); \ 685e88f27b3Smrg } \ 686e88f27b3Smrg } while (0) 687e88f27b3Smrg 68887bf8e7cSmrg get_properties(res, crtc, CRTC); 68987bf8e7cSmrg get_properties(res, connector, CONNECTOR); 690e88f27b3Smrg 69187bf8e7cSmrg for (i = 0; i < res->count_crtcs; ++i) 692e88f27b3Smrg res->crtcs[i].mode = &res->crtcs[i].crtc->mode; 693e88f27b3Smrg 69487bf8e7cSmrg plane_res = drmModeGetPlaneResources(dev->fd); 69587bf8e7cSmrg if (!plane_res) { 696e88f27b3Smrg fprintf(stderr, "drmModeGetPlaneResources failed: %s\n", 697e88f27b3Smrg strerror(errno)); 698e88f27b3Smrg return res; 69918210155Smrg } 70018210155Smrg 70187bf8e7cSmrg res->count_planes = plane_res->count_planes; 70287bf8e7cSmrg 70387bf8e7cSmrg res->planes = calloc(res->count_planes, sizeof(*res->planes)); 70487bf8e7cSmrg if (!res->planes) { 70587bf8e7cSmrg drmModeFreePlaneResources(plane_res); 706e88f27b3Smrg goto error; 70787bf8e7cSmrg } 708e88f27b3Smrg 709e88f27b3Smrg get_resource(res, plane_res, plane, Plane); 71087bf8e7cSmrg drmModeFreePlaneResources(plane_res); 71187bf8e7cSmrg get_properties(res, plane, PLANE); 712e88f27b3Smrg 713e88f27b3Smrg return res; 714e88f27b3Smrg 715e88f27b3Smrgerror: 716e88f27b3Smrg free_resources(res); 717e88f27b3Smrg return NULL; 71818210155Smrg} 71918210155Smrg 72087bf8e7cSmrgstatic struct crtc *get_crtc_by_id(struct device *dev, uint32_t id) 721d049871aSmrg{ 722e88f27b3Smrg int i; 72318210155Smrg 72487bf8e7cSmrg for (i = 0; i < dev->resources->count_crtcs; ++i) { 725e88f27b3Smrg drmModeCrtc *crtc = dev->resources->crtcs[i].crtc; 726e88f27b3Smrg if (crtc && crtc->crtc_id == id) 72787bf8e7cSmrg return &dev->resources->crtcs[i]; 728e88f27b3Smrg } 729d049871aSmrg 73087bf8e7cSmrg return NULL; 73187bf8e7cSmrg} 73287bf8e7cSmrg 73387bf8e7cSmrgstatic uint32_t get_crtc_mask(struct device *dev, struct crtc *crtc) 73487bf8e7cSmrg{ 73587bf8e7cSmrg unsigned int i; 73687bf8e7cSmrg 73787bf8e7cSmrg for (i = 0; i < (unsigned int)dev->resources->count_crtcs; i++) { 73887bf8e7cSmrg if (crtc->crtc->crtc_id == dev->resources->crtcs[i].crtc->crtc_id) 73987bf8e7cSmrg return 1 << i; 74087bf8e7cSmrg } 74187bf8e7cSmrg /* Unreachable: crtc->crtc is one of resources->crtcs[] */ 74287bf8e7cSmrg /* Don't return zero or static analysers will complain */ 74387bf8e7cSmrg abort(); 74487bf8e7cSmrg return 0; 745d049871aSmrg} 746d049871aSmrg 747fe517fc9Smrgstatic drmModeConnector *get_connector_by_name(struct device *dev, const char *name) 748fe517fc9Smrg{ 749fe517fc9Smrg struct connector *connector; 750fe517fc9Smrg int i; 751fe517fc9Smrg 75287bf8e7cSmrg for (i = 0; i < dev->resources->count_connectors; i++) { 753fe517fc9Smrg connector = &dev->resources->connectors[i]; 754fe517fc9Smrg 755fe517fc9Smrg if (strcmp(connector->name, name) == 0) 756fe517fc9Smrg return connector->connector; 757fe517fc9Smrg } 758fe517fc9Smrg 759fe517fc9Smrg return NULL; 760fe517fc9Smrg} 761fe517fc9Smrg 762e88f27b3Smrgstatic drmModeConnector *get_connector_by_id(struct device *dev, uint32_t id) 76318210155Smrg{ 764e88f27b3Smrg drmModeConnector *connector; 765e88f27b3Smrg int i; 766e88f27b3Smrg 76787bf8e7cSmrg for (i = 0; i < dev->resources->count_connectors; i++) { 768e88f27b3Smrg connector = dev->resources->connectors[i].connector; 769e88f27b3Smrg if (connector && connector->connector_id == id) 770e88f27b3Smrg return connector; 771e88f27b3Smrg } 772e88f27b3Smrg 773e88f27b3Smrg return NULL; 774e88f27b3Smrg} 775e88f27b3Smrg 776e88f27b3Smrgstatic drmModeEncoder *get_encoder_by_id(struct device *dev, uint32_t id) 777e88f27b3Smrg{ 778e88f27b3Smrg drmModeEncoder *encoder; 779e88f27b3Smrg int i; 780e88f27b3Smrg 78187bf8e7cSmrg for (i = 0; i < dev->resources->count_encoders; i++) { 782e88f27b3Smrg encoder = dev->resources->encoders[i].encoder; 783e88f27b3Smrg if (encoder && encoder->encoder_id == id) 784e88f27b3Smrg return encoder; 785e88f27b3Smrg } 786e88f27b3Smrg 787e88f27b3Smrg return NULL; 788e88f27b3Smrg} 789e88f27b3Smrg 790e88f27b3Smrg/* ----------------------------------------------------------------------------- 791e88f27b3Smrg * Pipes and planes 792e88f27b3Smrg */ 793e88f27b3Smrg 794e88f27b3Smrg/* 795e88f27b3Smrg * Mode setting with the kernel interfaces is a bit of a chore. 796e88f27b3Smrg * First you have to find the connector in question and make sure the 797e88f27b3Smrg * requested mode is available. 798e88f27b3Smrg * Then you need to find the encoder attached to that connector so you 799e88f27b3Smrg * can bind it with a free crtc. 800e88f27b3Smrg */ 801e88f27b3Smrgstruct pipe_arg { 802fe517fc9Smrg const char **cons; 803e88f27b3Smrg uint32_t *con_ids; 804e88f27b3Smrg unsigned int num_cons; 805e88f27b3Smrg uint32_t crtc_id; 806e88f27b3Smrg char mode_str[64]; 807e88f27b3Smrg char format_str[5]; 80887bf8e7cSmrg float vrefresh; 809e88f27b3Smrg unsigned int fourcc; 810e88f27b3Smrg drmModeModeInfo *mode; 811e88f27b3Smrg struct crtc *crtc; 812e88f27b3Smrg unsigned int fb_id[2], current_fb_id; 813e88f27b3Smrg struct timeval start; 814e88f27b3Smrg 815e88f27b3Smrg int swap_count; 816e88f27b3Smrg}; 817e88f27b3Smrg 818e88f27b3Smrgstruct plane_arg { 8192ee35494Smrg uint32_t plane_id; /* the id of plane to use */ 820e88f27b3Smrg uint32_t crtc_id; /* the id of CRTC to bind to */ 821e88f27b3Smrg bool has_position; 822e88f27b3Smrg int32_t x, y; 823e88f27b3Smrg uint32_t w, h; 824e88f27b3Smrg double scale; 825e88f27b3Smrg unsigned int fb_id; 8266260e5d5Smrg unsigned int old_fb_id; 827424e9256Smrg struct bo *bo; 8286260e5d5Smrg struct bo *old_bo; 829e88f27b3Smrg char format_str[5]; /* need to leave room for terminating \0 */ 830e88f27b3Smrg unsigned int fourcc; 831e88f27b3Smrg}; 832e88f27b3Smrg 833e88f27b3Smrgstatic drmModeModeInfo * 834e88f27b3Smrgconnector_find_mode(struct device *dev, uint32_t con_id, const char *mode_str, 83587bf8e7cSmrg const float vrefresh) 836e88f27b3Smrg{ 837e88f27b3Smrg drmModeConnector *connector; 838e88f27b3Smrg drmModeModeInfo *mode; 839e88f27b3Smrg int i; 840e88f27b3Smrg 841e88f27b3Smrg connector = get_connector_by_id(dev, con_id); 842e88f27b3Smrg if (!connector || !connector->count_modes) 843e88f27b3Smrg return NULL; 844e88f27b3Smrg 84587bf8e7cSmrg /* Pick by Index */ 84687bf8e7cSmrg if (mode_str[0] == '#') { 84787bf8e7cSmrg int index = atoi(mode_str + 1); 84887bf8e7cSmrg 84987bf8e7cSmrg if (index >= connector->count_modes || index < 0) 85087bf8e7cSmrg return NULL; 85187bf8e7cSmrg return &connector->modes[index]; 85287bf8e7cSmrg } 85387bf8e7cSmrg 85487bf8e7cSmrg /* Pick by Name */ 855e88f27b3Smrg for (i = 0; i < connector->count_modes; i++) { 856e88f27b3Smrg mode = &connector->modes[i]; 857e88f27b3Smrg if (!strcmp(mode->name, mode_str)) { 85887bf8e7cSmrg /* If the vertical refresh frequency is not specified 85987bf8e7cSmrg * then return the first mode that match with the name. 86087bf8e7cSmrg * Else, return the mode that match the name and 86187bf8e7cSmrg * the specified vertical refresh frequency. 862e88f27b3Smrg */ 863e88f27b3Smrg if (vrefresh == 0) 864e88f27b3Smrg return mode; 86587bf8e7cSmrg else if (fabs(mode_vrefresh(mode) - vrefresh) < 0.005) 866e88f27b3Smrg return mode; 86718210155Smrg } 868e88f27b3Smrg } 86918210155Smrg 870e88f27b3Smrg return NULL; 87118210155Smrg} 87218210155Smrg 873e88f27b3Smrgstatic struct crtc *pipe_find_crtc(struct device *dev, struct pipe_arg *pipe) 87418210155Smrg{ 875e88f27b3Smrg uint32_t possible_crtcs = ~0; 876e88f27b3Smrg uint32_t active_crtcs = 0; 877e88f27b3Smrg unsigned int crtc_idx; 878e88f27b3Smrg unsigned int i; 879e88f27b3Smrg int j; 880e88f27b3Smrg 881e88f27b3Smrg for (i = 0; i < pipe->num_cons; ++i) { 882e88f27b3Smrg uint32_t crtcs_for_connector = 0; 883e88f27b3Smrg drmModeConnector *connector; 884e88f27b3Smrg drmModeEncoder *encoder; 88587bf8e7cSmrg struct crtc *crtc; 886e88f27b3Smrg 887e88f27b3Smrg connector = get_connector_by_id(dev, pipe->con_ids[i]); 888e88f27b3Smrg if (!connector) 889e88f27b3Smrg return NULL; 890e88f27b3Smrg 891e88f27b3Smrg for (j = 0; j < connector->count_encoders; ++j) { 892e88f27b3Smrg encoder = get_encoder_by_id(dev, connector->encoders[j]); 893e88f27b3Smrg if (!encoder) 894e88f27b3Smrg continue; 895e88f27b3Smrg 896e88f27b3Smrg crtcs_for_connector |= encoder->possible_crtcs; 89787bf8e7cSmrg crtc = get_crtc_by_id(dev, encoder->crtc_id); 89887bf8e7cSmrg if (!crtc) 89987bf8e7cSmrg continue; 90087bf8e7cSmrg active_crtcs |= get_crtc_mask(dev, crtc); 901e88f27b3Smrg } 90218210155Smrg 903e88f27b3Smrg possible_crtcs &= crtcs_for_connector; 90418210155Smrg } 90518210155Smrg 906e88f27b3Smrg if (!possible_crtcs) 907e88f27b3Smrg return NULL; 908e88f27b3Smrg 909e88f27b3Smrg /* Return the first possible and active CRTC if one exists, or the first 910e88f27b3Smrg * possible CRTC otherwise. 911e88f27b3Smrg */ 912e88f27b3Smrg if (possible_crtcs & active_crtcs) 913e88f27b3Smrg crtc_idx = ffs(possible_crtcs & active_crtcs); 914e88f27b3Smrg else 915e88f27b3Smrg crtc_idx = ffs(possible_crtcs); 916e88f27b3Smrg 917e88f27b3Smrg return &dev->resources->crtcs[crtc_idx - 1]; 918e88f27b3Smrg} 919e88f27b3Smrg 920e88f27b3Smrgstatic int pipe_find_crtc_and_mode(struct device *dev, struct pipe_arg *pipe) 921e88f27b3Smrg{ 922e88f27b3Smrg drmModeModeInfo *mode = NULL; 923e88f27b3Smrg int i; 924e88f27b3Smrg 925e88f27b3Smrg pipe->mode = NULL; 926e88f27b3Smrg 927e88f27b3Smrg for (i = 0; i < (int)pipe->num_cons; i++) { 928e88f27b3Smrg mode = connector_find_mode(dev, pipe->con_ids[i], 929e88f27b3Smrg pipe->mode_str, pipe->vrefresh); 930e88f27b3Smrg if (mode == NULL) { 93187bf8e7cSmrg if (pipe->vrefresh) 93287bf8e7cSmrg fprintf(stderr, 93387bf8e7cSmrg "failed to find mode " 93487bf8e7cSmrg "\"%s-%.2fHz\" for connector %s\n", 93587bf8e7cSmrg pipe->mode_str, pipe->vrefresh, pipe->cons[i]); 93687bf8e7cSmrg else 93787bf8e7cSmrg fprintf(stderr, 938fe517fc9Smrg "failed to find mode \"%s\" for connector %s\n", 939fe517fc9Smrg pipe->mode_str, pipe->cons[i]); 940e88f27b3Smrg return -EINVAL; 941e88f27b3Smrg } 94218210155Smrg } 94318210155Smrg 944e88f27b3Smrg /* If the CRTC ID was specified, get the corresponding CRTC. Otherwise 945e88f27b3Smrg * locate a CRTC that can be attached to all the connectors. 946e88f27b3Smrg */ 947e88f27b3Smrg if (pipe->crtc_id != (uint32_t)-1) { 94887bf8e7cSmrg pipe->crtc = get_crtc_by_id(dev, pipe->crtc_id); 949e88f27b3Smrg } else { 950e88f27b3Smrg pipe->crtc = pipe_find_crtc(dev, pipe); 95187bf8e7cSmrg pipe->crtc_id = pipe->crtc->crtc->crtc_id; 95218210155Smrg } 953d049871aSmrg 954e88f27b3Smrg if (!pipe->crtc) { 955e88f27b3Smrg fprintf(stderr, "failed to find CRTC for pipe\n"); 956e88f27b3Smrg return -EINVAL; 957e88f27b3Smrg } 958d049871aSmrg 959e88f27b3Smrg pipe->mode = mode; 960e88f27b3Smrg pipe->crtc->mode = mode; 96118210155Smrg 96218210155Smrg return 0; 96318210155Smrg} 96418210155Smrg 965e88f27b3Smrg/* ----------------------------------------------------------------------------- 966e88f27b3Smrg * Properties 967e88f27b3Smrg */ 968e88f27b3Smrg 969e88f27b3Smrgstruct property_arg { 970e88f27b3Smrg uint32_t obj_id; 971e88f27b3Smrg uint32_t obj_type; 972e88f27b3Smrg char name[DRM_PROP_NAME_LEN+1]; 973e88f27b3Smrg uint32_t prop_id; 974e88f27b3Smrg uint64_t value; 975bf6cc7dcSmrg bool optional; 976e88f27b3Smrg}; 977e88f27b3Smrg 978bf6cc7dcSmrgstatic bool set_property(struct device *dev, struct property_arg *p) 97922944501Smrg{ 980e88f27b3Smrg drmModeObjectProperties *props = NULL; 981e88f27b3Smrg drmModePropertyRes **props_info = NULL; 982e88f27b3Smrg const char *obj_type; 983e88f27b3Smrg int ret; 984e88f27b3Smrg int i; 98522944501Smrg 986e88f27b3Smrg p->obj_type = 0; 987e88f27b3Smrg p->prop_id = 0; 988e88f27b3Smrg 98987bf8e7cSmrg#define find_object(_res, type, Type) \ 990e88f27b3Smrg do { \ 99187bf8e7cSmrg for (i = 0; i < (int)(_res)->count_##type##s; ++i) { \ 992e88f27b3Smrg struct type *obj = &(_res)->type##s[i]; \ 993e88f27b3Smrg if (obj->type->type##_id != p->obj_id) \ 994e88f27b3Smrg continue; \ 995e88f27b3Smrg p->obj_type = DRM_MODE_OBJECT_##Type; \ 996e88f27b3Smrg obj_type = #Type; \ 997e88f27b3Smrg props = obj->props; \ 998e88f27b3Smrg props_info = obj->props_info; \ 999e88f27b3Smrg } \ 1000e88f27b3Smrg } while(0) \ 1001e88f27b3Smrg 100287bf8e7cSmrg find_object(dev->resources, crtc, CRTC); 1003e88f27b3Smrg if (p->obj_type == 0) 100487bf8e7cSmrg find_object(dev->resources, connector, CONNECTOR); 1005e88f27b3Smrg if (p->obj_type == 0) 100687bf8e7cSmrg find_object(dev->resources, plane, PLANE); 1007e88f27b3Smrg if (p->obj_type == 0) { 1008e88f27b3Smrg fprintf(stderr, "Object %i not found, can't set property\n", 1009e88f27b3Smrg p->obj_id); 1010bf6cc7dcSmrg return false; 1011e88f27b3Smrg } 101222944501Smrg 1013e88f27b3Smrg if (!props) { 1014e88f27b3Smrg fprintf(stderr, "%s %i has no properties\n", 1015e88f27b3Smrg obj_type, p->obj_id); 1016bf6cc7dcSmrg return false; 101722944501Smrg } 101822944501Smrg 1019e88f27b3Smrg for (i = 0; i < (int)props->count_props; ++i) { 1020e88f27b3Smrg if (!props_info[i]) 1021e88f27b3Smrg continue; 1022e88f27b3Smrg if (strcmp(props_info[i]->name, p->name) == 0) 1023e88f27b3Smrg break; 102422944501Smrg } 102522944501Smrg 1026e88f27b3Smrg if (i == (int)props->count_props) { 1027bf6cc7dcSmrg if (!p->optional) 1028bf6cc7dcSmrg fprintf(stderr, "%s %i has no %s property\n", 1029bf6cc7dcSmrg obj_type, p->obj_id, p->name); 1030bf6cc7dcSmrg return false; 1031e88f27b3Smrg } 103222944501Smrg 1033e88f27b3Smrg p->prop_id = props->props[i]; 103422944501Smrg 10356260e5d5Smrg if (!dev->use_atomic) 10366260e5d5Smrg ret = drmModeObjectSetProperty(dev->fd, p->obj_id, p->obj_type, 10376260e5d5Smrg p->prop_id, p->value); 10386260e5d5Smrg else 10396260e5d5Smrg ret = drmModeAtomicAddProperty(dev->req, p->obj_id, p->prop_id, p->value); 10406260e5d5Smrg 1041e88f27b3Smrg if (ret < 0) 1042e88f27b3Smrg fprintf(stderr, "failed to set %s %i property %s to %" PRIu64 ": %s\n", 1043e88f27b3Smrg obj_type, p->obj_id, p->name, p->value, strerror(errno)); 1044bf6cc7dcSmrg 1045bf6cc7dcSmrg return true; 104622944501Smrg} 104722944501Smrg 1048e88f27b3Smrg/* -------------------------------------------------------------------------- */ 1049e88f27b3Smrg 1050e88f27b3Smrgstatic void 105122944501Smrgpage_flip_handler(int fd, unsigned int frame, 105222944501Smrg unsigned int sec, unsigned int usec, void *data) 105322944501Smrg{ 1054e88f27b3Smrg struct pipe_arg *pipe; 105522944501Smrg unsigned int new_fb_id; 105622944501Smrg struct timeval end; 105722944501Smrg double t; 105822944501Smrg 1059e88f27b3Smrg pipe = data; 1060e88f27b3Smrg if (pipe->current_fb_id == pipe->fb_id[0]) 1061e88f27b3Smrg new_fb_id = pipe->fb_id[1]; 106222944501Smrg else 1063e88f27b3Smrg new_fb_id = pipe->fb_id[0]; 1064e88f27b3Smrg 106587bf8e7cSmrg drmModePageFlip(fd, pipe->crtc_id, new_fb_id, 1066e88f27b3Smrg DRM_MODE_PAGE_FLIP_EVENT, pipe); 1067e88f27b3Smrg pipe->current_fb_id = new_fb_id; 1068e88f27b3Smrg pipe->swap_count++; 1069e88f27b3Smrg if (pipe->swap_count == 60) { 107022944501Smrg gettimeofday(&end, NULL); 107122944501Smrg t = end.tv_sec + end.tv_usec * 1e-6 - 1072e88f27b3Smrg (pipe->start.tv_sec + pipe->start.tv_usec * 1e-6); 1073e88f27b3Smrg fprintf(stderr, "freq: %.02fHz\n", pipe->swap_count / t); 1074e88f27b3Smrg pipe->swap_count = 0; 1075e88f27b3Smrg pipe->start = end; 107622944501Smrg } 107722944501Smrg} 107822944501Smrg 1079424e9256Smrgstatic bool format_support(const drmModePlanePtr ovr, uint32_t fmt) 1080424e9256Smrg{ 1081424e9256Smrg unsigned int i; 1082424e9256Smrg 1083424e9256Smrg for (i = 0; i < ovr->count_formats; ++i) { 1084424e9256Smrg if (ovr->formats[i] == fmt) 1085424e9256Smrg return true; 1086424e9256Smrg } 1087424e9256Smrg 1088424e9256Smrg return false; 1089424e9256Smrg} 1090424e9256Smrg 10916260e5d5Smrgstatic void add_property(struct device *dev, uint32_t obj_id, 10926260e5d5Smrg const char *name, uint64_t value) 10936260e5d5Smrg{ 10946260e5d5Smrg struct property_arg p; 10956260e5d5Smrg 10966260e5d5Smrg p.obj_id = obj_id; 10976260e5d5Smrg strcpy(p.name, name); 10986260e5d5Smrg p.value = value; 10996260e5d5Smrg 11006260e5d5Smrg set_property(dev, &p); 11016260e5d5Smrg} 11026260e5d5Smrg 1103bf6cc7dcSmrgstatic bool add_property_optional(struct device *dev, uint32_t obj_id, 1104bf6cc7dcSmrg const char *name, uint64_t value) 1105bf6cc7dcSmrg{ 1106bf6cc7dcSmrg struct property_arg p; 1107bf6cc7dcSmrg 1108bf6cc7dcSmrg p.obj_id = obj_id; 1109bf6cc7dcSmrg strcpy(p.name, name); 1110bf6cc7dcSmrg p.value = value; 1111bf6cc7dcSmrg p.optional = true; 1112bf6cc7dcSmrg 1113bf6cc7dcSmrg return set_property(dev, &p); 1114bf6cc7dcSmrg} 1115bf6cc7dcSmrg 1116bf6cc7dcSmrgstatic void set_gamma(struct device *dev, unsigned crtc_id, unsigned fourcc) 1117bf6cc7dcSmrg{ 1118bf6cc7dcSmrg unsigned blob_id = 0; 1119bf6cc7dcSmrg /* TODO: support 1024-sized LUTs, when the use-case arises */ 1120bf6cc7dcSmrg struct drm_color_lut gamma_lut[256]; 1121bf6cc7dcSmrg int i, ret; 1122bf6cc7dcSmrg 1123bf6cc7dcSmrg if (fourcc == DRM_FORMAT_C8) { 1124bf6cc7dcSmrg /* TODO: Add C8 support for more patterns */ 1125bf6cc7dcSmrg util_smpte_c8_gamma(256, gamma_lut); 1126bf6cc7dcSmrg drmModeCreatePropertyBlob(dev->fd, gamma_lut, sizeof(gamma_lut), &blob_id); 1127bf6cc7dcSmrg } else { 1128bf6cc7dcSmrg for (i = 0; i < 256; i++) { 1129bf6cc7dcSmrg gamma_lut[i].red = 1130bf6cc7dcSmrg gamma_lut[i].green = 1131bf6cc7dcSmrg gamma_lut[i].blue = i << 8; 1132bf6cc7dcSmrg } 1133bf6cc7dcSmrg } 1134bf6cc7dcSmrg 1135bf6cc7dcSmrg add_property_optional(dev, crtc_id, "DEGAMMA_LUT", 0); 1136bf6cc7dcSmrg add_property_optional(dev, crtc_id, "CTM", 0); 1137bf6cc7dcSmrg if (!add_property_optional(dev, crtc_id, "GAMMA_LUT", blob_id)) { 1138bf6cc7dcSmrg uint16_t r[256], g[256], b[256]; 1139bf6cc7dcSmrg 1140bf6cc7dcSmrg for (i = 0; i < 256; i++) { 1141bf6cc7dcSmrg r[i] = gamma_lut[i].red; 1142bf6cc7dcSmrg g[i] = gamma_lut[i].green; 1143bf6cc7dcSmrg b[i] = gamma_lut[i].blue; 1144bf6cc7dcSmrg } 1145bf6cc7dcSmrg 1146bf6cc7dcSmrg ret = drmModeCrtcSetGamma(dev->fd, crtc_id, 256, r, g, b); 1147bf6cc7dcSmrg if (ret) 1148bf6cc7dcSmrg fprintf(stderr, "failed to set gamma: %s\n", strerror(errno)); 1149bf6cc7dcSmrg } 1150bf6cc7dcSmrg} 1151bf6cc7dcSmrg 115287bf8e7cSmrgstatic int 115387bf8e7cSmrgbo_fb_create(int fd, unsigned int fourcc, const uint32_t w, const uint32_t h, 115487bf8e7cSmrg enum util_fill_pattern pat, struct bo **out_bo, unsigned int *out_fb_id) 115587bf8e7cSmrg{ 115687bf8e7cSmrg uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0}; 115787bf8e7cSmrg struct bo *bo; 115887bf8e7cSmrg unsigned int fb_id; 115987bf8e7cSmrg 116087bf8e7cSmrg bo = bo_create(fd, fourcc, w, h, handles, pitches, offsets, pat); 116187bf8e7cSmrg 116287bf8e7cSmrg if (bo == NULL) 116387bf8e7cSmrg return -1; 116487bf8e7cSmrg 116587bf8e7cSmrg if (drmModeAddFB2(fd, w, h, fourcc, handles, pitches, offsets, &fb_id, 0)) { 116687bf8e7cSmrg fprintf(stderr, "failed to add fb (%ux%u): %s\n", w, h, strerror(errno)); 116787bf8e7cSmrg bo_destroy(bo); 116887bf8e7cSmrg return -1; 116987bf8e7cSmrg } 117087bf8e7cSmrg *out_bo = bo; 117187bf8e7cSmrg *out_fb_id = fb_id; 117287bf8e7cSmrg return 0; 117387bf8e7cSmrg} 117487bf8e7cSmrg 11756260e5d5Smrgstatic int atomic_set_plane(struct device *dev, struct plane_arg *p, 11766260e5d5Smrg int pattern, bool update) 11776260e5d5Smrg{ 11786260e5d5Smrg struct bo *plane_bo; 11796260e5d5Smrg int crtc_x, crtc_y, crtc_w, crtc_h; 11806260e5d5Smrg struct crtc *crtc = NULL; 11816260e5d5Smrg unsigned int old_fb_id; 11826260e5d5Smrg 11836260e5d5Smrg /* Find an unused plane which can be connected to our CRTC. Find the 11846260e5d5Smrg * CRTC index first, then iterate over available planes. 11856260e5d5Smrg */ 118687bf8e7cSmrg crtc = get_crtc_by_id(dev, p->crtc_id); 11876260e5d5Smrg if (!crtc) { 11886260e5d5Smrg fprintf(stderr, "CRTC %u not found\n", p->crtc_id); 11896260e5d5Smrg return -1; 11906260e5d5Smrg } 11916260e5d5Smrg 11926260e5d5Smrg if (!update) 11936260e5d5Smrg fprintf(stderr, "testing %dx%d@%s on plane %u, crtc %u\n", 11946260e5d5Smrg p->w, p->h, p->format_str, p->plane_id, p->crtc_id); 11956260e5d5Smrg 11966260e5d5Smrg plane_bo = p->old_bo; 11976260e5d5Smrg p->old_bo = p->bo; 11986260e5d5Smrg 11996260e5d5Smrg if (!plane_bo) { 120087bf8e7cSmrg if (bo_fb_create(dev->fd, p->fourcc, p->w, p->h, 120187bf8e7cSmrg pattern, &plane_bo, &p->fb_id)) 12026260e5d5Smrg return -1; 12036260e5d5Smrg } 12046260e5d5Smrg 12056260e5d5Smrg p->bo = plane_bo; 12066260e5d5Smrg 12076260e5d5Smrg old_fb_id = p->fb_id; 12086260e5d5Smrg p->old_fb_id = old_fb_id; 12096260e5d5Smrg 12106260e5d5Smrg crtc_w = p->w * p->scale; 12116260e5d5Smrg crtc_h = p->h * p->scale; 12126260e5d5Smrg if (!p->has_position) { 12136260e5d5Smrg /* Default to the middle of the screen */ 12146260e5d5Smrg crtc_x = (crtc->mode->hdisplay - crtc_w) / 2; 12156260e5d5Smrg crtc_y = (crtc->mode->vdisplay - crtc_h) / 2; 12166260e5d5Smrg } else { 12176260e5d5Smrg crtc_x = p->x; 12186260e5d5Smrg crtc_y = p->y; 12196260e5d5Smrg } 12206260e5d5Smrg 12216260e5d5Smrg add_property(dev, p->plane_id, "FB_ID", p->fb_id); 12226260e5d5Smrg add_property(dev, p->plane_id, "CRTC_ID", p->crtc_id); 12236260e5d5Smrg add_property(dev, p->plane_id, "SRC_X", 0); 12246260e5d5Smrg add_property(dev, p->plane_id, "SRC_Y", 0); 12256260e5d5Smrg add_property(dev, p->plane_id, "SRC_W", p->w << 16); 12266260e5d5Smrg add_property(dev, p->plane_id, "SRC_H", p->h << 16); 12276260e5d5Smrg add_property(dev, p->plane_id, "CRTC_X", crtc_x); 12286260e5d5Smrg add_property(dev, p->plane_id, "CRTC_Y", crtc_y); 12296260e5d5Smrg add_property(dev, p->plane_id, "CRTC_W", crtc_w); 12306260e5d5Smrg add_property(dev, p->plane_id, "CRTC_H", crtc_h); 12316260e5d5Smrg 12326260e5d5Smrg return 0; 12336260e5d5Smrg} 12346260e5d5Smrg 1235e88f27b3Smrgstatic int set_plane(struct device *dev, struct plane_arg *p) 123618210155Smrg{ 1237e88f27b3Smrg drmModePlane *ovr; 12382ee35494Smrg uint32_t plane_id; 1239e88f27b3Smrg int crtc_x, crtc_y, crtc_w, crtc_h; 1240e88f27b3Smrg struct crtc *crtc = NULL; 124187bf8e7cSmrg unsigned int i, crtc_mask; 1242e88f27b3Smrg 1243e88f27b3Smrg /* Find an unused plane which can be connected to our CRTC. Find the 1244e88f27b3Smrg * CRTC index first, then iterate over available planes. 1245e88f27b3Smrg */ 124687bf8e7cSmrg crtc = get_crtc_by_id(dev, p->crtc_id); 1247e88f27b3Smrg if (!crtc) { 1248e88f27b3Smrg fprintf(stderr, "CRTC %u not found\n", p->crtc_id); 1249e88f27b3Smrg return -1; 1250e88f27b3Smrg } 125187bf8e7cSmrg crtc_mask = get_crtc_mask(dev, crtc); 12522ee35494Smrg plane_id = p->plane_id; 12532ee35494Smrg 125487bf8e7cSmrg for (i = 0; i < dev->resources->count_planes; i++) { 1255e88f27b3Smrg ovr = dev->resources->planes[i].plane; 12562ee35494Smrg if (!ovr) 12572ee35494Smrg continue; 12582ee35494Smrg 12592ee35494Smrg if (plane_id && plane_id != ovr->plane_id) 12602ee35494Smrg continue; 12612ee35494Smrg 12622ee35494Smrg if (!format_support(ovr, p->fourcc)) 126318210155Smrg continue; 1264e88f27b3Smrg 126587bf8e7cSmrg if ((ovr->possible_crtcs & crtc_mask) && 12662b90624aSmrg (ovr->crtc_id == 0 || ovr->crtc_id == p->crtc_id)) { 1267e88f27b3Smrg plane_id = ovr->plane_id; 12682ee35494Smrg break; 12692ee35494Smrg } 127018210155Smrg } 127118210155Smrg 127287bf8e7cSmrg if (i == dev->resources->count_planes) { 1273e88f27b3Smrg fprintf(stderr, "no unused plane available for CRTC %u\n", 127487bf8e7cSmrg p->crtc_id); 1275e88f27b3Smrg return -1; 1276e88f27b3Smrg } 1277e88f27b3Smrg 1278e88f27b3Smrg fprintf(stderr, "testing %dx%d@%s overlay plane %u\n", 1279e88f27b3Smrg p->w, p->h, p->format_str, plane_id); 1280e88f27b3Smrg 1281e88f27b3Smrg /* just use single plane format for now.. */ 128287bf8e7cSmrg if (bo_fb_create(dev->fd, p->fourcc, p->w, p->h, 128387bf8e7cSmrg secondary_fill, &p->bo, &p->fb_id)) 1284e88f27b3Smrg return -1; 1285e88f27b3Smrg 1286e88f27b3Smrg crtc_w = p->w * p->scale; 1287e88f27b3Smrg crtc_h = p->h * p->scale; 1288e88f27b3Smrg if (!p->has_position) { 1289e88f27b3Smrg /* Default to the middle of the screen */ 1290e88f27b3Smrg crtc_x = (crtc->mode->hdisplay - crtc_w) / 2; 1291e88f27b3Smrg crtc_y = (crtc->mode->vdisplay - crtc_h) / 2; 1292e88f27b3Smrg } else { 1293e88f27b3Smrg crtc_x = p->x; 1294e88f27b3Smrg crtc_y = p->y; 129518210155Smrg } 129618210155Smrg 1297e88f27b3Smrg /* note src coords (last 4 args) are in Q16 format */ 129887bf8e7cSmrg if (drmModeSetPlane(dev->fd, plane_id, p->crtc_id, p->fb_id, 129987bf8e7cSmrg 0, crtc_x, crtc_y, crtc_w, crtc_h, 1300e88f27b3Smrg 0, 0, p->w << 16, p->h << 16)) { 1301e88f27b3Smrg fprintf(stderr, "failed to enable plane: %s\n", 1302e88f27b3Smrg strerror(errno)); 1303e88f27b3Smrg return -1; 1304e88f27b3Smrg } 1305e88f27b3Smrg 130687bf8e7cSmrg ovr->crtc_id = p->crtc_id; 1307e88f27b3Smrg 1308e88f27b3Smrg return 0; 1309e88f27b3Smrg} 1310e88f27b3Smrg 13116260e5d5Smrgstatic void atomic_set_planes(struct device *dev, struct plane_arg *p, 13126260e5d5Smrg unsigned int count, bool update) 13136260e5d5Smrg{ 1314bf6cc7dcSmrg unsigned int i, pattern = primary_fill; 13156260e5d5Smrg 13166260e5d5Smrg /* set up planes */ 13176260e5d5Smrg for (i = 0; i < count; i++) { 13186260e5d5Smrg if (i > 0) 1319bf6cc7dcSmrg pattern = secondary_fill; 1320bf6cc7dcSmrg else 1321bf6cc7dcSmrg set_gamma(dev, p[i].crtc_id, p[i].fourcc); 13226260e5d5Smrg 13236260e5d5Smrg if (atomic_set_plane(dev, &p[i], pattern, update)) 13246260e5d5Smrg return; 13256260e5d5Smrg } 13266260e5d5Smrg} 13276260e5d5Smrg 132887bf8e7cSmrgstatic void 132987bf8e7cSmrgatomic_test_page_flip(struct device *dev, struct pipe_arg *pipe_args, 133087bf8e7cSmrg struct plane_arg *plane_args, unsigned int plane_count) 133187bf8e7cSmrg{ 133287bf8e7cSmrg int ret; 133387bf8e7cSmrg 133487bf8e7cSmrg gettimeofday(&pipe_args->start, NULL); 133587bf8e7cSmrg pipe_args->swap_count = 0; 133687bf8e7cSmrg 133787bf8e7cSmrg while (true) { 133887bf8e7cSmrg drmModeAtomicFree(dev->req); 133987bf8e7cSmrg dev->req = drmModeAtomicAlloc(); 134087bf8e7cSmrg atomic_set_planes(dev, plane_args, plane_count, true); 134187bf8e7cSmrg 134287bf8e7cSmrg ret = drmModeAtomicCommit(dev->fd, dev->req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL); 134387bf8e7cSmrg if (ret) { 134487bf8e7cSmrg fprintf(stderr, "Atomic Commit failed [2]\n"); 134587bf8e7cSmrg return; 134687bf8e7cSmrg } 134787bf8e7cSmrg 134887bf8e7cSmrg pipe_args->swap_count++; 134987bf8e7cSmrg if (pipe_args->swap_count == 60) { 135087bf8e7cSmrg struct timeval end; 135187bf8e7cSmrg double t; 135287bf8e7cSmrg 135387bf8e7cSmrg gettimeofday(&end, NULL); 135487bf8e7cSmrg t = end.tv_sec + end.tv_usec * 1e-6 - 135587bf8e7cSmrg (pipe_args->start.tv_sec + pipe_args->start.tv_usec * 1e-6); 135687bf8e7cSmrg fprintf(stderr, "freq: %.02fHz\n", pipe_args->swap_count / t); 135787bf8e7cSmrg pipe_args->swap_count = 0; 135887bf8e7cSmrg pipe_args->start = end; 135987bf8e7cSmrg } 136087bf8e7cSmrg } 136187bf8e7cSmrg} 136287bf8e7cSmrg 13636260e5d5Smrgstatic void atomic_clear_planes(struct device *dev, struct plane_arg *p, unsigned int count) 13646260e5d5Smrg{ 13656260e5d5Smrg unsigned int i; 13666260e5d5Smrg 13676260e5d5Smrg for (i = 0; i < count; i++) { 13686260e5d5Smrg add_property(dev, p[i].plane_id, "FB_ID", 0); 13696260e5d5Smrg add_property(dev, p[i].plane_id, "CRTC_ID", 0); 13706260e5d5Smrg add_property(dev, p[i].plane_id, "SRC_X", 0); 13716260e5d5Smrg add_property(dev, p[i].plane_id, "SRC_Y", 0); 13726260e5d5Smrg add_property(dev, p[i].plane_id, "SRC_W", 0); 13736260e5d5Smrg add_property(dev, p[i].plane_id, "SRC_H", 0); 13746260e5d5Smrg add_property(dev, p[i].plane_id, "CRTC_X", 0); 13756260e5d5Smrg add_property(dev, p[i].plane_id, "CRTC_Y", 0); 13766260e5d5Smrg add_property(dev, p[i].plane_id, "CRTC_W", 0); 13776260e5d5Smrg add_property(dev, p[i].plane_id, "CRTC_H", 0); 13786260e5d5Smrg } 13796260e5d5Smrg} 13806260e5d5Smrg 13816260e5d5Smrgstatic void atomic_clear_FB(struct device *dev, struct plane_arg *p, unsigned int count) 13826260e5d5Smrg{ 13836260e5d5Smrg unsigned int i; 13846260e5d5Smrg 13856260e5d5Smrg for (i = 0; i < count; i++) { 13866260e5d5Smrg if (p[i].fb_id) { 13876260e5d5Smrg drmModeRmFB(dev->fd, p[i].fb_id); 13886260e5d5Smrg p[i].fb_id = 0; 13896260e5d5Smrg } 13906260e5d5Smrg if (p[i].old_fb_id) { 13916260e5d5Smrg drmModeRmFB(dev->fd, p[i].old_fb_id); 13926260e5d5Smrg p[i].old_fb_id = 0; 13936260e5d5Smrg } 13946260e5d5Smrg if (p[i].bo) { 13956260e5d5Smrg bo_destroy(p[i].bo); 13966260e5d5Smrg p[i].bo = NULL; 13976260e5d5Smrg } 13986260e5d5Smrg if (p[i].old_bo) { 13996260e5d5Smrg bo_destroy(p[i].old_bo); 14006260e5d5Smrg p[i].old_bo = NULL; 14016260e5d5Smrg } 14026260e5d5Smrg 14036260e5d5Smrg } 14046260e5d5Smrg} 14056260e5d5Smrg 1406424e9256Smrgstatic void clear_planes(struct device *dev, struct plane_arg *p, unsigned int count) 1407424e9256Smrg{ 1408424e9256Smrg unsigned int i; 1409424e9256Smrg 1410424e9256Smrg for (i = 0; i < count; i++) { 1411424e9256Smrg if (p[i].fb_id) 1412424e9256Smrg drmModeRmFB(dev->fd, p[i].fb_id); 1413424e9256Smrg if (p[i].bo) 1414424e9256Smrg bo_destroy(p[i].bo); 1415424e9256Smrg } 1416424e9256Smrg} 1417424e9256Smrg 141887bf8e7cSmrgstatic int pipe_resolve_connectors(struct device *dev, struct pipe_arg *pipe) 14196260e5d5Smrg{ 142087bf8e7cSmrg drmModeConnector *connector; 14216260e5d5Smrg unsigned int i; 142287bf8e7cSmrg uint32_t id; 142387bf8e7cSmrg char *endp; 14246260e5d5Smrg 142587bf8e7cSmrg for (i = 0; i < pipe->num_cons; i++) { 142687bf8e7cSmrg id = strtoul(pipe->cons[i], &endp, 10); 142787bf8e7cSmrg if (endp == pipe->cons[i]) { 142887bf8e7cSmrg connector = get_connector_by_name(dev, pipe->cons[i]); 142987bf8e7cSmrg if (!connector) { 143087bf8e7cSmrg fprintf(stderr, "no connector named '%s'\n", 143187bf8e7cSmrg pipe->cons[i]); 143287bf8e7cSmrg return -ENODEV; 143387bf8e7cSmrg } 14346260e5d5Smrg 143587bf8e7cSmrg id = connector->connector_id; 143687bf8e7cSmrg } 143787bf8e7cSmrg 143887bf8e7cSmrg pipe->con_ids[i] = id; 143987bf8e7cSmrg } 144087bf8e7cSmrg 144187bf8e7cSmrg return 0; 144287bf8e7cSmrg} 144387bf8e7cSmrg 144487bf8e7cSmrgstatic int pipe_attempt_connector(struct device *dev, drmModeConnector *con, 144587bf8e7cSmrg struct pipe_arg *pipe) 144687bf8e7cSmrg{ 144787bf8e7cSmrg char *con_str; 144887bf8e7cSmrg int i; 144987bf8e7cSmrg 145087bf8e7cSmrg con_str = calloc(8, sizeof(char)); 145187bf8e7cSmrg if (!con_str) 145287bf8e7cSmrg return -1; 145387bf8e7cSmrg 145487bf8e7cSmrg sprintf(con_str, "%d", con->connector_id); 145587bf8e7cSmrg strcpy(pipe->format_str, "XR24"); 145687bf8e7cSmrg pipe->fourcc = util_format_fourcc(pipe->format_str); 145787bf8e7cSmrg pipe->num_cons = 1; 145887bf8e7cSmrg pipe->con_ids = calloc(1, sizeof(*pipe->con_ids)); 145987bf8e7cSmrg pipe->cons = calloc(1, sizeof(*pipe->cons)); 146087bf8e7cSmrg 146187bf8e7cSmrg if (!pipe->con_ids || !pipe->cons) 146287bf8e7cSmrg goto free_con_str; 146387bf8e7cSmrg 146487bf8e7cSmrg pipe->con_ids[0] = con->connector_id; 146587bf8e7cSmrg pipe->cons[0] = (const char*)con_str; 146687bf8e7cSmrg 146787bf8e7cSmrg pipe->crtc = pipe_find_crtc(dev, pipe); 146887bf8e7cSmrg if (!pipe->crtc) 146987bf8e7cSmrg goto free_all; 147087bf8e7cSmrg 147187bf8e7cSmrg pipe->crtc_id = pipe->crtc->crtc->crtc_id; 147287bf8e7cSmrg 147387bf8e7cSmrg /* Return the first mode if no preferred. */ 147487bf8e7cSmrg pipe->mode = &con->modes[0]; 147587bf8e7cSmrg 147687bf8e7cSmrg for (i = 0; i < con->count_modes; i++) { 147787bf8e7cSmrg drmModeModeInfo *current_mode = &con->modes[i]; 147887bf8e7cSmrg 147987bf8e7cSmrg if (current_mode->type & DRM_MODE_TYPE_PREFERRED) { 148087bf8e7cSmrg pipe->mode = current_mode; 148187bf8e7cSmrg break; 148287bf8e7cSmrg } 148387bf8e7cSmrg } 148487bf8e7cSmrg 148587bf8e7cSmrg sprintf(pipe->mode_str, "%dx%d", pipe->mode->hdisplay, pipe->mode->vdisplay); 148687bf8e7cSmrg 148787bf8e7cSmrg return 0; 148887bf8e7cSmrg 148987bf8e7cSmrgfree_all: 149087bf8e7cSmrg free(pipe->cons); 149187bf8e7cSmrg free(pipe->con_ids); 149287bf8e7cSmrgfree_con_str: 149387bf8e7cSmrg free(con_str); 149487bf8e7cSmrg return -1; 149587bf8e7cSmrg} 149687bf8e7cSmrg 149787bf8e7cSmrgstatic int pipe_find_preferred(struct device *dev, struct pipe_arg **out_pipes) 149887bf8e7cSmrg{ 149987bf8e7cSmrg struct pipe_arg *pipes; 150087bf8e7cSmrg struct resources *res = dev->resources; 150187bf8e7cSmrg drmModeConnector *con = NULL; 150287bf8e7cSmrg int i, connected = 0, attempted = 0; 150387bf8e7cSmrg 150487bf8e7cSmrg for (i = 0; i < res->count_connectors; i++) { 150587bf8e7cSmrg con = res->connectors[i].connector; 150687bf8e7cSmrg if (!con || con->connection != DRM_MODE_CONNECTED) 15076260e5d5Smrg continue; 150887bf8e7cSmrg connected++; 150987bf8e7cSmrg } 151087bf8e7cSmrg if (!connected) { 151187bf8e7cSmrg printf("no connected connector!\n"); 151287bf8e7cSmrg return 0; 15136260e5d5Smrg } 15146260e5d5Smrg 151587bf8e7cSmrg pipes = calloc(connected, sizeof(struct pipe_arg)); 151687bf8e7cSmrg if (!pipes) 151787bf8e7cSmrg return 0; 15186260e5d5Smrg 151987bf8e7cSmrg for (i = 0; i < res->count_connectors && attempted < connected; i++) { 152087bf8e7cSmrg con = res->connectors[i].connector; 152187bf8e7cSmrg if (!con || con->connection != DRM_MODE_CONNECTED) 15226260e5d5Smrg continue; 15236260e5d5Smrg 152487bf8e7cSmrg if (pipe_attempt_connector(dev, con, &pipes[attempted]) < 0) { 152587bf8e7cSmrg printf("failed fetching preferred mode for connector\n"); 152687bf8e7cSmrg continue; 15276260e5d5Smrg } 152887bf8e7cSmrg attempted++; 15296260e5d5Smrg } 153087bf8e7cSmrg 153187bf8e7cSmrg *out_pipes = pipes; 153287bf8e7cSmrg return attempted; 15336260e5d5Smrg} 15346260e5d5Smrg 153587bf8e7cSmrgstatic struct plane *get_primary_plane_by_crtc(struct device *dev, struct crtc *crtc) 15366260e5d5Smrg{ 15376260e5d5Smrg unsigned int i; 15386260e5d5Smrg 153987bf8e7cSmrg for (i = 0; i < dev->resources->count_planes; i++) { 154087bf8e7cSmrg struct plane *plane = &dev->resources->planes[i]; 154187bf8e7cSmrg drmModePlane *ovr = plane->plane; 154287bf8e7cSmrg if (!ovr) 15436260e5d5Smrg continue; 15446260e5d5Smrg 154587bf8e7cSmrg // XXX: add is_primary_plane and (?) format checks 15466260e5d5Smrg 154787bf8e7cSmrg if (ovr->possible_crtcs & get_crtc_mask(dev, crtc)) 154887bf8e7cSmrg return plane; 15496260e5d5Smrg } 155087bf8e7cSmrg return NULL; 15516260e5d5Smrg} 1552424e9256Smrg 1553e88f27b3Smrgstatic void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count) 1554e88f27b3Smrg{ 155587bf8e7cSmrg unsigned int i, j; 155687bf8e7cSmrg int ret, x = 0; 155787bf8e7cSmrg int preferred = count == 0; 1558e88f27b3Smrg 1559e88f27b3Smrg for (i = 0; i < count; i++) { 1560e88f27b3Smrg struct pipe_arg *pipe = &pipes[i]; 1561e88f27b3Smrg 156287bf8e7cSmrg ret = pipe_resolve_connectors(dev, pipe); 156387bf8e7cSmrg if (ret < 0) 156487bf8e7cSmrg return; 156587bf8e7cSmrg 1566e88f27b3Smrg ret = pipe_find_crtc_and_mode(dev, pipe); 1567e88f27b3Smrg if (ret < 0) 1568e88f27b3Smrg continue; 156987bf8e7cSmrg } 157087bf8e7cSmrg if (preferred) { 157187bf8e7cSmrg struct pipe_arg *pipe_args; 1572e88f27b3Smrg 157387bf8e7cSmrg count = pipe_find_preferred(dev, &pipe_args); 157487bf8e7cSmrg if (!count) { 157587bf8e7cSmrg fprintf(stderr, "can't find any preferred connector/mode.\n"); 157687bf8e7cSmrg return; 157787bf8e7cSmrg } 157887bf8e7cSmrg pipes = pipe_args; 1579e88f27b3Smrg } 1580e88f27b3Smrg 158187bf8e7cSmrg if (!dev->use_atomic) { 158287bf8e7cSmrg for (i = 0; i < count; i++) { 158387bf8e7cSmrg struct pipe_arg *pipe = &pipes[i]; 158418210155Smrg 158587bf8e7cSmrg if (pipe->mode == NULL) 158687bf8e7cSmrg continue; 1587424e9256Smrg 158887bf8e7cSmrg if (!preferred) { 158987bf8e7cSmrg dev->mode.width += pipe->mode->hdisplay; 159087bf8e7cSmrg if (dev->mode.height < pipe->mode->vdisplay) 159187bf8e7cSmrg dev->mode.height = pipe->mode->vdisplay; 159287bf8e7cSmrg } else { 159387bf8e7cSmrg /* XXX: Use a clone mode, more like atomic. We could do per 159487bf8e7cSmrg * connector bo/fb, so we don't have the stretched image. 159587bf8e7cSmrg */ 159687bf8e7cSmrg if (dev->mode.width < pipe->mode->hdisplay) 159787bf8e7cSmrg dev->mode.width = pipe->mode->hdisplay; 159887bf8e7cSmrg if (dev->mode.height < pipe->mode->vdisplay) 159987bf8e7cSmrg dev->mode.height = pipe->mode->vdisplay; 160087bf8e7cSmrg } 160187bf8e7cSmrg } 160218210155Smrg 160387bf8e7cSmrg if (bo_fb_create(dev->fd, pipes[0].fourcc, dev->mode.width, dev->mode.height, 160487bf8e7cSmrg primary_fill, &dev->mode.bo, &dev->mode.fb_id)) 160587bf8e7cSmrg return; 160687bf8e7cSmrg } 1607424e9256Smrg 160818210155Smrg for (i = 0; i < count; i++) { 1609e88f27b3Smrg struct pipe_arg *pipe = &pipes[i]; 161087bf8e7cSmrg uint32_t blob_id; 1611e88f27b3Smrg 1612e88f27b3Smrg if (pipe->mode == NULL) 161318210155Smrg continue; 161418210155Smrg 161587bf8e7cSmrg printf("setting mode %s-%.2fHz on connectors ", 161687bf8e7cSmrg pipe->mode->name, mode_vrefresh(pipe->mode)); 161787bf8e7cSmrg for (j = 0; j < pipe->num_cons; ++j) { 1618fe517fc9Smrg printf("%s, ", pipe->cons[j]); 161987bf8e7cSmrg if (dev->use_atomic) 162087bf8e7cSmrg add_property(dev, pipe->con_ids[j], "CRTC_ID", pipe->crtc_id); 162187bf8e7cSmrg } 162287bf8e7cSmrg printf("crtc %d\n", pipe->crtc_id); 1623e88f27b3Smrg 162487bf8e7cSmrg if (!dev->use_atomic) { 162587bf8e7cSmrg ret = drmModeSetCrtc(dev->fd, pipe->crtc_id, dev->mode.fb_id, 162687bf8e7cSmrg x, 0, pipe->con_ids, pipe->num_cons, 162787bf8e7cSmrg pipe->mode); 1628e88f27b3Smrg 162987bf8e7cSmrg /* XXX: Actually check if this is needed */ 163087bf8e7cSmrg drmModeDirtyFB(dev->fd, dev->mode.fb_id, NULL, 0); 163118210155Smrg 163287bf8e7cSmrg if (!preferred) 163387bf8e7cSmrg x += pipe->mode->hdisplay; 163418210155Smrg 163587bf8e7cSmrg if (ret) { 163687bf8e7cSmrg fprintf(stderr, "failed to set mode: %s\n", strerror(errno)); 163787bf8e7cSmrg return; 163887bf8e7cSmrg } 163987bf8e7cSmrg 164087bf8e7cSmrg set_gamma(dev, pipe->crtc_id, pipe->fourcc); 164187bf8e7cSmrg } else { 164287bf8e7cSmrg drmModeCreatePropertyBlob(dev->fd, pipe->mode, sizeof(*pipe->mode), &blob_id); 164387bf8e7cSmrg add_property(dev, pipe->crtc_id, "MODE_ID", blob_id); 164487bf8e7cSmrg add_property(dev, pipe->crtc_id, "ACTIVE", 1); 164587bf8e7cSmrg 164687bf8e7cSmrg /* By default atomic modeset does not set a primary plane, shrug */ 164787bf8e7cSmrg if (preferred) { 164887bf8e7cSmrg struct plane *plane = get_primary_plane_by_crtc(dev, pipe->crtc); 164987bf8e7cSmrg struct plane_arg plane_args = { 165087bf8e7cSmrg .plane_id = plane->plane->plane_id, 165187bf8e7cSmrg .crtc_id = pipe->crtc_id, 165287bf8e7cSmrg .w = pipe->mode->hdisplay, 165387bf8e7cSmrg .h = pipe->mode->vdisplay, 165487bf8e7cSmrg .scale = 1.0, 165587bf8e7cSmrg .format_str = "XR24", 165687bf8e7cSmrg .fourcc = util_format_fourcc(pipe->format_str), 165787bf8e7cSmrg }; 165887bf8e7cSmrg 165987bf8e7cSmrg atomic_set_planes(dev, &plane_args, 1, false); 166087bf8e7cSmrg } 166118210155Smrg } 166287bf8e7cSmrg } 166387bf8e7cSmrg} 166487bf8e7cSmrg 166587bf8e7cSmrgstatic void atomic_clear_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count) 166687bf8e7cSmrg{ 166787bf8e7cSmrg unsigned int i; 166887bf8e7cSmrg unsigned int j; 166987bf8e7cSmrg 167087bf8e7cSmrg for (i = 0; i < count; i++) { 167187bf8e7cSmrg struct pipe_arg *pipe = &pipes[i]; 1672bf6cc7dcSmrg 167387bf8e7cSmrg if (pipe->mode == NULL) 167487bf8e7cSmrg continue; 167587bf8e7cSmrg 167687bf8e7cSmrg for (j = 0; j < pipe->num_cons; ++j) 167787bf8e7cSmrg add_property(dev, pipe->con_ids[j], "CRTC_ID",0); 167887bf8e7cSmrg 167987bf8e7cSmrg add_property(dev, pipe->crtc_id, "MODE_ID", 0); 168087bf8e7cSmrg add_property(dev, pipe->crtc_id, "ACTIVE", 0); 168118210155Smrg } 1682424e9256Smrg} 168322944501Smrg 1684424e9256Smrgstatic void clear_mode(struct device *dev) 1685424e9256Smrg{ 1686424e9256Smrg if (dev->mode.fb_id) 1687424e9256Smrg drmModeRmFB(dev->fd, dev->mode.fb_id); 1688424e9256Smrg if (dev->mode.bo) 1689424e9256Smrg bo_destroy(dev->mode.bo); 1690e88f27b3Smrg} 169122944501Smrg 1692e88f27b3Smrgstatic void set_planes(struct device *dev, struct plane_arg *p, unsigned int count) 1693e88f27b3Smrg{ 1694e88f27b3Smrg unsigned int i; 1695e88f27b3Smrg 1696e88f27b3Smrg /* set up planes/overlays */ 1697e88f27b3Smrg for (i = 0; i < count; i++) 1698e88f27b3Smrg if (set_plane(dev, &p[i])) 1699e88f27b3Smrg return; 1700e88f27b3Smrg} 1701e88f27b3Smrg 1702a7d7de1eSmrgstatic void set_cursors(struct device *dev, struct pipe_arg *pipes, unsigned int count) 1703a7d7de1eSmrg{ 1704424e9256Smrg uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0}; 1705adfa0b0cSmrg uint32_t cw = 64; 1706adfa0b0cSmrg uint32_t ch = 64; 17073c748557Ssnj struct bo *bo; 1708adfa0b0cSmrg uint64_t value; 1709a7d7de1eSmrg unsigned int i; 1710a7d7de1eSmrg int ret; 1711a7d7de1eSmrg 1712adfa0b0cSmrg ret = drmGetCap(dev->fd, DRM_CAP_CURSOR_WIDTH, &value); 1713adfa0b0cSmrg if (!ret) 1714adfa0b0cSmrg cw = value; 1715adfa0b0cSmrg 1716adfa0b0cSmrg ret = drmGetCap(dev->fd, DRM_CAP_CURSOR_HEIGHT, &value); 1717adfa0b0cSmrg if (!ret) 1718adfa0b0cSmrg ch = value; 1719adfa0b0cSmrg 1720a7d7de1eSmrg 1721a7d7de1eSmrg /* create cursor bo.. just using PATTERN_PLAIN as it has 1722a7d7de1eSmrg * translucent alpha 1723a7d7de1eSmrg */ 17243c748557Ssnj bo = bo_create(dev->fd, DRM_FORMAT_ARGB8888, cw, ch, handles, pitches, 1725fe517fc9Smrg offsets, UTIL_PATTERN_PLAIN); 1726a7d7de1eSmrg if (bo == NULL) 1727a7d7de1eSmrg return; 1728a7d7de1eSmrg 1729424e9256Smrg dev->mode.cursor_bo = bo; 1730424e9256Smrg 1731a7d7de1eSmrg for (i = 0; i < count; i++) { 1732a7d7de1eSmrg struct pipe_arg *pipe = &pipes[i]; 1733a7d7de1eSmrg ret = cursor_init(dev->fd, handles[0], 173487bf8e7cSmrg pipe->crtc_id, 1735a7d7de1eSmrg pipe->mode->hdisplay, pipe->mode->vdisplay, 1736a7d7de1eSmrg cw, ch); 1737a7d7de1eSmrg if (ret) { 1738a7d7de1eSmrg fprintf(stderr, "failed to init cursor for CRTC[%u]\n", 1739a7d7de1eSmrg pipe->crtc_id); 1740a7d7de1eSmrg return; 1741a7d7de1eSmrg } 1742a7d7de1eSmrg } 1743a7d7de1eSmrg 1744a7d7de1eSmrg cursor_start(); 1745a7d7de1eSmrg} 1746a7d7de1eSmrg 1747a7d7de1eSmrgstatic void clear_cursors(struct device *dev) 1748a7d7de1eSmrg{ 1749a7d7de1eSmrg cursor_stop(); 1750424e9256Smrg 1751424e9256Smrg if (dev->mode.cursor_bo) 1752424e9256Smrg bo_destroy(dev->mode.cursor_bo); 1753a7d7de1eSmrg} 1754a7d7de1eSmrg 1755e88f27b3Smrgstatic void test_page_flip(struct device *dev, struct pipe_arg *pipes, unsigned int count) 1756e88f27b3Smrg{ 1757e88f27b3Smrg unsigned int other_fb_id; 17583c748557Ssnj struct bo *other_bo; 1759e88f27b3Smrg drmEventContext evctx; 1760e88f27b3Smrg unsigned int i; 1761e88f27b3Smrg int ret; 1762e88f27b3Smrg 176387bf8e7cSmrg if (bo_fb_create(dev->fd, pipes[0].fourcc, dev->mode.width, dev->mode.height, 176487bf8e7cSmrg UTIL_PATTERN_PLAIN, &other_bo, &other_fb_id)) 176522944501Smrg return; 176622944501Smrg 176722944501Smrg for (i = 0; i < count; i++) { 1768e88f27b3Smrg struct pipe_arg *pipe = &pipes[i]; 1769e88f27b3Smrg 1770e88f27b3Smrg if (pipe->mode == NULL) 177122944501Smrg continue; 177222944501Smrg 177387bf8e7cSmrg ret = drmModePageFlip(dev->fd, pipe->crtc_id, 1774e88f27b3Smrg other_fb_id, DRM_MODE_PAGE_FLIP_EVENT, 1775e88f27b3Smrg pipe); 1776e88f27b3Smrg if (ret) { 1777e88f27b3Smrg fprintf(stderr, "failed to page flip: %s\n", strerror(errno)); 1778424e9256Smrg goto err_rmfb; 1779e88f27b3Smrg } 1780e88f27b3Smrg gettimeofday(&pipe->start, NULL); 1781e88f27b3Smrg pipe->swap_count = 0; 1782e88f27b3Smrg pipe->fb_id[0] = dev->mode.fb_id; 1783e88f27b3Smrg pipe->fb_id[1] = other_fb_id; 1784e88f27b3Smrg pipe->current_fb_id = other_fb_id; 178522944501Smrg } 178622944501Smrg 178722944501Smrg memset(&evctx, 0, sizeof evctx); 178822944501Smrg evctx.version = DRM_EVENT_CONTEXT_VERSION; 178922944501Smrg evctx.vblank_handler = NULL; 179022944501Smrg evctx.page_flip_handler = page_flip_handler; 1791fe517fc9Smrg 179222944501Smrg while (1) { 179322944501Smrg#if 0 179422944501Smrg struct pollfd pfd[2]; 179522944501Smrg 179622944501Smrg pfd[0].fd = 0; 179722944501Smrg pfd[0].events = POLLIN; 179822944501Smrg pfd[1].fd = fd; 179922944501Smrg pfd[1].events = POLLIN; 180022944501Smrg 180122944501Smrg if (poll(pfd, 2, -1) < 0) { 180222944501Smrg fprintf(stderr, "poll error\n"); 180322944501Smrg break; 180422944501Smrg } 180522944501Smrg 180622944501Smrg if (pfd[0].revents) 180722944501Smrg break; 180822944501Smrg#else 180922944501Smrg struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 }; 181022944501Smrg fd_set fds; 181122944501Smrg 181222944501Smrg FD_ZERO(&fds); 181322944501Smrg FD_SET(0, &fds); 1814e88f27b3Smrg FD_SET(dev->fd, &fds); 1815e88f27b3Smrg ret = select(dev->fd + 1, &fds, NULL, NULL, &timeout); 181622944501Smrg 181722944501Smrg if (ret <= 0) { 181822944501Smrg fprintf(stderr, "select timed out or error (ret %d)\n", 181922944501Smrg ret); 182022944501Smrg continue; 182122944501Smrg } else if (FD_ISSET(0, &fds)) { 182222944501Smrg break; 182322944501Smrg } 182422944501Smrg#endif 182522944501Smrg 1826e88f27b3Smrg drmHandleEvent(dev->fd, &evctx); 182722944501Smrg } 1828e88f27b3Smrg 1829424e9256Smrgerr_rmfb: 1830424e9256Smrg drmModeRmFB(dev->fd, other_fb_id); 18313c748557Ssnj bo_destroy(other_bo); 183218210155Smrg} 183318210155Smrg 1834e88f27b3Smrg#define min(a, b) ((a) < (b) ? (a) : (b)) 183518210155Smrg 1836e88f27b3Smrgstatic int parse_connector(struct pipe_arg *pipe, const char *arg) 183718210155Smrg{ 1838e88f27b3Smrg unsigned int len; 1839e88f27b3Smrg unsigned int i; 1840e88f27b3Smrg const char *p; 1841e88f27b3Smrg char *endp; 1842e88f27b3Smrg 1843e88f27b3Smrg pipe->vrefresh = 0; 1844e88f27b3Smrg pipe->crtc_id = (uint32_t)-1; 1845e88f27b3Smrg strcpy(pipe->format_str, "XR24"); 1846e88f27b3Smrg 1847e88f27b3Smrg /* Count the number of connectors and allocate them. */ 1848e88f27b3Smrg pipe->num_cons = 1; 1849fe517fc9Smrg for (p = arg; *p && *p != ':' && *p != '@'; ++p) { 1850e88f27b3Smrg if (*p == ',') 1851e88f27b3Smrg pipe->num_cons++; 1852e88f27b3Smrg } 1853e88f27b3Smrg 1854424e9256Smrg pipe->con_ids = calloc(pipe->num_cons, sizeof(*pipe->con_ids)); 1855fe517fc9Smrg pipe->cons = calloc(pipe->num_cons, sizeof(*pipe->cons)); 1856fe517fc9Smrg if (pipe->con_ids == NULL || pipe->cons == NULL) 1857e88f27b3Smrg return -1; 1858e88f27b3Smrg 1859e88f27b3Smrg /* Parse the connectors. */ 1860e88f27b3Smrg for (i = 0, p = arg; i < pipe->num_cons; ++i, p = endp + 1) { 1861fe517fc9Smrg endp = strpbrk(p, ",@:"); 1862fe517fc9Smrg if (!endp) 1863fe517fc9Smrg break; 1864fe517fc9Smrg 1865fe517fc9Smrg pipe->cons[i] = strndup(p, endp - p); 1866fe517fc9Smrg 1867e88f27b3Smrg if (*endp != ',') 1868e88f27b3Smrg break; 1869e88f27b3Smrg } 1870e88f27b3Smrg 1871e88f27b3Smrg if (i != pipe->num_cons - 1) 1872e88f27b3Smrg return -1; 1873e88f27b3Smrg 1874e88f27b3Smrg /* Parse the remaining parameters. */ 187587bf8e7cSmrg if (!endp) 187687bf8e7cSmrg return -1; 1877e88f27b3Smrg if (*endp == '@') { 1878e88f27b3Smrg arg = endp + 1; 1879e88f27b3Smrg pipe->crtc_id = strtoul(arg, &endp, 10); 1880e88f27b3Smrg } 1881e88f27b3Smrg if (*endp != ':') 1882e88f27b3Smrg return -1; 1883e88f27b3Smrg 1884e88f27b3Smrg arg = endp + 1; 1885e88f27b3Smrg 1886e88f27b3Smrg /* Search for the vertical refresh or the format. */ 1887e88f27b3Smrg p = strpbrk(arg, "-@"); 1888e88f27b3Smrg if (p == NULL) 1889e88f27b3Smrg p = arg + strlen(arg); 1890e88f27b3Smrg len = min(sizeof pipe->mode_str - 1, (unsigned int)(p - arg)); 1891e88f27b3Smrg strncpy(pipe->mode_str, arg, len); 1892e88f27b3Smrg pipe->mode_str[len] = '\0'; 1893e88f27b3Smrg 1894e88f27b3Smrg if (*p == '-') { 189587bf8e7cSmrg pipe->vrefresh = strtof(p + 1, &endp); 1896e88f27b3Smrg p = endp; 1897e88f27b3Smrg } 1898e88f27b3Smrg 1899e88f27b3Smrg if (*p == '@') { 1900e88f27b3Smrg strncpy(pipe->format_str, p + 1, 4); 1901e88f27b3Smrg pipe->format_str[4] = '\0'; 1902e88f27b3Smrg } 1903e88f27b3Smrg 1904fe517fc9Smrg pipe->fourcc = util_format_fourcc(pipe->format_str); 1905e88f27b3Smrg if (pipe->fourcc == 0) { 1906e88f27b3Smrg fprintf(stderr, "unknown format %s\n", pipe->format_str); 1907e88f27b3Smrg return -1; 1908e88f27b3Smrg } 1909e88f27b3Smrg 1910e88f27b3Smrg return 0; 1911e88f27b3Smrg} 1912e88f27b3Smrg 1913e88f27b3Smrgstatic int parse_plane(struct plane_arg *plane, const char *p) 1914e88f27b3Smrg{ 1915e88f27b3Smrg char *end; 1916e88f27b3Smrg 19172ee35494Smrg plane->plane_id = strtoul(p, &end, 10); 19182ee35494Smrg if (*end != '@') 19192ee35494Smrg return -EINVAL; 19202ee35494Smrg 19212ee35494Smrg p = end + 1; 1922e88f27b3Smrg plane->crtc_id = strtoul(p, &end, 10); 1923e88f27b3Smrg if (*end != ':') 1924e88f27b3Smrg return -EINVAL; 1925e88f27b3Smrg 1926e88f27b3Smrg p = end + 1; 1927e88f27b3Smrg plane->w = strtoul(p, &end, 10); 1928e88f27b3Smrg if (*end != 'x') 1929e88f27b3Smrg return -EINVAL; 1930e88f27b3Smrg 1931e88f27b3Smrg p = end + 1; 1932e88f27b3Smrg plane->h = strtoul(p, &end, 10); 1933e88f27b3Smrg 1934e88f27b3Smrg if (*end == '+' || *end == '-') { 1935e88f27b3Smrg plane->x = strtol(end, &end, 10); 1936e88f27b3Smrg if (*end != '+' && *end != '-') 1937e88f27b3Smrg return -EINVAL; 1938e88f27b3Smrg plane->y = strtol(end, &end, 10); 1939e88f27b3Smrg 1940e88f27b3Smrg plane->has_position = true; 1941e88f27b3Smrg } 1942e88f27b3Smrg 1943e88f27b3Smrg if (*end == '*') { 1944e88f27b3Smrg p = end + 1; 1945e88f27b3Smrg plane->scale = strtod(p, &end); 1946e88f27b3Smrg if (plane->scale <= 0.0) 1947e88f27b3Smrg return -EINVAL; 1948e88f27b3Smrg } else { 1949e88f27b3Smrg plane->scale = 1.0; 1950e88f27b3Smrg } 1951e88f27b3Smrg 1952e88f27b3Smrg if (*end == '@') { 1953bf6cc7dcSmrg strncpy(plane->format_str, end + 1, 4); 1954bf6cc7dcSmrg plane->format_str[4] = '\0'; 1955e88f27b3Smrg } else { 1956e88f27b3Smrg strcpy(plane->format_str, "XR24"); 1957e88f27b3Smrg } 1958e88f27b3Smrg 1959fe517fc9Smrg plane->fourcc = util_format_fourcc(plane->format_str); 1960e88f27b3Smrg if (plane->fourcc == 0) { 1961e88f27b3Smrg fprintf(stderr, "unknown format %s\n", plane->format_str); 1962e88f27b3Smrg return -EINVAL; 1963e88f27b3Smrg } 1964e88f27b3Smrg 1965e88f27b3Smrg return 0; 1966e88f27b3Smrg} 1967e88f27b3Smrg 1968e88f27b3Smrgstatic int parse_property(struct property_arg *p, const char *arg) 1969e88f27b3Smrg{ 1970e88f27b3Smrg if (sscanf(arg, "%d:%32[^:]:%" SCNu64, &p->obj_id, p->name, &p->value) != 3) 1971e88f27b3Smrg return -1; 1972e88f27b3Smrg 1973e88f27b3Smrg p->obj_type = 0; 1974e88f27b3Smrg p->name[DRM_PROP_NAME_LEN] = '\0'; 1975e88f27b3Smrg 1976e88f27b3Smrg return 0; 1977e88f27b3Smrg} 1978e88f27b3Smrg 1979bf6cc7dcSmrgstatic void parse_fill_patterns(char *arg) 1980bf6cc7dcSmrg{ 1981bf6cc7dcSmrg char *fill = strtok(arg, ","); 1982bf6cc7dcSmrg if (!fill) 1983bf6cc7dcSmrg return; 1984bf6cc7dcSmrg primary_fill = util_pattern_enum(fill); 1985bf6cc7dcSmrg fill = strtok(NULL, ","); 1986bf6cc7dcSmrg if (!fill) 1987bf6cc7dcSmrg return; 1988bf6cc7dcSmrg secondary_fill = util_pattern_enum(fill); 1989bf6cc7dcSmrg} 1990bf6cc7dcSmrg 1991e88f27b3Smrgstatic void usage(char *name) 1992e88f27b3Smrg{ 199387bf8e7cSmrg fprintf(stderr, "usage: %s [-acDdefMPpsCvrw]\n", name); 1994e88f27b3Smrg 1995e88f27b3Smrg fprintf(stderr, "\n Query options:\n\n"); 199618210155Smrg fprintf(stderr, "\t-c\tlist connectors\n"); 1997e88f27b3Smrg fprintf(stderr, "\t-e\tlist encoders\n"); 199818210155Smrg fprintf(stderr, "\t-f\tlist framebuffers\n"); 1999e88f27b3Smrg fprintf(stderr, "\t-p\tlist CRTCs and planes (pipes)\n"); 2000e88f27b3Smrg 2001e88f27b3Smrg fprintf(stderr, "\n Test options:\n\n"); 20022ee35494Smrg fprintf(stderr, "\t-P <plane_id>@<crtc_id>:<w>x<h>[+<x>+<y>][*<scale>][@<format>]\tset a plane\n"); 200387bf8e7cSmrg fprintf(stderr, "\t-s <connector_id>[,<connector_id>][@<crtc_id>]:[#<mode index>]<mode>[-<vrefresh>][@<format>]\tset a mode\n"); 2004a7d7de1eSmrg fprintf(stderr, "\t-C\ttest hw cursor\n"); 200522944501Smrg fprintf(stderr, "\t-v\ttest vsynced page flipping\n"); 200687bf8e7cSmrg fprintf(stderr, "\t-r\tset the preferred mode for all connectors\n"); 2007e88f27b3Smrg fprintf(stderr, "\t-w <obj_id>:<prop_name>:<value>\tset property\n"); 20086260e5d5Smrg fprintf(stderr, "\t-a \tuse atomic API\n"); 2009bf6cc7dcSmrg fprintf(stderr, "\t-F pattern1,pattern2\tspecify fill patterns\n"); 2010e88f27b3Smrg 2011e88f27b3Smrg fprintf(stderr, "\n Generic options:\n\n"); 2012e88f27b3Smrg fprintf(stderr, "\t-d\tdrop master after mode set\n"); 2013e88f27b3Smrg fprintf(stderr, "\t-M module\tuse the given driver\n"); 2014e88f27b3Smrg fprintf(stderr, "\t-D device\tuse the given device\n"); 2015e88f27b3Smrg 201618210155Smrg fprintf(stderr, "\n\tDefault is to dump all info.\n"); 201718210155Smrg exit(0); 201818210155Smrg} 201918210155Smrg 202087bf8e7cSmrgstatic char optstr[] = "acdD:efF:M:P:ps:Cvrw:"; 2021e88f27b3Smrg 202218210155Smrgint main(int argc, char **argv) 202318210155Smrg{ 2024e88f27b3Smrg struct device dev; 2025e88f27b3Smrg 202618210155Smrg int c; 2027e88f27b3Smrg int encoders = 0, connectors = 0, crtcs = 0, planes = 0, framebuffers = 0; 2028e88f27b3Smrg int drop_master = 0; 202922944501Smrg int test_vsync = 0; 2030a7d7de1eSmrg int test_cursor = 0; 203187bf8e7cSmrg int set_preferred = 0; 20326260e5d5Smrg int use_atomic = 0; 2033e88f27b3Smrg char *device = NULL; 2034e88f27b3Smrg char *module = NULL; 2035e88f27b3Smrg unsigned int i; 2036fe517fc9Smrg unsigned int count = 0, plane_count = 0; 2037e88f27b3Smrg unsigned int prop_count = 0; 2038e88f27b3Smrg struct pipe_arg *pipe_args = NULL; 2039e88f27b3Smrg struct plane_arg *plane_args = NULL; 2040e88f27b3Smrg struct property_arg *prop_args = NULL; 2041e88f27b3Smrg unsigned int args = 0; 2042e88f27b3Smrg int ret; 2043e88f27b3Smrg 2044e88f27b3Smrg memset(&dev, 0, sizeof dev); 2045e88f27b3Smrg 204618210155Smrg opterr = 0; 204718210155Smrg while ((c = getopt(argc, argv, optstr)) != -1) { 2048e88f27b3Smrg args++; 2049e88f27b3Smrg 205018210155Smrg switch (c) { 20516260e5d5Smrg case 'a': 20526260e5d5Smrg use_atomic = 1; 205387bf8e7cSmrg /* Preserve the default behaviour of dumping all information. */ 205487bf8e7cSmrg args--; 20556260e5d5Smrg break; 205618210155Smrg case 'c': 205718210155Smrg connectors = 1; 205818210155Smrg break; 2059e88f27b3Smrg case 'D': 2060e88f27b3Smrg device = optarg; 206187bf8e7cSmrg /* Preserve the default behaviour of dumping all information. */ 2062e88f27b3Smrg args--; 2063e88f27b3Smrg break; 2064e88f27b3Smrg case 'd': 2065e88f27b3Smrg drop_master = 1; 206618210155Smrg break; 2067e88f27b3Smrg case 'e': 2068e88f27b3Smrg encoders = 1; 206918210155Smrg break; 207018210155Smrg case 'f': 207118210155Smrg framebuffers = 1; 207218210155Smrg break; 2073bf6cc7dcSmrg case 'F': 2074bf6cc7dcSmrg parse_fill_patterns(optarg); 2075bf6cc7dcSmrg break; 2076e88f27b3Smrg case 'M': 2077e88f27b3Smrg module = optarg; 2078e88f27b3Smrg /* Preserve the default behaviour of dumping all information. */ 2079e88f27b3Smrg args--; 2080e88f27b3Smrg break; 2081e88f27b3Smrg case 'P': 2082e88f27b3Smrg plane_args = realloc(plane_args, 2083e88f27b3Smrg (plane_count + 1) * sizeof *plane_args); 2084e88f27b3Smrg if (plane_args == NULL) { 2085e88f27b3Smrg fprintf(stderr, "memory allocation failed\n"); 2086e88f27b3Smrg return 1; 2087e88f27b3Smrg } 2088424e9256Smrg memset(&plane_args[plane_count], 0, sizeof(*plane_args)); 2089e88f27b3Smrg 2090e88f27b3Smrg if (parse_plane(&plane_args[plane_count], optarg) < 0) 2091e88f27b3Smrg usage(argv[0]); 2092e88f27b3Smrg 2093e88f27b3Smrg plane_count++; 2094e88f27b3Smrg break; 2095e88f27b3Smrg case 'p': 2096e88f27b3Smrg crtcs = 1; 2097e88f27b3Smrg planes = 1; 209822944501Smrg break; 209918210155Smrg case 's': 2100e88f27b3Smrg pipe_args = realloc(pipe_args, 2101e88f27b3Smrg (count + 1) * sizeof *pipe_args); 2102e88f27b3Smrg if (pipe_args == NULL) { 2103e88f27b3Smrg fprintf(stderr, "memory allocation failed\n"); 2104e88f27b3Smrg return 1; 2105e88f27b3Smrg } 2106424e9256Smrg memset(&pipe_args[count], 0, sizeof(*pipe_args)); 2107e88f27b3Smrg 2108e88f27b3Smrg if (parse_connector(&pipe_args[count], optarg) < 0) 210918210155Smrg usage(argv[0]); 2110e88f27b3Smrg 2111fe517fc9Smrg count++; 211218210155Smrg break; 2113a7d7de1eSmrg case 'C': 2114a7d7de1eSmrg test_cursor = 1; 2115a7d7de1eSmrg break; 2116e88f27b3Smrg case 'v': 2117e88f27b3Smrg test_vsync = 1; 2118e88f27b3Smrg break; 211987bf8e7cSmrg case 'r': 212087bf8e7cSmrg set_preferred = 1; 212187bf8e7cSmrg break; 2122e88f27b3Smrg case 'w': 2123e88f27b3Smrg prop_args = realloc(prop_args, 2124e88f27b3Smrg (prop_count + 1) * sizeof *prop_args); 2125e88f27b3Smrg if (prop_args == NULL) { 2126e88f27b3Smrg fprintf(stderr, "memory allocation failed\n"); 2127e88f27b3Smrg return 1; 2128e88f27b3Smrg } 2129424e9256Smrg memset(&prop_args[prop_count], 0, sizeof(*prop_args)); 2130e88f27b3Smrg 2131e88f27b3Smrg if (parse_property(&prop_args[prop_count], optarg) < 0) 2132e88f27b3Smrg usage(argv[0]); 2133e88f27b3Smrg 2134e88f27b3Smrg prop_count++; 2135e88f27b3Smrg break; 213618210155Smrg default: 213718210155Smrg usage(argv[0]); 213818210155Smrg break; 213918210155Smrg } 214018210155Smrg } 214118210155Smrg 214287bf8e7cSmrg /* Dump all the details when no* arguments are provided. */ 214387bf8e7cSmrg if (!args) 2144e88f27b3Smrg encoders = connectors = crtcs = planes = framebuffers = 1; 214518210155Smrg 214687bf8e7cSmrg if (test_vsync && !count) { 214787bf8e7cSmrg fprintf(stderr, "page flipping requires at least one -s option.\n"); 21486260e5d5Smrg return -1; 21496260e5d5Smrg } 215087bf8e7cSmrg if (set_preferred && count) { 215187bf8e7cSmrg fprintf(stderr, "cannot use -r (preferred) when -s (mode) is set\n"); 215222944501Smrg return -1; 215322944501Smrg } 215422944501Smrg 215587bf8e7cSmrg if (set_preferred && plane_count) { 215687bf8e7cSmrg fprintf(stderr, "cannot use -r (preferred) when -P (plane) is set\n"); 215718210155Smrg return -1; 215818210155Smrg } 215918210155Smrg 216087bf8e7cSmrg dev.fd = util_open(device, module); 216187bf8e7cSmrg if (dev.fd < 0) 2162a7d7de1eSmrg return -1; 216387bf8e7cSmrg 216487bf8e7cSmrg if (use_atomic) { 216587bf8e7cSmrg ret = drmSetClientCap(dev.fd, DRM_CLIENT_CAP_ATOMIC, 1); 216687bf8e7cSmrg if (ret) { 216787bf8e7cSmrg fprintf(stderr, "no atomic modesetting support: %s\n", strerror(errno)); 216887bf8e7cSmrg drmClose(dev.fd); 216987bf8e7cSmrg return -1; 217087bf8e7cSmrg } 2171a7d7de1eSmrg } 2172a7d7de1eSmrg 217387bf8e7cSmrg dev.use_atomic = use_atomic; 217487bf8e7cSmrg 2175e88f27b3Smrg dev.resources = get_resources(&dev); 2176e88f27b3Smrg if (!dev.resources) { 2177e88f27b3Smrg drmClose(dev.fd); 217818210155Smrg return 1; 217918210155Smrg } 218018210155Smrg 2181e88f27b3Smrg#define dump_resource(dev, res) if (res) dump_##res(dev) 2182e88f27b3Smrg 2183e88f27b3Smrg dump_resource(&dev, encoders); 2184e88f27b3Smrg dump_resource(&dev, connectors); 2185e88f27b3Smrg dump_resource(&dev, crtcs); 2186e88f27b3Smrg dump_resource(&dev, planes); 2187e88f27b3Smrg dump_resource(&dev, framebuffers); 2188e88f27b3Smrg 2189e88f27b3Smrg for (i = 0; i < prop_count; ++i) 2190e88f27b3Smrg set_property(&dev, &prop_args[i]); 2191e88f27b3Smrg 21926260e5d5Smrg if (dev.use_atomic) { 21936260e5d5Smrg dev.req = drmModeAtomicAlloc(); 21943c748557Ssnj 219587bf8e7cSmrg if (set_preferred || (count && plane_count)) { 21966260e5d5Smrg uint64_t cap = 0; 21976260e5d5Smrg 21986260e5d5Smrg ret = drmGetCap(dev.fd, DRM_CAP_DUMB_BUFFER, &cap); 21996260e5d5Smrg if (ret || cap == 0) { 22006260e5d5Smrg fprintf(stderr, "driver doesn't support the dumb buffer API\n"); 22016260e5d5Smrg return 1; 22026260e5d5Smrg } 22036260e5d5Smrg 220487bf8e7cSmrg if (set_preferred || count) 220587bf8e7cSmrg set_mode(&dev, pipe_args, count); 220687bf8e7cSmrg 220787bf8e7cSmrg if (plane_count) 220887bf8e7cSmrg atomic_set_planes(&dev, plane_args, plane_count, false); 22096260e5d5Smrg 22106260e5d5Smrg ret = drmModeAtomicCommit(dev.fd, dev.req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL); 22116260e5d5Smrg if (ret) { 22126260e5d5Smrg fprintf(stderr, "Atomic Commit failed [1]\n"); 22136260e5d5Smrg return 1; 22146260e5d5Smrg } 22156260e5d5Smrg 221687bf8e7cSmrg if (test_vsync) 221787bf8e7cSmrg atomic_test_page_flip(&dev, pipe_args, plane_args, plane_count); 22186260e5d5Smrg 22196260e5d5Smrg if (drop_master) 22206260e5d5Smrg drmDropMaster(dev.fd); 22216260e5d5Smrg 22226260e5d5Smrg getchar(); 22236260e5d5Smrg 22246260e5d5Smrg drmModeAtomicFree(dev.req); 22256260e5d5Smrg dev.req = drmModeAtomicAlloc(); 22266260e5d5Smrg 222787bf8e7cSmrg /* XXX: properly teardown the preferred mode/plane state */ 222887bf8e7cSmrg if (plane_count) 222987bf8e7cSmrg atomic_clear_planes(&dev, plane_args, plane_count); 223087bf8e7cSmrg 223187bf8e7cSmrg if (count) 223287bf8e7cSmrg atomic_clear_mode(&dev, pipe_args, count); 223387bf8e7cSmrg 22346260e5d5Smrg ret = drmModeAtomicCommit(dev.fd, dev.req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL); 223587bf8e7cSmrg if (ret) 22366260e5d5Smrg fprintf(stderr, "Atomic Commit failed\n"); 22376260e5d5Smrg 223887bf8e7cSmrg if (plane_count) 223987bf8e7cSmrg atomic_clear_FB(&dev, plane_args, plane_count); 2240e88f27b3Smrg } 2241e88f27b3Smrg 22426260e5d5Smrg drmModeAtomicFree(dev.req); 22436260e5d5Smrg } else { 224487bf8e7cSmrg if (set_preferred || count || plane_count) { 22456260e5d5Smrg uint64_t cap = 0; 22466260e5d5Smrg 22476260e5d5Smrg ret = drmGetCap(dev.fd, DRM_CAP_DUMB_BUFFER, &cap); 22486260e5d5Smrg if (ret || cap == 0) { 22496260e5d5Smrg fprintf(stderr, "driver doesn't support the dumb buffer API\n"); 22506260e5d5Smrg return 1; 22516260e5d5Smrg } 22526260e5d5Smrg 225387bf8e7cSmrg if (set_preferred || count) 22546260e5d5Smrg set_mode(&dev, pipe_args, count); 2255e88f27b3Smrg 22566260e5d5Smrg if (plane_count) 22576260e5d5Smrg set_planes(&dev, plane_args, plane_count); 2258e88f27b3Smrg 22596260e5d5Smrg if (test_cursor) 22606260e5d5Smrg set_cursors(&dev, pipe_args, count); 2261a7d7de1eSmrg 22626260e5d5Smrg if (test_vsync) 22636260e5d5Smrg test_page_flip(&dev, pipe_args, count); 2264e88f27b3Smrg 22656260e5d5Smrg if (drop_master) 22666260e5d5Smrg drmDropMaster(dev.fd); 2267e88f27b3Smrg 22686260e5d5Smrg getchar(); 2269a7d7de1eSmrg 22706260e5d5Smrg if (test_cursor) 22716260e5d5Smrg clear_cursors(&dev); 2272a7d7de1eSmrg 22736260e5d5Smrg if (plane_count) 22746260e5d5Smrg clear_planes(&dev, plane_args, plane_count); 22756260e5d5Smrg 227687bf8e7cSmrg if (set_preferred || count) 22776260e5d5Smrg clear_mode(&dev); 22786260e5d5Smrg } 227918210155Smrg } 228018210155Smrg 2281e88f27b3Smrg free_resources(dev.resources); 228287bf8e7cSmrg drmClose(dev.fd); 228318210155Smrg 228418210155Smrg return 0; 228518210155Smrg} 2286