diff options
Diffstat (limited to 'tools/vtview.c')
-rw-r--r-- | tools/vtview.c | 477 |
1 files changed, 477 insertions, 0 deletions
diff --git a/tools/vtview.c b/tools/vtview.c new file mode 100644 index 0000000..6b58f58 --- /dev/null +++ b/tools/vtview.c @@ -0,0 +1,477 @@ +/* + * Copyright 2010 Intel Corporation + * Jesse Barnes <jesse.barnes@intel.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/* + * This program is intended for testing of display functionality. It should + * allow for testing of + * - hotplug + * - mode setting + * - clone & twin modes + * - panel fitting + * - test patterns & pixel generators + * Additional programs can test the detected outputs against VBT provided + * device lists (both docked & undocked). + * + * TODO: + * - pixel generator in transcoder + * - test pattern reg in pipe + * - test patterns on outputs (e.g. TV) + * - handle hotplug (leaks crtcs, can't handle clones) + * - allow mode force + * - expose output specific controls + * - e.g. DDC-CI brightness + * - HDMI controls + * - panel brightness + * - DP commands (e.g. poweroff) + * - verify outputs against VBT/physical connectors + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <cairo.h> +#include <errno.h> +#include <math.h> +#include <stdint.h> +#include <stdbool.h> +#include <strings.h> +#include <unistd.h> +#include <termios.h> +#include <sys/poll.h> +#include <sys/time.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "drmtest.h" +#include "vtview.h" +#include "igt_kms.h" + +#include <stdlib.h> +#include <signal.h> + + +static int tio_fd; +struct termios saved_tio; + +drmModeRes *resources; +int drm_fd, modes; +int test_all_modes = 0, test_preferred_mode = 0; + +unsigned int tiling = I915_TILING_X; //tiling = I915_TILING_NONE; +int sleep_between_modes = 5; +uint32_t depth = 24, stride, bpp = 32; + +drmModeModeInfo force_timing; + +int crtc_x, crtc_y, crtc_w, crtc_h, width, height; +unsigned int plane_fb_id; +unsigned int plane_crtc_id; +unsigned int plane_id; +int plane_width, plane_height; +static const uint32_t SPRITE_COLOR_KEY = 0x00aaaaaa; + +/* + * Mode setting with the kernel interfaces is a bit of a chore. + * First you have to find the connector in question and make sure the + * requested mode is available. + * Then you need to find the encoder attached to that connector so you + * can bind it with a free crtc. + */ +struct connector { + uint32_t id; + int mode_valid; + drmModeModeInfo mode; + drmModeEncoder *encoder; + drmModeConnector *connector; + int crtc; + int crtc_idx; + int pipe; +}; + +static void connector_find_preferred_mode(uint32_t connector_id, + unsigned long crtc_idx_mask, + int mode_num, struct connector *c) +{ + struct kmstest_connector_config config; + + if (!kmstest_get_connector_config(drm_fd, connector_id, crtc_idx_mask, + &config)) { + c->mode_valid = 0; + return; + } + + c->connector = config.connector; + c->encoder = config.encoder; + c->crtc = config.crtc->crtc_id; + c->crtc_idx = config.crtc_idx; + c->pipe = config.pipe; + + if (mode_num != -1) { + igt_assert(mode_num < config.connector->count_modes); + c->mode = config.connector->modes[mode_num]; + } else { + c->mode = config.default_mode; + } + c->mode_valid = 1; +} + +static void paint_image(cairo_t *cr, const char *file) +{ + int img_x, img_y, img_w, img_h, img_w_o, img_h_o; + double img_w_scale, img_h_scale; + + cairo_surface_t *image; + + img_y = height * (0.10 ); + img_h = height * 0.08 * 4; + img_w = img_h; + + img_x = (width / 2) - (img_w / 2); + + image = cairo_image_surface_create_from_png(file); + + img_w_o = cairo_image_surface_get_width(image); + img_h_o = cairo_image_surface_get_height(image); + + cairo_translate(cr, img_x, img_y); + + img_w_scale = (double)img_w / (double)img_w_o; + img_h_scale = (double)img_h / (double)img_h_o; + cairo_scale(cr, img_w_scale, img_h_scale); + + cairo_set_source_surface(cr, image, 0, 0); + cairo_scale(cr, 1, 1); + + cairo_paint(cr); + cairo_surface_destroy(image); +} + +static void paint_output_info(struct connector *c, struct igt_fb *fb) +{ + cairo_t *cr = igt_get_cairo_ctx(drm_fd, fb); + int l_width = fb->width; + int l_height = fb->height; + double str_width; + double x, y, top_y; + double max_width; + int i; + + paint_image(cr, IGT_DATADIR"/pass.png"); + + igt_assert(!cairo_status(cr)); + + cairo_destroy(cr); +} + +static void +set_mode(struct connector *c) +{ + unsigned int fb_id = 0; + struct igt_fb fb_info[2] = { }; + int j, test_mode_num, current_fb = 0, old_fb = -1; + + test_mode_num = 1; + if (test_all_modes) + test_mode_num = c->connector->count_modes; + + + + width = c->mode.hdisplay; + height = c->mode.vdisplay; + + fb_id = igt_create_fb(drm_fd, width, height, + igt_bpp_depth_to_drm_format(bpp, depth), + tiling, &fb_info[current_fb]); + paint_output_info(c, &fb_info[current_fb]); + + kmstest_dump_mode(&c->mode); + if (drmModeSetCrtc(drm_fd, c->crtc, fb_id, 0, 0, + &c->id, 1, &c->mode)) { + igt_warn("failed to set mode (%dx%d@%dHz): %s\n", width, height, c->mode.vrefresh, strerror(errno)); + } + + if (old_fb != -1) + igt_remove_fb(drm_fd, &fb_info[old_fb]); + old_fb = current_fb; + current_fb = 1 - current_fb; + + if (sleep_between_modes && test_all_modes) + sleep(sleep_between_modes); + + + if (test_all_modes) + igt_remove_fb(drm_fd, &fb_info[old_fb]); + + drmModeFreeEncoder(c->encoder); + drmModeFreeConnector(c->connector); +} + +/* + * Re-probe outputs and light up as many as possible. + * + * On Intel, we have two CRTCs that we can drive independently with + * different timings and scanout buffers. + * + * Each connector has a corresponding encoder, except in the SDVO case + * where an encoder may have multiple connectors. + */ +int update_display(void) +{ + struct connector *connectors; + int c; + + resources = drmModeGetResources(drm_fd); + if (!resources) { + igt_warn("drmModeGetResources failed: %s\n", strerror(errno)); + return 0; + } + + connectors = calloc(resources->count_connectors, + sizeof(struct connector)); + if (!connectors) + return 0; + + if (test_preferred_mode || test_all_modes ) { + unsigned long crtc_idx_mask = -1UL; + + /* Find any connected displays */ + for (c = 0; c < resources->count_connectors; c++) { + struct connector *connector = &connectors[c]; + + connector->id = resources->connectors[c]; + + connector_find_preferred_mode(connector->id, + crtc_idx_mask, + -1, + connector); + if (!connector->mode_valid) + continue; + + set_mode(connector); + + if (test_preferred_mode ) + crtc_idx_mask &= ~(1 << connector->crtc_idx); + + } + } + + free(connectors); + drmModeFreeResources(resources); + return 1; +} + +static char optstr[] = "3hiaf:s:d:p:mrto:j:"; + +static void __attribute__((noreturn)) usage(char *name, char opt) +{ + igt_info("usage: %s [-hiasdpmtf]\n", name); + igt_info("\t-i\tdump info\n"); + igt_info("\t-a\ttest all modes\n"); + igt_info("\t-s\t<duration>\tsleep between each mode test\n"); + igt_info("\t-d\t<depth>\tbit depth of scanout buffer\n"); + igt_info("\t-p\t<planew,h>,<crtcx,y>,<crtcw,h> test overlay plane\n"); + igt_info("\t-m\ttest the preferred mode\n"); + igt_info("\t-3\ttest all 3D modes\n"); + igt_info("\t-t\tuse a tiled framebuffer\n"); + igt_info("\t-j\tdo dpms off, optional arg to select dpms leve (1-3)\n"); + igt_info("\t-r\tprint a QR code on the screen whose content is \"pass\" for the automatic test\n"); + igt_info("\t-o\t<id of the display>,<number of the mode>\tonly test specified mode on the specified display\n"); + igt_info("\t-f\t<clock MHz>,<hdisp>,<hsync-start>,<hsync-end>,<htotal>,\n"); + igt_info("\t\t<vdisp>,<vsync-start>,<vsync-end>,<vtotal>\n"); + igt_info("\t\ttest force mode\n"); + igt_info("\tDefault is to test all modes.\n"); + exit((opt != 'h') ? -1 : 0); +} + +#define dump_resource(res) if (res) dump_##res() + +static void cleanup_and_exit(int ret) +{ + close(drm_fd); + exit(ret); +} + +static gboolean input_event(GIOChannel *source, GIOCondition condition, + gpointer data) +{ + gchar buf[2]; + gsize count; + + count = read(g_io_channel_unix_get_fd(source), buf, sizeof(buf)); + if (buf[0] == 'q' && (count == 1 || buf[1] == '\n')) { + cleanup_and_exit(0); + } + + return TRUE; +} + +static void enter_exec_path( char **argv ) +{ + char *exec_path = NULL; + char *pos = NULL; + short len_path = 0; + int ret; + + len_path = strlen( argv[0] ); + exec_path = (char*) malloc(len_path); + + memcpy(exec_path, argv[0], len_path); + pos = strrchr(exec_path, '/'); + if (pos != NULL) + *(pos+1) = '\0'; + + ret = chdir(exec_path); + igt_assert(ret == 0); + free(exec_path); +} + +static void restore_termio_mode(int sig) +{ + tcsetattr(tio_fd, TCSANOW, &saved_tio); + close(tio_fd); +} + +static void set_termio_mode(void) +{ + struct termios tio; + + /* don't attempt to set terminal attributes if not in the foreground + * process group */ + if (getpgrp() != tcgetpgrp(STDOUT_FILENO)) + return; + + tio_fd = dup(STDIN_FILENO); + tcgetattr(tio_fd, &saved_tio); + igt_install_exit_handler(restore_termio_mode); + tio = saved_tio; + tio.c_lflag &= ~(ICANON | ECHO); + tcsetattr(tio_fd, TCSANOW, &tio); +} + +int main(int argc, char **argv) +{ + int c; + int ret = 0; + GIOChannel *stdinchannel; + GMainLoop *mainloop; + float force_clock; + struct option long_opts[] = { + {"help", 0, 0, 'h'}, + { 0, 0, 0, 0 } + }; + +// igt_skip_on_simulation(); + + enter_exec_path( argv ); + + while ((c = getopt_long(argc, argv, optstr, long_opts, NULL)) != -1) { + switch (c) { + case 'a': + test_all_modes = 1; + break; + case 'f': + if(sscanf(optarg,"%f,%hu,%hu,%hu,%hu,%hu,%hu,%hu,%hu", + &force_clock,&force_timing.hdisplay, &force_timing.hsync_start,&force_timing.hsync_end,&force_timing.htotal, + &force_timing.vdisplay, &force_timing.vsync_start, &force_timing.vsync_end, &force_timing.vtotal)!= 9) + usage(argv[0], c); + force_timing.clock = force_clock*1000; + + break; + case 's': + sleep_between_modes = atoi(optarg); + break; + case 'd': + depth = atoi(optarg); + igt_info("using depth %d\n", depth); + break; + case 'm': + test_preferred_mode = 1; + break; + default: + /* fall through */ + case 'h': + usage(argv[0], c); + break; + } + } + +// set_termio_mode(); + + if (!test_all_modes && !test_preferred_mode ) + test_all_modes = 1; + + drm_fd = drm_open_any(); + +// kmstest_set_vt_graphics_mode(); + + mainloop = g_main_loop_new(NULL, FALSE); + if (!mainloop) { + igt_warn("failed to create glib mainloop\n"); + ret = -1; + goto out_close; + } + +// if (!testdisplay_setup_hotplug()) { +// igt_warn("failed to initialize hotplug support\n"); +// goto out_mainloop; +// } + + stdinchannel = g_io_channel_unix_new(0); +// if (!stdinchannel) { +// igt_warn("failed to create stdin GIO channel\n"); +// goto out_hotplug; +// } + + ret = g_io_add_watch(stdinchannel, G_IO_IN | G_IO_ERR, input_event, + NULL); + if (ret < 0) { + igt_warn("failed to add watch on stdin GIO channel\n"); + goto out_stdio; + } + + ret = 0; + + if (!update_display()) { + ret = 1; + goto out_stdio; + } + + if (test_all_modes) + goto out_stdio; + + g_main_loop_run(mainloop); + +out_stdio: + g_io_channel_shutdown(stdinchannel, TRUE, NULL); +//out_hotplug: +// testdisplay_cleanup_hotplug(); +out_mainloop: + g_main_loop_unref(mainloop); +out_close: + close(drm_fd); + + igt_assert(ret == 0); + + igt_exit(); +} |