modetest.c revision 22944501
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 */ 4018210155Smrg#include "config.h" 4118210155Smrg 4218210155Smrg#include <assert.h> 4318210155Smrg#include <stdio.h> 4418210155Smrg#include <stdlib.h> 4518210155Smrg#include <stdint.h> 4618210155Smrg#include <unistd.h> 4718210155Smrg#include <string.h> 4818210155Smrg#include <errno.h> 4922944501Smrg#include <sys/poll.h> 5022944501Smrg#include <sys/time.h> 5118210155Smrg 5218210155Smrg#include "xf86drm.h" 5318210155Smrg#include "xf86drmMode.h" 5418210155Smrg#include "intel_bufmgr.h" 5522944501Smrg#include "i915_drm.h" 5618210155Smrg 5718210155Smrg#ifdef HAVE_CAIRO 5818210155Smrg#include <math.h> 5918210155Smrg#include <cairo.h> 6018210155Smrg#endif 6118210155Smrg 6218210155SmrgdrmModeRes *resources; 6318210155Smrgint fd, modes; 6418210155Smrg 6518210155Smrg#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 6618210155Smrg 6718210155Smrgstruct type_name { 6818210155Smrg int type; 6918210155Smrg char *name; 7018210155Smrg}; 7118210155Smrg 7218210155Smrg#define type_name_fn(res) \ 7318210155Smrgchar * res##_str(int type) { \ 7418210155Smrg int i; \ 7518210155Smrg for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \ 7618210155Smrg if (res##_names[i].type == type) \ 7718210155Smrg return res##_names[i].name; \ 7818210155Smrg } \ 7918210155Smrg return "(invalid)"; \ 8018210155Smrg} 8118210155Smrg 8218210155Smrgstruct type_name encoder_type_names[] = { 8318210155Smrg { DRM_MODE_ENCODER_NONE, "none" }, 8418210155Smrg { DRM_MODE_ENCODER_DAC, "DAC" }, 8518210155Smrg { DRM_MODE_ENCODER_TMDS, "TMDS" }, 8618210155Smrg { DRM_MODE_ENCODER_LVDS, "LVDS" }, 8718210155Smrg { DRM_MODE_ENCODER_TVDAC, "TVDAC" }, 8818210155Smrg}; 8918210155Smrg 9018210155Smrgtype_name_fn(encoder_type) 9118210155Smrg 9218210155Smrgstruct type_name connector_status_names[] = { 9318210155Smrg { DRM_MODE_CONNECTED, "connected" }, 9418210155Smrg { DRM_MODE_DISCONNECTED, "disconnected" }, 9518210155Smrg { DRM_MODE_UNKNOWNCONNECTION, "unknown" }, 9618210155Smrg}; 9718210155Smrg 9818210155Smrgtype_name_fn(connector_status) 9918210155Smrg 10018210155Smrgstruct type_name connector_type_names[] = { 10118210155Smrg { DRM_MODE_CONNECTOR_Unknown, "unknown" }, 10218210155Smrg { DRM_MODE_CONNECTOR_VGA, "VGA" }, 10318210155Smrg { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, 10418210155Smrg { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, 10518210155Smrg { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, 10618210155Smrg { DRM_MODE_CONNECTOR_Composite, "composite" }, 10718210155Smrg { DRM_MODE_CONNECTOR_SVIDEO, "s-video" }, 10818210155Smrg { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, 10918210155Smrg { DRM_MODE_CONNECTOR_Component, "component" }, 11018210155Smrg { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" }, 11118210155Smrg { DRM_MODE_CONNECTOR_DisplayPort, "displayport" }, 11218210155Smrg { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" }, 11318210155Smrg { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" }, 11418210155Smrg}; 11518210155Smrg 11618210155Smrgtype_name_fn(connector_type) 11718210155Smrg 11818210155Smrgvoid dump_encoders(void) 11918210155Smrg{ 12018210155Smrg drmModeEncoder *encoder; 12118210155Smrg int i; 12218210155Smrg 12318210155Smrg printf("Encoders:\n"); 12418210155Smrg printf("id\tcrtc\ttype\tpossible crtcs\tpossible clones\t\n"); 12518210155Smrg for (i = 0; i < resources->count_encoders; i++) { 12618210155Smrg encoder = drmModeGetEncoder(fd, resources->encoders[i]); 12718210155Smrg 12818210155Smrg if (!encoder) { 12918210155Smrg fprintf(stderr, "could not get encoder %i: %s\n", 13018210155Smrg resources->encoders[i], strerror(errno)); 13118210155Smrg continue; 13218210155Smrg } 13318210155Smrg printf("%d\t%d\t%s\t0x%08x\t0x%08x\n", 13418210155Smrg encoder->encoder_id, 13518210155Smrg encoder->crtc_id, 13618210155Smrg encoder_type_str(encoder->encoder_type), 13718210155Smrg encoder->possible_crtcs, 13818210155Smrg encoder->possible_clones); 13918210155Smrg drmModeFreeEncoder(encoder); 14018210155Smrg } 14118210155Smrg printf("\n"); 14218210155Smrg} 14318210155Smrg 14418210155Smrgvoid dump_mode(drmModeModeInfo *mode) 14518210155Smrg{ 14622944501Smrg printf(" %s %d %d %d %d %d %d %d %d %d\n", 14718210155Smrg mode->name, 14822944501Smrg mode->vrefresh, 14918210155Smrg mode->hdisplay, 15018210155Smrg mode->hsync_start, 15118210155Smrg mode->hsync_end, 15218210155Smrg mode->htotal, 15318210155Smrg mode->vdisplay, 15418210155Smrg mode->vsync_start, 15518210155Smrg mode->vsync_end, 15618210155Smrg mode->vtotal); 15718210155Smrg} 15818210155Smrg 15918210155Smrgstatic void 16018210155Smrgdump_props(drmModeConnector *connector) 16118210155Smrg{ 16218210155Smrg drmModePropertyPtr props; 16318210155Smrg int i; 16418210155Smrg 16518210155Smrg for (i = 0; i < connector->count_props; i++) { 16618210155Smrg props = drmModeGetProperty(fd, connector->props[i]); 16718210155Smrg printf("\t%s, flags %d\n", props->name, props->flags); 16818210155Smrg drmModeFreeProperty(props); 16918210155Smrg } 17018210155Smrg} 17118210155Smrg 17218210155Smrgvoid dump_connectors(void) 17318210155Smrg{ 17418210155Smrg drmModeConnector *connector; 17518210155Smrg int i, j; 17618210155Smrg 17718210155Smrg printf("Connectors:\n"); 17822944501Smrg printf("id\tencoder\tstatus\t\ttype\tsize (mm)\tmodes\tencoders\n"); 17918210155Smrg for (i = 0; i < resources->count_connectors; i++) { 18018210155Smrg connector = drmModeGetConnector(fd, resources->connectors[i]); 18118210155Smrg 18218210155Smrg if (!connector) { 18318210155Smrg fprintf(stderr, "could not get connector %i: %s\n", 18418210155Smrg resources->connectors[i], strerror(errno)); 18518210155Smrg continue; 18618210155Smrg } 18718210155Smrg 18822944501Smrg printf("%d\t%d\t%s\t%s\t%dx%d\t\t%d\t", 18918210155Smrg connector->connector_id, 19018210155Smrg connector->encoder_id, 19118210155Smrg connector_status_str(connector->connection), 19218210155Smrg connector_type_str(connector->connector_type), 19318210155Smrg connector->mmWidth, connector->mmHeight, 19418210155Smrg connector->count_modes); 19518210155Smrg 19622944501Smrg for (j = 0; j < connector->count_encoders; j++) 19722944501Smrg printf("%s%d", j > 0 ? ", " : "", connector->encoders[j]); 19822944501Smrg printf("\n"); 19922944501Smrg 20018210155Smrg if (!connector->count_modes) 20118210155Smrg continue; 20218210155Smrg 20318210155Smrg printf(" modes:\n"); 20418210155Smrg printf(" name refresh (Hz) hdisp hss hse htot vdisp " 20518210155Smrg "vss vse vtot)\n"); 20618210155Smrg for (j = 0; j < connector->count_modes; j++) 20718210155Smrg dump_mode(&connector->modes[j]); 20818210155Smrg 20918210155Smrg printf(" props:\n"); 21018210155Smrg dump_props(connector); 21122944501Smrg 21222944501Smrg drmModeFreeConnector(connector); 21318210155Smrg } 21418210155Smrg printf("\n"); 21518210155Smrg} 21618210155Smrg 21718210155Smrgvoid dump_crtcs(void) 21818210155Smrg{ 21918210155Smrg drmModeCrtc *crtc; 22018210155Smrg int i; 22118210155Smrg 22218210155Smrg printf("CRTCs:\n"); 22318210155Smrg printf("id\tfb\tpos\tsize\n"); 22418210155Smrg for (i = 0; i < resources->count_crtcs; i++) { 22518210155Smrg crtc = drmModeGetCrtc(fd, resources->crtcs[i]); 22618210155Smrg 22718210155Smrg if (!crtc) { 22818210155Smrg fprintf(stderr, "could not get crtc %i: %s\n", 22918210155Smrg resources->crtcs[i], strerror(errno)); 23018210155Smrg continue; 23118210155Smrg } 23218210155Smrg printf("%d\t%d\t(%d,%d)\t(%dx%d)\n", 23318210155Smrg crtc->crtc_id, 23418210155Smrg crtc->buffer_id, 23518210155Smrg crtc->x, crtc->y, 23618210155Smrg crtc->width, crtc->height); 23718210155Smrg dump_mode(&crtc->mode); 23818210155Smrg 23918210155Smrg drmModeFreeCrtc(crtc); 24018210155Smrg } 24118210155Smrg printf("\n"); 24218210155Smrg} 24318210155Smrg 24418210155Smrgvoid dump_framebuffers(void) 24518210155Smrg{ 24618210155Smrg drmModeFB *fb; 24718210155Smrg int i; 24818210155Smrg 24918210155Smrg printf("Frame buffers:\n"); 25018210155Smrg printf("id\tsize\tpitch\n"); 25118210155Smrg for (i = 0; i < resources->count_fbs; i++) { 25218210155Smrg fb = drmModeGetFB(fd, resources->fbs[i]); 25318210155Smrg 25418210155Smrg if (!fb) { 25518210155Smrg fprintf(stderr, "could not get fb %i: %s\n", 25618210155Smrg resources->fbs[i], strerror(errno)); 25718210155Smrg continue; 25818210155Smrg } 25922944501Smrg printf("%u\t(%ux%u)\t%u\n", 26018210155Smrg fb->fb_id, 26122944501Smrg fb->width, fb->height, 26222944501Smrg fb->pitch); 26318210155Smrg 26418210155Smrg drmModeFreeFB(fb); 26518210155Smrg } 26618210155Smrg printf("\n"); 26718210155Smrg} 26818210155Smrg 26918210155Smrg/* 27018210155Smrg * Mode setting with the kernel interfaces is a bit of a chore. 27118210155Smrg * First you have to find the connector in question and make sure the 27218210155Smrg * requested mode is available. 27318210155Smrg * Then you need to find the encoder attached to that connector so you 27418210155Smrg * can bind it with a free crtc. 27518210155Smrg */ 27618210155Smrgstruct connector { 27722944501Smrg uint32_t id; 27818210155Smrg char mode_str[64]; 27918210155Smrg drmModeModeInfo *mode; 28018210155Smrg drmModeEncoder *encoder; 28118210155Smrg int crtc; 28222944501Smrg unsigned int fb_id[2], current_fb_id; 28322944501Smrg struct timeval start; 28422944501Smrg 28522944501Smrg int swap_count; 28618210155Smrg}; 28718210155Smrg 28818210155Smrgstatic void 28918210155Smrgconnector_find_mode(struct connector *c) 29018210155Smrg{ 29118210155Smrg drmModeConnector *connector; 29222944501Smrg int i, j; 29318210155Smrg 29418210155Smrg /* First, find the connector & mode */ 29518210155Smrg c->mode = NULL; 29618210155Smrg for (i = 0; i < resources->count_connectors; i++) { 29718210155Smrg connector = drmModeGetConnector(fd, resources->connectors[i]); 29818210155Smrg 29918210155Smrg if (!connector) { 30018210155Smrg fprintf(stderr, "could not get connector %i: %s\n", 30118210155Smrg resources->connectors[i], strerror(errno)); 30218210155Smrg drmModeFreeConnector(connector); 30318210155Smrg continue; 30418210155Smrg } 30518210155Smrg 30618210155Smrg if (!connector->count_modes) { 30718210155Smrg drmModeFreeConnector(connector); 30818210155Smrg continue; 30918210155Smrg } 31018210155Smrg 31118210155Smrg if (connector->connector_id != c->id) { 31218210155Smrg drmModeFreeConnector(connector); 31318210155Smrg continue; 31418210155Smrg } 31518210155Smrg 31618210155Smrg for (j = 0; j < connector->count_modes; j++) { 31718210155Smrg c->mode = &connector->modes[j]; 31818210155Smrg if (!strcmp(c->mode->name, c->mode_str)) 31918210155Smrg break; 32018210155Smrg } 32118210155Smrg 32218210155Smrg /* Found it, break out */ 32318210155Smrg if (c->mode) 32418210155Smrg break; 32518210155Smrg 32618210155Smrg drmModeFreeConnector(connector); 32718210155Smrg } 32818210155Smrg 32918210155Smrg if (!c->mode) { 33018210155Smrg fprintf(stderr, "failed to find mode \"%s\"\n", c->mode_str); 33118210155Smrg return; 33218210155Smrg } 33318210155Smrg 33418210155Smrg /* Now get the encoder */ 33518210155Smrg for (i = 0; i < resources->count_encoders; i++) { 33618210155Smrg c->encoder = drmModeGetEncoder(fd, resources->encoders[i]); 33718210155Smrg 33818210155Smrg if (!c->encoder) { 33918210155Smrg fprintf(stderr, "could not get encoder %i: %s\n", 34018210155Smrg resources->encoders[i], strerror(errno)); 34118210155Smrg drmModeFreeEncoder(c->encoder); 34218210155Smrg continue; 34318210155Smrg } 34418210155Smrg 34518210155Smrg if (c->encoder->encoder_id == connector->encoder_id) 34618210155Smrg break; 34718210155Smrg 34818210155Smrg drmModeFreeEncoder(c->encoder); 34918210155Smrg } 35018210155Smrg 35118210155Smrg if (c->crtc == -1) 35218210155Smrg c->crtc = c->encoder->crtc_id; 35318210155Smrg} 35418210155Smrg 35518210155Smrg#ifdef HAVE_CAIRO 35618210155Smrg 35718210155Smrgstatic int 35818210155Smrgcreate_test_buffer(drm_intel_bufmgr *bufmgr, 35918210155Smrg int width, int height, int *stride_out, drm_intel_bo **bo_out) 36018210155Smrg{ 36118210155Smrg drm_intel_bo *bo; 36218210155Smrg unsigned int *fb_ptr; 36322944501Smrg int size, i, stride; 36418210155Smrg div_t d; 36518210155Smrg cairo_surface_t *surface; 36618210155Smrg cairo_t *cr; 36718210155Smrg char buf[64]; 36818210155Smrg int x, y; 36918210155Smrg 37018210155Smrg surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); 37118210155Smrg stride = cairo_image_surface_get_stride(surface); 37218210155Smrg size = stride * height; 37318210155Smrg fb_ptr = (unsigned int *) cairo_image_surface_get_data(surface); 37418210155Smrg 37518210155Smrg /* paint the buffer with colored tiles */ 37618210155Smrg for (i = 0; i < width * height; i++) { 37718210155Smrg d = div(i, width); 37818210155Smrg fb_ptr[i] = 0x00130502 * (d.quot >> 6) + 0x000a1120 * (d.rem >> 6); 37918210155Smrg } 38018210155Smrg 38118210155Smrg cr = cairo_create(surface); 38218210155Smrg cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE); 38318210155Smrg for (x = 0; x < width; x += 250) 38418210155Smrg for (y = 0; y < height; y += 250) { 38518210155Smrg cairo_set_operator(cr, CAIRO_OPERATOR_OVER); 38618210155Smrg cairo_move_to(cr, x, y - 20); 38718210155Smrg cairo_line_to(cr, x, y + 20); 38818210155Smrg cairo_move_to(cr, x - 20, y); 38918210155Smrg cairo_line_to(cr, x + 20, y); 39018210155Smrg cairo_new_sub_path(cr); 39118210155Smrg cairo_arc(cr, x, y, 10, 0, M_PI * 2); 39218210155Smrg cairo_set_line_width(cr, 4); 39318210155Smrg cairo_set_source_rgb(cr, 0, 0, 0); 39418210155Smrg cairo_stroke_preserve(cr); 39518210155Smrg cairo_set_source_rgb(cr, 1, 1, 1); 39618210155Smrg cairo_set_line_width(cr, 2); 39718210155Smrg cairo_stroke(cr); 39818210155Smrg snprintf(buf, sizeof buf, "%d, %d", x, y); 39918210155Smrg cairo_move_to(cr, x + 20, y + 20); 40018210155Smrg cairo_text_path(cr, buf); 40118210155Smrg cairo_set_source_rgb(cr, 0, 0, 0); 40218210155Smrg cairo_stroke_preserve(cr); 40318210155Smrg cairo_set_source_rgb(cr, 1, 1, 1); 40418210155Smrg cairo_fill(cr); 40518210155Smrg } 40618210155Smrg 40718210155Smrg cairo_destroy(cr); 40818210155Smrg 40918210155Smrg bo = drm_intel_bo_alloc(bufmgr, "frontbuffer", size, 4096); 41018210155Smrg if (!bo) { 41118210155Smrg fprintf(stderr, "failed to alloc buffer: %s\n", 41218210155Smrg strerror(errno)); 41318210155Smrg return -1; 41418210155Smrg } 41518210155Smrg 41618210155Smrg drm_intel_bo_subdata(bo, 0, size, fb_ptr); 41718210155Smrg 41818210155Smrg cairo_surface_destroy(surface); 41918210155Smrg 42018210155Smrg *bo_out = bo; 42118210155Smrg *stride_out = stride; 42218210155Smrg 42318210155Smrg return 0; 42418210155Smrg} 42518210155Smrg 42618210155Smrg#else 42718210155Smrg 42818210155Smrgstatic int 42918210155Smrgcreate_test_buffer(drm_intel_bufmgr *bufmgr, 43018210155Smrg int width, int height, int *stride_out, drm_intel_bo **bo_out) 43118210155Smrg{ 43218210155Smrg drm_intel_bo *bo; 43318210155Smrg unsigned int *fb_ptr; 43418210155Smrg int size, ret, i, stride; 43518210155Smrg div_t d; 43618210155Smrg 43718210155Smrg /* Mode size at 32 bpp */ 43818210155Smrg stride = width * 4; 43918210155Smrg size = stride * height; 44018210155Smrg 44118210155Smrg bo = drm_intel_bo_alloc(bufmgr, "frontbuffer", size, 4096); 44218210155Smrg if (!bo) { 44318210155Smrg fprintf(stderr, "failed to alloc buffer: %s\n", 44418210155Smrg strerror(errno)); 44518210155Smrg return -1; 44618210155Smrg } 44718210155Smrg 44818210155Smrg ret = drm_intel_gem_bo_map_gtt(bo); 44918210155Smrg if (ret) { 45018210155Smrg fprintf(stderr, "failed to GTT map buffer: %s\n", 45118210155Smrg strerror(errno)); 45218210155Smrg return -1; 45318210155Smrg } 45418210155Smrg 45518210155Smrg fb_ptr = bo->virtual; 45618210155Smrg 45718210155Smrg /* paint the buffer with colored tiles */ 45818210155Smrg for (i = 0; i < width * height; i++) { 45918210155Smrg d = div(i, width); 46018210155Smrg fb_ptr[i] = 0x00130502 * (d.quot >> 6) + 0x000a1120 * (d.rem >> 6); 46118210155Smrg } 46222944501Smrg drm_intel_gem_bo_unmap_gtt(bo); 46318210155Smrg 46418210155Smrg *bo_out = bo; 46518210155Smrg *stride_out = stride; 46618210155Smrg 46718210155Smrg return 0; 46818210155Smrg} 46918210155Smrg 47018210155Smrg#endif 47118210155Smrg 47222944501Smrgstatic int 47322944501Smrgcreate_grey_buffer(drm_intel_bufmgr *bufmgr, 47422944501Smrg int width, int height, int *stride_out, drm_intel_bo **bo_out) 47522944501Smrg{ 47622944501Smrg drm_intel_bo *bo; 47722944501Smrg int size, ret, stride; 47822944501Smrg 47922944501Smrg /* Mode size at 32 bpp */ 48022944501Smrg stride = width * 4; 48122944501Smrg size = stride * height; 48222944501Smrg 48322944501Smrg bo = drm_intel_bo_alloc(bufmgr, "frontbuffer", size, 4096); 48422944501Smrg if (!bo) { 48522944501Smrg fprintf(stderr, "failed to alloc buffer: %s\n", 48622944501Smrg strerror(errno)); 48722944501Smrg return -1; 48822944501Smrg } 48922944501Smrg 49022944501Smrg ret = drm_intel_gem_bo_map_gtt(bo); 49122944501Smrg if (ret) { 49222944501Smrg fprintf(stderr, "failed to GTT map buffer: %s\n", 49322944501Smrg strerror(errno)); 49422944501Smrg return -1; 49522944501Smrg } 49622944501Smrg 49722944501Smrg memset(bo->virtual, 0x77, size); 49822944501Smrg drm_intel_gem_bo_unmap_gtt(bo); 49922944501Smrg 50022944501Smrg *bo_out = bo; 50122944501Smrg *stride_out = stride; 50222944501Smrg 50322944501Smrg return 0; 50422944501Smrg} 50522944501Smrg 50622944501Smrgvoid 50722944501Smrgpage_flip_handler(int fd, unsigned int frame, 50822944501Smrg unsigned int sec, unsigned int usec, void *data) 50922944501Smrg{ 51022944501Smrg struct connector *c; 51122944501Smrg unsigned int new_fb_id; 51222944501Smrg struct timeval end; 51322944501Smrg double t; 51422944501Smrg 51522944501Smrg c = data; 51622944501Smrg if (c->current_fb_id == c->fb_id[0]) 51722944501Smrg new_fb_id = c->fb_id[1]; 51822944501Smrg else 51922944501Smrg new_fb_id = c->fb_id[0]; 52022944501Smrg 52122944501Smrg drmModePageFlip(fd, c->crtc, new_fb_id, 52222944501Smrg DRM_MODE_PAGE_FLIP_EVENT, c); 52322944501Smrg c->current_fb_id = new_fb_id; 52422944501Smrg c->swap_count++; 52522944501Smrg if (c->swap_count == 60) { 52622944501Smrg gettimeofday(&end, NULL); 52722944501Smrg t = end.tv_sec + end.tv_usec * 1e-6 - 52822944501Smrg (c->start.tv_sec + c->start.tv_usec * 1e-6); 52922944501Smrg fprintf(stderr, "freq: %.02fHz\n", c->swap_count / t); 53022944501Smrg c->swap_count = 0; 53122944501Smrg c->start = end; 53222944501Smrg } 53322944501Smrg} 53422944501Smrg 53518210155Smrgstatic void 53622944501Smrgset_mode(struct connector *c, int count, int page_flip) 53718210155Smrg{ 53818210155Smrg drm_intel_bufmgr *bufmgr; 53922944501Smrg drm_intel_bo *bo, *other_bo; 54022944501Smrg unsigned int fb_id, other_fb_id; 54122944501Smrg int i, ret, width, height, x, stride; 54222944501Smrg drmEventContext evctx; 54318210155Smrg 54418210155Smrg width = 0; 54518210155Smrg height = 0; 54618210155Smrg for (i = 0; i < count; i++) { 54718210155Smrg connector_find_mode(&c[i]); 54818210155Smrg if (c[i].mode == NULL) 54918210155Smrg continue; 55018210155Smrg width += c[i].mode->hdisplay; 55118210155Smrg if (height < c[i].mode->vdisplay) 55218210155Smrg height = c[i].mode->vdisplay; 55318210155Smrg } 55418210155Smrg 55518210155Smrg bufmgr = drm_intel_bufmgr_gem_init(fd, 2<<20); 55618210155Smrg if (!bufmgr) { 55718210155Smrg fprintf(stderr, "failed to init bufmgr: %s\n", strerror(errno)); 55818210155Smrg return; 55918210155Smrg } 56018210155Smrg 56118210155Smrg if (create_test_buffer(bufmgr, width, height, &stride, &bo)) 56218210155Smrg return; 56318210155Smrg 56418210155Smrg ret = drmModeAddFB(fd, width, height, 32, 32, stride, bo->handle, 56518210155Smrg &fb_id); 56618210155Smrg if (ret) { 56718210155Smrg fprintf(stderr, "failed to add fb: %s\n", strerror(errno)); 56818210155Smrg return; 56918210155Smrg } 57018210155Smrg 57118210155Smrg x = 0; 57218210155Smrg for (i = 0; i < count; i++) { 57318210155Smrg if (c[i].mode == NULL) 57418210155Smrg continue; 57518210155Smrg 57618210155Smrg printf("setting mode %s on connector %d, crtc %d\n", 57718210155Smrg c[i].mode_str, c[i].id, c[i].crtc); 57818210155Smrg 57918210155Smrg ret = drmModeSetCrtc(fd, c[i].crtc, fb_id, x, 0, 58018210155Smrg &c[i].id, 1, c[i].mode); 58118210155Smrg x += c[i].mode->hdisplay; 58218210155Smrg 58318210155Smrg if (ret) { 58418210155Smrg fprintf(stderr, "failed to set mode: %s\n", strerror(errno)); 58518210155Smrg return; 58618210155Smrg } 58718210155Smrg } 58822944501Smrg 58922944501Smrg if (!page_flip) 59022944501Smrg return; 59122944501Smrg 59222944501Smrg if (create_grey_buffer(bufmgr, width, height, &stride, &other_bo)) 59322944501Smrg return; 59422944501Smrg 59522944501Smrg ret = drmModeAddFB(fd, width, height, 32, 32, stride, other_bo->handle, 59622944501Smrg &other_fb_id); 59722944501Smrg if (ret) { 59822944501Smrg fprintf(stderr, "failed to add fb: %s\n", strerror(errno)); 59922944501Smrg return; 60022944501Smrg } 60122944501Smrg 60222944501Smrg for (i = 0; i < count; i++) { 60322944501Smrg if (c[i].mode == NULL) 60422944501Smrg continue; 60522944501Smrg 60622944501Smrg drmModePageFlip(fd, c[i].crtc, other_fb_id, 60722944501Smrg DRM_MODE_PAGE_FLIP_EVENT, &c[i]); 60822944501Smrg gettimeofday(&c[i].start, NULL); 60922944501Smrg c[i].swap_count = 0; 61022944501Smrg c[i].fb_id[0] = fb_id; 61122944501Smrg c[i].fb_id[1] = other_fb_id; 61222944501Smrg c[i].current_fb_id = fb_id; 61322944501Smrg } 61422944501Smrg 61522944501Smrg memset(&evctx, 0, sizeof evctx); 61622944501Smrg evctx.version = DRM_EVENT_CONTEXT_VERSION; 61722944501Smrg evctx.vblank_handler = NULL; 61822944501Smrg evctx.page_flip_handler = page_flip_handler; 61922944501Smrg 62022944501Smrg while (1) { 62122944501Smrg#if 0 62222944501Smrg struct pollfd pfd[2]; 62322944501Smrg 62422944501Smrg pfd[0].fd = 0; 62522944501Smrg pfd[0].events = POLLIN; 62622944501Smrg pfd[1].fd = fd; 62722944501Smrg pfd[1].events = POLLIN; 62822944501Smrg 62922944501Smrg if (poll(pfd, 2, -1) < 0) { 63022944501Smrg fprintf(stderr, "poll error\n"); 63122944501Smrg break; 63222944501Smrg } 63322944501Smrg 63422944501Smrg if (pfd[0].revents) 63522944501Smrg break; 63622944501Smrg#else 63722944501Smrg struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 }; 63822944501Smrg fd_set fds; 63922944501Smrg int ret; 64022944501Smrg 64122944501Smrg FD_ZERO(&fds); 64222944501Smrg FD_SET(0, &fds); 64322944501Smrg FD_SET(fd, &fds); 64422944501Smrg ret = select(fd + 1, &fds, NULL, NULL, &timeout); 64522944501Smrg 64622944501Smrg if (ret <= 0) { 64722944501Smrg fprintf(stderr, "select timed out or error (ret %d)\n", 64822944501Smrg ret); 64922944501Smrg continue; 65022944501Smrg } else if (FD_ISSET(0, &fds)) { 65122944501Smrg break; 65222944501Smrg } 65322944501Smrg#endif 65422944501Smrg 65522944501Smrg drmHandleEvent(fd, &evctx); 65622944501Smrg } 65718210155Smrg} 65818210155Smrg 65918210155Smrgextern char *optarg; 66018210155Smrgextern int optind, opterr, optopt; 66122944501Smrgstatic char optstr[] = "ecpmfs:v"; 66218210155Smrg 66318210155Smrgvoid usage(char *name) 66418210155Smrg{ 66518210155Smrg fprintf(stderr, "usage: %s [-ecpmf]\n", name); 66618210155Smrg fprintf(stderr, "\t-e\tlist encoders\n"); 66718210155Smrg fprintf(stderr, "\t-c\tlist connectors\n"); 66818210155Smrg fprintf(stderr, "\t-p\tlist CRTCs (pipes)\n"); 66918210155Smrg fprintf(stderr, "\t-m\tlist modes\n"); 67018210155Smrg fprintf(stderr, "\t-f\tlist framebuffers\n"); 67122944501Smrg fprintf(stderr, "\t-v\ttest vsynced page flipping\n"); 67218210155Smrg fprintf(stderr, "\t-s <connector_id>:<mode>\tset a mode\n"); 67318210155Smrg fprintf(stderr, "\t-s <connector_id>@<crtc_id>:<mode>\tset a mode\n"); 67418210155Smrg fprintf(stderr, "\n\tDefault is to dump all info.\n"); 67518210155Smrg exit(0); 67618210155Smrg} 67718210155Smrg 67818210155Smrg#define dump_resource(res) if (res) dump_##res() 67918210155Smrg 68022944501Smrgstatic int page_flipping_supported(int fd) 68122944501Smrg{ 68222944501Smrg int ret, value; 68322944501Smrg struct drm_i915_getparam gp; 68422944501Smrg 68522944501Smrg gp.param = I915_PARAM_HAS_PAGEFLIPPING; 68622944501Smrg gp.value = &value; 68722944501Smrg 68822944501Smrg ret = drmCommandWriteRead(fd, DRM_I915_GETPARAM, &gp, sizeof(gp)); 68922944501Smrg if (ret) { 69022944501Smrg fprintf(stderr, "drm_i915_getparam: %m\n"); 69122944501Smrg return 0; 69222944501Smrg } 69322944501Smrg 69422944501Smrg return *gp.value; 69522944501Smrg} 69622944501Smrg 69718210155Smrgint main(int argc, char **argv) 69818210155Smrg{ 69918210155Smrg int c; 70018210155Smrg int encoders = 0, connectors = 0, crtcs = 0, framebuffers = 0; 70122944501Smrg int test_vsync = 0; 70222944501Smrg char *modules[] = { "i915", "radeon", "nouveau" }; 70322944501Smrg char *modeset = NULL; 70422944501Smrg int i, count = 0; 70518210155Smrg struct connector con_args[2]; 70618210155Smrg 70718210155Smrg opterr = 0; 70818210155Smrg while ((c = getopt(argc, argv, optstr)) != -1) { 70918210155Smrg switch (c) { 71018210155Smrg case 'e': 71118210155Smrg encoders = 1; 71218210155Smrg break; 71318210155Smrg case 'c': 71418210155Smrg connectors = 1; 71518210155Smrg break; 71618210155Smrg case 'p': 71718210155Smrg crtcs = 1; 71818210155Smrg break; 71918210155Smrg case 'm': 72018210155Smrg modes = 1; 72118210155Smrg break; 72218210155Smrg case 'f': 72318210155Smrg framebuffers = 1; 72418210155Smrg break; 72522944501Smrg case 'v': 72622944501Smrg test_vsync = 1; 72722944501Smrg break; 72818210155Smrg case 's': 72918210155Smrg modeset = strdup(optarg); 73018210155Smrg con_args[count].crtc = -1; 73118210155Smrg if (sscanf(optarg, "%d:%64s", 73218210155Smrg &con_args[count].id, 73322944501Smrg con_args[count].mode_str) != 2 && 73418210155Smrg sscanf(optarg, "%d@%d:%64s", 73518210155Smrg &con_args[count].id, 73618210155Smrg &con_args[count].crtc, 73722944501Smrg con_args[count].mode_str) != 3) 73818210155Smrg usage(argv[0]); 73918210155Smrg count++; 74018210155Smrg break; 74118210155Smrg default: 74218210155Smrg usage(argv[0]); 74318210155Smrg break; 74418210155Smrg } 74518210155Smrg } 74618210155Smrg 74718210155Smrg if (argc == 1) 74818210155Smrg encoders = connectors = crtcs = modes = framebuffers = 1; 74918210155Smrg 75018210155Smrg for (i = 0; i < ARRAY_SIZE(modules); i++) { 75118210155Smrg printf("trying to load module %s...", modules[i]); 75218210155Smrg fd = drmOpen(modules[i], NULL); 75318210155Smrg if (fd < 0) { 75418210155Smrg printf("failed.\n"); 75518210155Smrg } else { 75618210155Smrg printf("success.\n"); 75718210155Smrg break; 75818210155Smrg } 75918210155Smrg } 76018210155Smrg 76122944501Smrg if (test_vsync && !page_flipping_supported(fd)) { 76222944501Smrg fprintf(stderr, "page flipping not supported by drm.\n"); 76322944501Smrg return -1; 76422944501Smrg } 76522944501Smrg 76618210155Smrg if (i == ARRAY_SIZE(modules)) { 76718210155Smrg fprintf(stderr, "failed to load any modules, aborting.\n"); 76818210155Smrg return -1; 76918210155Smrg } 77018210155Smrg 77118210155Smrg resources = drmModeGetResources(fd); 77218210155Smrg if (!resources) { 77318210155Smrg fprintf(stderr, "drmModeGetResources failed: %s\n", 77418210155Smrg strerror(errno)); 77518210155Smrg drmClose(fd); 77618210155Smrg return 1; 77718210155Smrg } 77818210155Smrg 77918210155Smrg dump_resource(encoders); 78018210155Smrg dump_resource(connectors); 78118210155Smrg dump_resource(crtcs); 78218210155Smrg dump_resource(framebuffers); 78318210155Smrg 78418210155Smrg if (count > 0) { 78522944501Smrg set_mode(con_args, count, test_vsync); 78618210155Smrg getchar(); 78718210155Smrg } 78818210155Smrg 78918210155Smrg drmModeFreeResources(resources); 79018210155Smrg 79118210155Smrg return 0; 79218210155Smrg} 793