summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--demos/intel_sprite_on.c1
-rw-r--r--lib/Makefile.sources2
-rw-r--r--lib/drmtest.c732
-rw-r--r--lib/drmtest.h72
-rw-r--r--lib/igt_kms.c765
-rw-r--r--lib/igt_kms.h102
-rw-r--r--tests/kms_cursor_crc.c1
-rw-r--r--tests/kms_flip.c1
-rw-r--r--tests/kms_pipe_crc_basic.c1
-rw-r--r--tests/kms_render.c1
-rw-r--r--tests/kms_setmode.c1
-rw-r--r--tests/pm_pc8.c1
-rw-r--r--tests/testdisplay.c1
13 files changed, 877 insertions, 804 deletions
diff --git a/demos/intel_sprite_on.c b/demos/intel_sprite_on.c
index e1b4fd55..98c0af91 100644
--- a/demos/intel_sprite_on.c
+++ b/demos/intel_sprite_on.c
@@ -45,6 +45,7 @@
#include "i915_drm.h"
#include "drmtest.h"
+#include "igt_kms.h"
#if defined(DRM_IOCTL_MODE_ADDFB2) && defined(DRM_I915_SET_SPRITE_COLORKEY)
#define TEST_PLANES 1
diff --git a/lib/Makefile.sources b/lib/Makefile.sources
index d71f8378..78e2034e 100644
--- a/lib/Makefile.sources
+++ b/lib/Makefile.sources
@@ -32,5 +32,7 @@ libintel_tools_la_SOURCES = \
intel_reg_map.c \
intel_dpio.c \
intel_iosf.c \
+ igt_kms.c \
+ igt_kms.h \
$(NULL)
diff --git a/lib/drmtest.c b/lib/drmtest.c
index d8fc60f6..38463f8c 100644
--- a/lib/drmtest.c
+++ b/lib/drmtest.c
@@ -35,13 +35,10 @@
#include <sys/mman.h>
#include <signal.h>
#include <pciaccess.h>
-#include <math.h>
#include <getopt.h>
#include <stdlib.h>
-#include <linux/kd.h>
#include <unistd.h>
#include <sys/wait.h>
-#include "drm_fourcc.h"
#include "drmtest.h"
#include "i915_drm.h"
@@ -1375,553 +1372,6 @@ void igt_cleanup_aperture_trashers(void)
free(trash_bos);
}
-/* helpers to create nice-looking framebuffers */
-static int create_bo_for_fb(int fd, int width, int height, int bpp,
- bool tiled, uint32_t *gem_handle_ret,
- unsigned *size_ret, unsigned *stride_ret)
-{
- uint32_t gem_handle;
- int size;
- unsigned stride;
-
- if (tiled) {
- int v;
-
- /* Round the tiling up to the next power-of-two and the
- * region up to the next pot fence size so that this works
- * on all generations.
- *
- * This can still fail if the framebuffer is too large to
- * be tiled. But then that failure is expected.
- */
-
- v = width * bpp / 8;
- for (stride = 512; stride < v; stride *= 2)
- ;
-
- v = stride * height;
- for (size = 1024*1024; size < v; size *= 2)
- ;
- } else {
- /* Scan-out has a 64 byte alignment restriction */
- stride = (width * (bpp / 8) + 63) & ~63;
- size = stride * height;
- }
-
- gem_handle = gem_create(fd, size);
-
- if (tiled)
- gem_set_tiling(fd, gem_handle, I915_TILING_X, stride);
-
- *stride_ret = stride;
- *size_ret = size;
- *gem_handle_ret = gem_handle;
-
- return 0;
-}
-
-void kmstest_paint_color(cairo_t *cr, int x, int y, int w, int h,
- double r, double g, double b)
-{
- cairo_rectangle(cr, x, y, w, h);
- cairo_set_source_rgb(cr, r, g, b);
- cairo_fill(cr);
-}
-
-void kmstest_paint_color_alpha(cairo_t *cr, int x, int y, int w, int h,
- double r, double g, double b, double a)
-{
- cairo_rectangle(cr, x, y, w, h);
- cairo_set_source_rgba(cr, r, g, b, a);
- cairo_fill(cr);
-}
-
-void
-kmstest_paint_color_gradient(cairo_t *cr, int x, int y, int w, int h,
- int r, int g, int b)
-{
- cairo_pattern_t *pat;
-
- pat = cairo_pattern_create_linear(x, y, x + w, y + h);
- cairo_pattern_add_color_stop_rgba(pat, 1, 0, 0, 0, 1);
- cairo_pattern_add_color_stop_rgba(pat, 0, r, g, b, 1);
-
- cairo_rectangle(cr, x, y, w, h);
- cairo_set_source(cr, pat);
- cairo_fill(cr);
- cairo_pattern_destroy(pat);
-}
-
-static void
-paint_test_patterns(cairo_t *cr, int width, int height)
-{
- double gr_height, gr_width;
- int x, y;
-
- y = height * 0.10;
- gr_width = width * 0.75;
- gr_height = height * 0.08;
- x = (width / 2) - (gr_width / 2);
-
- kmstest_paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 0, 0);
-
- y += gr_height;
- kmstest_paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 1, 0);
-
- y += gr_height;
- kmstest_paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 0, 1);
-
- y += gr_height;
- kmstest_paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 1, 1);
-}
-
-int kmstest_cairo_printf_line(cairo_t *cr, enum kmstest_text_align align,
- double yspacing, const char *fmt, ...)
-{
- double x, y, xofs, yofs;
- cairo_text_extents_t extents;
- char *text;
- va_list ap;
- int ret;
-
- va_start(ap, fmt);
- ret = vasprintf(&text, fmt, ap);
- assert(ret >= 0);
- va_end(ap);
-
- cairo_text_extents(cr, text, &extents);
-
- xofs = yofs = 0;
- if (align & align_right)
- xofs = -extents.width;
- else if (align & align_hcenter)
- xofs = -extents.width / 2;
-
- if (align & align_top)
- yofs = extents.height;
- else if (align & align_vcenter)
- yofs = extents.height / 2;
-
- cairo_get_current_point(cr, &x, &y);
- if (xofs || yofs)
- cairo_rel_move_to(cr, xofs, yofs);
-
- cairo_text_path(cr, text);
- cairo_set_source_rgb(cr, 0, 0, 0);
- cairo_stroke_preserve(cr);
- cairo_set_source_rgb(cr, 1, 1, 1);
- cairo_fill(cr);
-
- cairo_move_to(cr, x, y + extents.height + yspacing);
-
- free(text);
-
- return extents.width;
-}
-
-static void
-paint_marker(cairo_t *cr, int x, int y)
-{
- enum kmstest_text_align align;
- int xoff, yoff;
-
- cairo_move_to(cr, x, y - 20);
- cairo_line_to(cr, x, y + 20);
- cairo_move_to(cr, x - 20, y);
- cairo_line_to(cr, x + 20, y);
- cairo_new_sub_path(cr);
- cairo_arc(cr, x, y, 10, 0, M_PI * 2);
- cairo_set_line_width(cr, 4);
- cairo_set_source_rgb(cr, 0, 0, 0);
- cairo_stroke_preserve(cr);
- cairo_set_source_rgb(cr, 1, 1, 1);
- cairo_set_line_width(cr, 2);
- cairo_stroke(cr);
-
- xoff = x ? -20 : 20;
- align = x ? align_right : align_left;
-
- yoff = y ? -20 : 20;
- align |= y ? align_bottom : align_top;
-
- cairo_move_to(cr, x + xoff, y + yoff);
- cairo_set_font_size(cr, 18);
- kmstest_cairo_printf_line(cr, align, 0, "(%d, %d)", x, y);
-}
-
-void kmstest_paint_test_pattern(cairo_t *cr, int width, int height)
-{
- paint_test_patterns(cr, width, height);
-
- cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
-
- /* Paint corner markers */
- paint_marker(cr, 0, 0);
- paint_marker(cr, width, 0);
- paint_marker(cr, 0, height);
- paint_marker(cr, width, height);
-
- assert(!cairo_status(cr));
-}
-
-void kmstest_paint_image(cairo_t *cr, const char *filename,
- int dst_x, int dst_y, int dst_width, int dst_height)
-{
- cairo_surface_t *image;
- int img_width, img_height;
- double scale_x, scale_y;
-
- image = cairo_image_surface_create_from_png(filename);
- assert(cairo_surface_status(image) == CAIRO_STATUS_SUCCESS);
-
- img_width = cairo_image_surface_get_width(image);
- img_height = cairo_image_surface_get_height(image);
-
- scale_x = (double)dst_width / img_width;
- scale_y = (double)dst_height / img_height;
-
- cairo_save(cr);
-
- cairo_translate(cr, dst_x, dst_y);
- cairo_scale(cr, scale_x, scale_y);
- cairo_set_source_surface(cr, image, 0, 0);
- cairo_paint(cr);
-
- cairo_surface_destroy(image);
-
- cairo_restore(cr);
-}
-
-#define DF(did, cid, _bpp, _depth) \
- { DRM_FORMAT_##did, CAIRO_FORMAT_##cid, # did, _bpp, _depth }
-static struct format_desc_struct {
- uint32_t drm_id;
- cairo_format_t cairo_id;
- const char *name;
- int bpp;
- int depth;
-} format_desc[] = {
- DF(RGB565, RGB16_565, 16, 16),
- DF(RGB888, INVALID, 24, 24),
- DF(XRGB8888, RGB24, 32, 24),
- DF(XRGB2101010, RGB30, 32, 30),
- DF(ARGB8888, ARGB32, 32, 32),
-};
-#undef DF
-
-#define for_each_format(f) \
- for (f = format_desc; f - format_desc < ARRAY_SIZE(format_desc); f++)
-
-static uint32_t bpp_depth_to_drm_format(int bpp, int depth)
-{
- struct format_desc_struct *f;
-
- for_each_format(f)
- if (f->bpp == bpp && f->depth == depth)
- return f->drm_id;
-
- abort();
-}
-
-/* Return fb_id on success, 0 on error */
-unsigned int kmstest_create_fb(int fd, int width, int height, int bpp,
- int depth, bool tiled, struct kmstest_fb *fb)
-{
- memset(fb, 0, sizeof(*fb));
-
- if (create_bo_for_fb(fd, width, height, bpp, tiled, &fb->gem_handle,
- &fb->size, &fb->stride) < 0)
- return 0;
-
- if (drmModeAddFB(fd, width, height, depth, bpp, fb->stride,
- fb->gem_handle, &fb->fb_id) < 0) {
- gem_close(fd, fb->gem_handle);
-
- return 0;
- }
-
- fb->width = width;
- fb->height = height;
- fb->tiling = tiled;
- fb->drm_format = bpp_depth_to_drm_format(bpp, depth);
-
- return fb->fb_id;
-}
-
-uint32_t drm_format_to_bpp(uint32_t drm_format)
-{
- struct format_desc_struct *f;
-
- for_each_format(f)
- if (f->drm_id == drm_format)
- return f->bpp;
-
- abort();
-}
-
-unsigned int kmstest_create_fb2(int fd, int width, int height, uint32_t format,
- bool tiled, struct kmstest_fb *fb)
-{
- uint32_t handles[4];
- uint32_t pitches[4];
- uint32_t offsets[4];
- uint32_t fb_id;
- int bpp;
- int ret;
-
- memset(fb, 0, sizeof(*fb));
-
- bpp = drm_format_to_bpp(format);
- ret = create_bo_for_fb(fd, width, height, bpp, tiled, &fb->gem_handle,
- &fb->size, &fb->stride);
- if (ret < 0)
- return ret;
-
- memset(handles, 0, sizeof(handles));
- handles[0] = fb->gem_handle;
- memset(pitches, 0, sizeof(pitches));
- pitches[0] = fb->stride;
- memset(offsets, 0, sizeof(offsets));
- if (drmModeAddFB2(fd, width, height, format, handles, pitches,
- offsets, &fb_id, 0) < 0) {
- gem_close(fd, fb->gem_handle);
-
- return 0;
- }
-
- fb->width = width;
- fb->height = height;
- fb->tiling = tiled;
- fb->drm_format = format;
- fb->fb_id = fb_id;
-
- return fb_id;
-}
-
-static cairo_format_t drm_format_to_cairo(uint32_t drm_format)
-{
- struct format_desc_struct *f;
-
- for_each_format(f)
- if (f->drm_id == drm_format)
- return f->cairo_id;
-
- abort();
-}
-
-static cairo_surface_t *create_image_surface(int fd, struct kmstest_fb *fb)
-{
- cairo_surface_t *surface;
- cairo_format_t cformat;
- void *fb_ptr;
-
- cformat = drm_format_to_cairo(fb->drm_format);
- fb_ptr = gem_mmap(fd, fb->gem_handle, fb->size, PROT_READ | PROT_WRITE);
- surface = cairo_image_surface_create_for_data((unsigned char *)fb_ptr,
- cformat, fb->width,
- fb->height, fb->stride);
- assert(surface);
-
- return surface;
-}
-
-static cairo_t *create_cairo_ctx(int fd, struct kmstest_fb *fb)
-{
- cairo_t *cr;
- cairo_surface_t *surface;
-
- surface = create_image_surface(fd, fb);
- cr = cairo_create(surface);
- cairo_surface_destroy(surface);
-
- return cr;
-}
-
-void kmstest_write_fb(int fd, struct kmstest_fb *fb, const char *filename)
-{
- cairo_surface_t *surface;
- cairo_status_t status;
-
- surface = create_image_surface(fd, fb);
- status = cairo_surface_write_to_png(surface, filename);
- assert(status == CAIRO_STATUS_SUCCESS);
- cairo_surface_destroy(surface);
-}
-
-cairo_t *kmstest_get_cairo_ctx(int fd, struct kmstest_fb *fb)
-{
-
- if (!fb->cairo_ctx)
- fb->cairo_ctx = create_cairo_ctx(fd, fb);
-
- gem_set_domain(fd, fb->gem_handle, I915_GEM_DOMAIN_CPU,
- I915_GEM_DOMAIN_CPU);
-
- return fb->cairo_ctx;
-}
-
-void kmstest_remove_fb(int fd, struct kmstest_fb *fb)
-{
- if (fb->cairo_ctx)
- cairo_destroy(fb->cairo_ctx);
- do_or_die(drmModeRmFB(fd, fb->fb_id));
- gem_close(fd, fb->gem_handle);
-}
-
-const char *kmstest_format_str(uint32_t drm_format)
-{
- struct format_desc_struct *f;
-
- for_each_format(f)
- if (f->drm_id == drm_format)
- return f->name;
-
- return "invalid";
-}
-
-const char *kmstest_pipe_str(int pipe)
-{
- const char *str[] = { "A", "B", "C" };
-
- if (pipe > 2)
- return "invalid";
-
- return str[pipe];
-}
-
-void kmstest_get_all_formats(const uint32_t **formats, int *format_count)
-{
- static uint32_t *drm_formats;
-
- if (!drm_formats) {
- struct format_desc_struct *f;
- uint32_t *format;
-
- drm_formats = calloc(ARRAY_SIZE(format_desc),
- sizeof(*drm_formats));
- format = &drm_formats[0];
- for_each_format(f)
- *format++ = f->drm_id;
- }
-
- *formats = drm_formats;
- *format_count = ARRAY_SIZE(format_desc);
-}
-
-struct type_name {
- int type;
- const char *name;
-};
-
-#define type_name_fn(res) \
-const char * kmstest_##res##_str(int type) { \
- unsigned int i; \
- for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \
- if (res##_names[i].type == type) \
- return res##_names[i].name; \
- } \
- return "(invalid)"; \
-}
-
-struct type_name encoder_type_names[] = {
- { DRM_MODE_ENCODER_NONE, "none" },
- { DRM_MODE_ENCODER_DAC, "DAC" },
- { DRM_MODE_ENCODER_TMDS, "TMDS" },
- { DRM_MODE_ENCODER_LVDS, "LVDS" },
- { DRM_MODE_ENCODER_TVDAC, "TVDAC" },
-};
-
-type_name_fn(encoder_type)
-
-struct type_name connector_status_names[] = {
- { DRM_MODE_CONNECTED, "connected" },
- { DRM_MODE_DISCONNECTED, "disconnected" },
- { DRM_MODE_UNKNOWNCONNECTION, "unknown" },
-};
-
-type_name_fn(connector_status)
-
-struct type_name connector_type_names[] = {
- { DRM_MODE_CONNECTOR_Unknown, "unknown" },
- { DRM_MODE_CONNECTOR_VGA, "VGA" },
- { DRM_MODE_CONNECTOR_DVII, "DVI-I" },
- { DRM_MODE_CONNECTOR_DVID, "DVI-D" },
- { DRM_MODE_CONNECTOR_DVIA, "DVI-A" },
- { DRM_MODE_CONNECTOR_Composite, "composite" },
- { DRM_MODE_CONNECTOR_SVIDEO, "s-video" },
- { DRM_MODE_CONNECTOR_LVDS, "LVDS" },
- { DRM_MODE_CONNECTOR_Component, "component" },
- { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" },
- { DRM_MODE_CONNECTOR_DisplayPort, "DP" },
- { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" },
- { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" },
- { DRM_MODE_CONNECTOR_TV, "TV" },
- { DRM_MODE_CONNECTOR_eDP, "eDP" },
-};
-
-type_name_fn(connector_type)
-
-static const char *mode_stereo_name(const drmModeModeInfo *mode)
-{
- switch (mode->flags & DRM_MODE_FLAG_3D_MASK) {
- case DRM_MODE_FLAG_3D_FRAME_PACKING:
- return "FP";
- case DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE:
- return "FA";
- case DRM_MODE_FLAG_3D_LINE_ALTERNATIVE:
- return "LA";
- case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL:
- return "SBSF";
- case DRM_MODE_FLAG_3D_L_DEPTH:
- return "LD";
- case DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH:
- return "LDGFX";
- case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM:
- return "TB";
- case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF:
- return "SBSH";
- default:
- return NULL;
- }
-}
-
-void kmstest_dump_mode(drmModeModeInfo *mode)
-{
- const char *stereo = mode_stereo_name(mode);
-
- printf(" %s %d %d %d %d %d %d %d %d %d 0x%x 0x%x %d%s%s%s\n",
- mode->name,
- mode->vrefresh,
- mode->hdisplay,
- mode->hsync_start,
- mode->hsync_end,
- mode->htotal,
- mode->vdisplay,
- mode->vsync_start,
- mode->vsync_end,
- mode->vtotal,
- mode->flags,
- mode->type,
- mode->clock,
- stereo ? " (3D:" : "",
- stereo ? stereo : "",
- stereo ? ")" : "");
- fflush(stdout);
-}
-
-int kmstest_get_pipe_from_crtc_id(int fd, int crtc_id)
-{
- struct drm_i915_get_pipe_from_crtc_id pfci;
- int ret;
-
- memset(&pfci, 0, sizeof(pfci));
- pfci.crtc_id = crtc_id;
- ret = drmIoctl(fd, DRM_IOCTL_I915_GET_PIPE_FROM_CRTC_ID, &pfci);
- igt_assert(ret == 0);
-
- return pfci.pipe;
-}
-
#define MAX_SIGNALS 32
#define MAX_EXIT_HANDLERS 5
@@ -2075,188 +1525,6 @@ void igt_enable_exit_handler(void)
exit_handler_disabled = false;
}
-static signed long set_vt_mode(unsigned long mode)
-{
- int fd;
- unsigned long prev_mode;
-
- fd = open("/dev/tty0", O_RDONLY);
- if (fd < 0)
- return -errno;
-
- prev_mode = 0;
- if (drmIoctl(fd, KDGETMODE, &prev_mode))
- goto err;
- if (drmIoctl(fd, KDSETMODE, (void *)mode))
- goto err;
-
- close(fd);
-
- return prev_mode;
-err:
- close(fd);
-
- return -errno;
-}
-
-static unsigned long orig_vt_mode = -1UL;
-
-static void restore_vt_mode_at_exit(int sig)
-{
- if (orig_vt_mode != -1UL)
- set_vt_mode(orig_vt_mode);
-}
-
-/*
- * Set the VT to graphics mode and install an exit handler to restore the
- * original mode.
- */
-
-void igt_set_vt_graphics_mode(void)
-{
- igt_install_exit_handler(restore_vt_mode_at_exit);
-
- igt_disable_exit_handler();
- orig_vt_mode = set_vt_mode(KD_GRAPHICS);
- if (orig_vt_mode < 0)
- orig_vt_mode = -1UL;
- igt_enable_exit_handler();
-
- igt_assert(orig_vt_mode >= 0);
-}
-
-int kmstest_get_connector_default_mode(int drm_fd, drmModeConnector *connector,
- drmModeModeInfo *mode)
-{
- drmModeRes *resources;
- int i;
-
- resources = drmModeGetResources(drm_fd);
- if (!resources) {
- perror("drmModeGetResources failed");
-
- return -1;
- }
-
- if (!connector->count_modes) {
- fprintf(stderr, "no modes for connector %d\n",
- connector->connector_id);
- drmModeFreeResources(resources);
-
- return -1;
- }
-
- for (i = 0; i < connector->count_modes; i++) {
- if (i == 0 ||
- connector->modes[i].type & DRM_MODE_TYPE_PREFERRED) {
- *mode = connector->modes[i];
- if (mode->type & DRM_MODE_TYPE_PREFERRED)
- break;
- }
- }
-
- drmModeFreeResources(resources);
-
- return 0;
-}
-
-int kmstest_get_connector_config(int drm_fd, uint32_t connector_id,
- unsigned long crtc_idx_mask,
- struct kmstest_connector_config *config)
-{
- drmModeRes *resources;
- drmModeConnector *connector;
- drmModeEncoder *encoder;
- int i, j;
-
- resources = drmModeGetResources(drm_fd);
- if (!resources) {
- perror("drmModeGetResources failed");
- goto err1;
- }
-
- /* First, find the connector & mode */
- connector = drmModeGetConnector(drm_fd, connector_id);
- if (!connector)
- goto err2;
-
- if (connector->connection != DRM_MODE_CONNECTED)
- goto err3;
-
- if (!connector->count_modes) {
- fprintf(stderr, "connector %d has no modes\n", connector_id);
- goto err3;
- }
-
- if (connector->connector_id != connector_id) {
- fprintf(stderr, "connector id doesn't match (%d != %d)\n",
- connector->connector_id, connector_id);
- goto err3;
- }
-
- /*
- * Find given CRTC if crtc_id != 0 or else the first CRTC not in use.
- * In both cases find the first compatible encoder and skip the CRTC
- * if there is non such.
- */
- encoder = NULL; /* suppress GCC warning */
- for (i = 0; i < resources->count_crtcs; i++) {
- if (!resources->crtcs[i] || !(crtc_idx_mask & (1 << i)))
- continue;
-
- /* Now get a compatible encoder */
- for (j = 0; j < connector->count_encoders; j++) {
- encoder = drmModeGetEncoder(drm_fd,
- connector->encoders[j]);
-
- if (!encoder) {
- fprintf(stderr, "could not get encoder %d: %s\n",
- resources->encoders[j], strerror(errno));
-
- continue;
- }
-
- if (encoder->possible_crtcs & (1 << i))
- goto found;
-
- drmModeFreeEncoder(encoder);
- }
- }
-
- goto err3;
-
-found:
- if (kmstest_get_connector_default_mode(drm_fd, connector,
- &config->default_mode) < 0)
- goto err4;
-
- config->connector = connector;
- config->encoder = encoder;
- config->crtc = drmModeGetCrtc(drm_fd, resources->crtcs[i]);
- config->crtc_idx = i;
- config->pipe = kmstest_get_pipe_from_crtc_id(drm_fd,
- config->crtc->crtc_id);
-
- drmModeFreeResources(resources);
-
- return 0;
-err4:
- drmModeFreeEncoder(encoder);
-err3:
- drmModeFreeConnector(connector);
-err2:
- drmModeFreeResources(resources);
-err1:
- return -1;
-}
-
-void kmstest_free_connector_config(struct kmstest_connector_config *config)
-{
- drmModeFreeCrtc(config->crtc);
- drmModeFreeEncoder(config->encoder);
- drmModeFreeConnector(config->connector);
-}
-
#define PREFAULT_DEBUGFS "/sys/module/i915/parameters/prefault_disable"
static void igt_prefault_control(bool enable)
{
diff --git a/lib/drmtest.h b/lib/drmtest.h
index a9fd0bc5..ce9d18dd 100644
--- a/lib/drmtest.h
+++ b/lib/drmtest.h
@@ -34,7 +34,6 @@
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
-#include <cairo.h>
#include <setjmp.h>
#include <sys/mman.h>
@@ -322,77 +321,6 @@ void igt_init_aperture_trashers(drm_intel_bufmgr *bufmgr);
void igt_trash_aperture(void);
void igt_cleanup_aperture_trashers(void);
-struct kmstest_connector_config {
- drmModeCrtc *crtc;
- drmModeConnector *connector;
- drmModeEncoder *encoder;
- drmModeModeInfo default_mode;
- int crtc_idx;
- int pipe;
-};
-
-int kmstest_get_connector_default_mode(int drm_fd, drmModeConnector *connector,
- drmModeModeInfo *mode);
-int kmstest_get_connector_config(int drm_fd, uint32_t connector_id,
- unsigned long crtc_idx_mask,
- struct kmstest_connector_config *config);
-void kmstest_free_connector_config(struct kmstest_connector_config *config);
-
-/* helpers to create nice-looking framebuffers */
-struct kmstest_fb {
- uint32_t fb_id;
- uint32_t gem_handle;
- uint32_t drm_format;
- int width;
- int height;
- int depth;
- unsigned stride;
- unsigned tiling;
- unsigned size;
- cairo_t *cairo_ctx;
-};
-
-enum kmstest_text_align {
- align_left,
- align_bottom = align_left,
- align_right = 0x01,
- align_top = 0x02,
- align_vcenter = 0x04,
- align_hcenter = 0x08,
-};
-
-int kmstest_cairo_printf_line(cairo_t *cr, enum kmstest_text_align align,
- double yspacing, const char *fmt, ...)
- __attribute__((format (printf, 4, 5)));
-
-unsigned int kmstest_create_fb(int fd, int width, int height, int bpp,
- int depth, bool tiled,
- struct kmstest_fb *fb_info);
-unsigned int kmstest_create_fb2(int fd, int width, int height, uint32_t format,
- bool tiled, struct kmstest_fb *fb);
-void kmstest_remove_fb(int fd, struct kmstest_fb *fb_info);
-cairo_t *kmstest_get_cairo_ctx(int fd, struct kmstest_fb *fb);
-void kmstest_paint_color(cairo_t *cr, int x, int y, int w, int h,
- double r, double g, double b);
-void kmstest_paint_color_alpha(cairo_t *cr, int x, int y, int w, int h,
- double r, double g, double b, double a);
-void kmstest_paint_color_gradient(cairo_t *cr, int x, int y, int w, int h,
- int r, int g, int b);
-void kmstest_paint_test_pattern(cairo_t *cr, int width, int height);
-void kmstest_paint_image(cairo_t *cr, const char *filename,
- int dst_x, int dst_y, int dst_width, int dst_height);
-void kmstest_write_fb(int fd, struct kmstest_fb *fb, const char *filename);
-void kmstest_dump_mode(drmModeModeInfo *mode);
-int kmstest_get_pipe_from_crtc_id(int fd, int crtc_id);
-const char *kmstest_format_str(uint32_t drm_format);
-const char *kmstest_pipe_str(int pipe);
-void kmstest_get_all_formats(const uint32_t **formats, int *format_count);
-const char *kmstest_encoder_type_str(int type);
-const char *kmstest_connector_status_str(int type);
-const char *kmstest_connector_type_str(int type);
-
-uint32_t drm_format_to_bpp(uint32_t drm_format);
-
#define do_or_die(x) igt_assert((x) == 0)
#define do_ioctl(fd, ptr, sz) igt_assert(drmIoctl((fd), (ptr), (sz)) == 0)
diff --git a/lib/igt_kms.c b/lib/igt_kms.c
new file mode 100644
index 00000000..57795b16
--- /dev/null
+++ b/lib/igt_kms.c
@@ -0,0 +1,765 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * 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 (including the next
+ * paragraph) 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.
+ *
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <math.h>
+#include <linux/kd.h>
+#include "drm_fourcc.h"
+
+#include "drmtest.h"
+#include "igt_kms.h"
+
+/* helpers to create nice-looking framebuffers */
+static int create_bo_for_fb(int fd, int width, int height, int bpp,
+ bool tiled, uint32_t *gem_handle_ret,
+ unsigned *size_ret, unsigned *stride_ret)
+{
+ uint32_t gem_handle;
+ int size;
+ unsigned stride;
+
+ if (tiled) {
+ int v;
+
+ /* Round the tiling up to the next power-of-two and the
+ * region up to the next pot fence size so that this works
+ * on all generations.
+ *
+ * This can still fail if the framebuffer is too large to
+ * be tiled. But then that failure is expected.
+ */
+
+ v = width * bpp / 8;
+ for (stride = 512; stride < v; stride *= 2)
+ ;
+
+ v = stride * height;
+ for (size = 1024*1024; size < v; size *= 2)
+ ;
+ } else {
+ /* Scan-out has a 64 byte alignment restriction */
+ stride = (width * (bpp / 8) + 63) & ~63;
+ size = stride * height;
+ }
+
+ gem_handle = gem_create(fd, size);
+
+ if (tiled)
+ gem_set_tiling(fd, gem_handle, I915_TILING_X, stride);
+
+ *stride_ret = stride;
+ *size_ret = size;
+ *gem_handle_ret = gem_handle;
+
+ return 0;
+}
+
+void kmstest_paint_color(cairo_t *cr, int x, int y, int w, int h,
+ double r, double g, double b)
+{
+ cairo_rectangle(cr, x, y, w, h);
+ cairo_set_source_rgb(cr, r, g, b);
+ cairo_fill(cr);
+}
+
+void kmstest_paint_color_alpha(cairo_t *cr, int x, int y, int w, int h,
+ double r, double g, double b, double a)
+{
+ cairo_rectangle(cr, x, y, w, h);
+ cairo_set_source_rgba(cr, r, g, b, a);
+ cairo_fill(cr);
+}
+
+void
+kmstest_paint_color_gradient(cairo_t *cr, int x, int y, int w, int h,
+ int r, int g, int b)
+{
+ cairo_pattern_t *pat;
+
+ pat = cairo_pattern_create_linear(x, y, x + w, y + h);
+ cairo_pattern_add_color_stop_rgba(pat, 1, 0, 0, 0, 1);
+ cairo_pattern_add_color_stop_rgba(pat, 0, r, g, b, 1);
+
+ cairo_rectangle(cr, x, y, w, h);
+ cairo_set_source(cr, pat);
+ cairo_fill(cr);
+ cairo_pattern_destroy(pat);
+}
+
+static void
+paint_test_patterns(cairo_t *cr, int width, int height)
+{
+ double gr_height, gr_width;
+ int x, y;
+
+ y = height * 0.10;
+ gr_width = width * 0.75;
+ gr_height = height * 0.08;
+ x = (width / 2) - (gr_width / 2);
+
+ kmstest_paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 0, 0);
+
+ y += gr_height;
+ kmstest_paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 1, 0);
+
+ y += gr_height;
+ kmstest_paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 0, 1);
+
+ y += gr_height;
+ kmstest_paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 1, 1);
+}
+
+int kmstest_cairo_printf_line(cairo_t *cr, enum kmstest_text_align align,
+ double yspacing, const char *fmt, ...)
+{
+ double x, y, xofs, yofs;
+ cairo_text_extents_t extents;
+ char *text;
+ va_list ap;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = vasprintf(&text, fmt, ap);
+ assert(ret >= 0);
+ va_end(ap);
+
+ cairo_text_extents(cr, text, &extents);
+
+ xofs = yofs = 0;
+ if (align & align_right)
+ xofs = -extents.width;
+ else if (align & align_hcenter)
+ xofs = -extents.width / 2;
+
+ if (align & align_top)
+ yofs = extents.height;
+ else if (align & align_vcenter)
+ yofs = extents.height / 2;
+
+ cairo_get_current_point(cr, &x, &y);
+ if (xofs || yofs)
+ cairo_rel_move_to(cr, xofs, yofs);
+
+ cairo_text_path(cr, text);
+ cairo_set_source_rgb(cr, 0, 0, 0);
+ cairo_stroke_preserve(cr);
+ cairo_set_source_rgb(cr, 1, 1, 1);
+ cairo_fill(cr);
+
+ cairo_move_to(cr, x, y + extents.height + yspacing);
+
+ free(text);
+
+ return extents.width;
+}
+
+static void
+paint_marker(cairo_t *cr, int x, int y)
+{
+ enum kmstest_text_align align;
+ int xoff, yoff;
+
+ cairo_move_to(cr, x, y - 20);
+ cairo_line_to(cr, x, y + 20);
+ cairo_move_to(cr, x - 20, y);
+ cairo_line_to(cr, x + 20, y);
+ cairo_new_sub_path(cr);
+ cairo_arc(cr, x, y, 10, 0, M_PI * 2);
+ cairo_set_line_width(cr, 4);
+ cairo_set_source_rgb(cr, 0, 0, 0);
+ cairo_stroke_preserve(cr);
+ cairo_set_source_rgb(cr, 1, 1, 1);
+ cairo_set_line_width(cr, 2);
+ cairo_stroke(cr);
+
+ xoff = x ? -20 : 20;
+ align = x ? align_right : align_left;
+
+ yoff = y ? -20 : 20;
+ align |= y ? align_bottom : align_top;
+
+ cairo_move_to(cr, x + xoff, y + yoff);
+ cairo_set_font_size(cr, 18);
+ kmstest_cairo_printf_line(cr, align, 0, "(%d, %d)", x, y);
+}
+
+void kmstest_paint_test_pattern(cairo_t *cr, int width, int height)
+{
+ paint_test_patterns(cr, width, height);
+
+ cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
+
+ /* Paint corner markers */
+ paint_marker(cr, 0, 0);
+ paint_marker(cr, width, 0);
+ paint_marker(cr, 0, height);
+ paint_marker(cr, width, height);
+
+ assert(!cairo_status(cr));
+}
+
+void kmstest_paint_image(cairo_t *cr, const char *filename,
+ int dst_x, int dst_y, int dst_width, int dst_height)
+{
+ cairo_surface_t *image;
+ int img_width, img_height;
+ double scale_x, scale_y;
+
+ image = cairo_image_surface_create_from_png(filename);
+ assert(cairo_surface_status(image) == CAIRO_STATUS_SUCCESS);
+
+ img_width = cairo_image_surface_get_width(image);
+ img_height = cairo_image_surface_get_height(image);
+
+ scale_x = (double)dst_width / img_width;
+ scale_y = (double)dst_height / img_height;
+
+ cairo_save(cr);
+
+ cairo_translate(cr, dst_x, dst_y);
+ cairo_scale(cr, scale_x, scale_y);
+ cairo_set_source_surface(cr, image, 0, 0);
+ cairo_paint(cr);
+
+ cairo_surface_destroy(image);
+
+ cairo_restore(cr);
+}
+
+#define DF(did, cid, _bpp, _depth) \
+ { DRM_FORMAT_##did, CAIRO_FORMAT_##cid, # did, _bpp, _depth }
+static struct format_desc_struct {
+ uint32_t drm_id;
+ cairo_format_t cairo_id;
+ const char *name;
+ int bpp;
+ int depth;
+} format_desc[] = {
+ DF(RGB565, RGB16_565, 16, 16),
+ DF(RGB888, INVALID, 24, 24),
+ DF(XRGB8888, RGB24, 32, 24),
+ DF(XRGB2101010, RGB30, 32, 30),
+ DF(ARGB8888, ARGB32, 32, 32),
+};
+#undef DF
+
+#define for_each_format(f) \
+ for (f = format_desc; f - format_desc < ARRAY_SIZE(format_desc); f++)
+
+static uint32_t bpp_depth_to_drm_format(int bpp, int depth)
+{
+ struct format_desc_struct *f;
+
+ for_each_format(f)
+ if (f->bpp == bpp && f->depth == depth)
+ return f->drm_id;
+
+ abort();
+}
+
+/* Return fb_id on success, 0 on error */
+unsigned int kmstest_create_fb(int fd, int width, int height, int bpp,
+ int depth, bool tiled, struct kmstest_fb *fb)
+{
+ memset(fb, 0, sizeof(*fb));
+
+ if (create_bo_for_fb(fd, width, height, bpp, tiled, &fb->gem_handle,
+ &fb->size, &fb->stride) < 0)
+ return 0;
+
+ if (drmModeAddFB(fd, width, height, depth, bpp, fb->stride,
+ fb->gem_handle, &fb->fb_id) < 0) {
+ gem_close(fd, fb->gem_handle);
+
+ return 0;
+ }
+
+ fb->width = width;
+ fb->height = height;
+ fb->tiling = tiled;
+ fb->drm_format = bpp_depth_to_drm_format(bpp, depth);
+
+ return fb->fb_id;
+}
+
+uint32_t drm_format_to_bpp(uint32_t drm_format)
+{
+ struct format_desc_struct *f;
+
+ for_each_format(f)
+ if (f->drm_id == drm_format)
+ return f->bpp;
+
+ abort();
+}
+
+unsigned int kmstest_create_fb2(int fd, int width, int height, uint32_t format,
+ bool tiled, struct kmstest_fb *fb)
+{
+ uint32_t handles[4];
+ uint32_t pitches[4];
+ uint32_t offsets[4];
+ uint32_t fb_id;
+ int bpp;
+ int ret;
+
+ memset(fb, 0, sizeof(*fb));
+
+ bpp = drm_format_to_bpp(format);
+ ret = create_bo_for_fb(fd, width, height, bpp, tiled, &fb->gem_handle,
+ &fb->size, &fb->stride);
+ if (ret < 0)
+ return ret;
+
+ memset(handles, 0, sizeof(handles));
+ handles[0] = fb->gem_handle;
+ memset(pitches, 0, sizeof(pitches));
+ pitches[0] = fb->stride;
+ memset(offsets, 0, sizeof(offsets));
+ if (drmModeAddFB2(fd, width, height, format, handles, pitches,
+ offsets, &fb_id, 0) < 0) {
+ gem_close(fd, fb->gem_handle);
+
+ return 0;
+ }
+
+ fb->width = width;
+ fb->height = height;
+ fb->tiling = tiled;
+ fb->drm_format = format;
+ fb->fb_id = fb_id;
+
+ return fb_id;
+}
+
+static cairo_format_t drm_format_to_cairo(uint32_t drm_format)
+{
+ struct format_desc_struct *f;
+
+ for_each_format(f)
+ if (f->drm_id == drm_format)
+ return f->cairo_id;
+
+ abort();
+}
+
+static cairo_surface_t *create_image_surface(int fd, struct kmstest_fb *fb)
+{
+ cairo_surface_t *surface;
+ cairo_format_t cformat;
+ void *fb_ptr;
+
+ cformat = drm_format_to_cairo(fb->drm_format);
+ fb_ptr = gem_mmap(fd, fb->gem_handle, fb->size, PROT_READ | PROT_WRITE);
+ surface = cairo_image_surface_create_for_data((unsigned char *)fb_ptr,
+ cformat, fb->width,
+ fb->height, fb->stride);
+ assert(surface);
+
+ return surface;
+}
+
+static cairo_t *create_cairo_ctx(int fd, struct kmstest_fb *fb)
+{
+ cairo_t *cr;
+ cairo_surface_t *surface;
+
+ surface = create_image_surface(fd, fb);
+ cr = cairo_create(surface);
+ cairo_surface_destroy(surface);
+
+ return cr;
+}
+
+void kmstest_write_fb(int fd, struct kmstest_fb *fb, const char *filename)
+{
+ cairo_surface_t *surface;
+ cairo_status_t status;
+
+ surface = create_image_surface(fd, fb);
+ status = cairo_surface_write_to_png(surface, filename);
+ assert(status == CAIRO_STATUS_SUCCESS);
+ cairo_surface_destroy(surface);
+}
+
+cairo_t *kmstest_get_cairo_ctx(int fd, struct kmstest_fb *fb)
+{
+
+ if (!fb->cairo_ctx)
+ fb->cairo_ctx = create_cairo_ctx(fd, fb);
+
+ gem_set_domain(fd, fb->gem_handle, I915_GEM_DOMAIN_CPU,
+ I915_GEM_DOMAIN_CPU);
+
+ return fb->cairo_ctx;
+}
+
+void kmstest_remove_fb(int fd, struct kmstest_fb *fb)
+{
+ if (fb->cairo_ctx)
+ cairo_destroy(fb->cairo_ctx);
+ do_or_die(drmModeRmFB(fd, fb->fb_id));
+ gem_close(fd, fb->gem_handle);
+}
+
+const char *kmstest_format_str(uint32_t drm_format)
+{
+ struct format_desc_struct *f;
+
+ for_each_format(f)
+ if (f->drm_id == drm_format)
+ return f->name;
+
+ return "invalid";
+}
+
+const char *kmstest_pipe_str(int pipe)
+{
+ const char *str[] = { "A", "B", "C" };
+
+ if (pipe > 2)
+ return "invalid";
+
+ return str[pipe];
+}
+
+void kmstest_get_all_formats(const uint32_t **formats, int *format_count)
+{
+ static uint32_t *drm_formats;
+
+ if (!drm_formats) {
+ struct format_desc_struct *f;
+ uint32_t *format;
+
+ drm_formats = calloc(ARRAY_SIZE(format_desc),
+ sizeof(*drm_formats));
+ format = &drm_formats[0];
+ for_each_format(f)
+ *format++ = f->drm_id;
+ }
+
+ *formats = drm_formats;
+ *format_count = ARRAY_SIZE(format_desc);
+}
+
+struct type_name {
+ int type;
+ const char *name;
+};
+
+#define type_name_fn(res) \
+const char * kmstest_##res##_str(int type) { \
+ unsigned int i; \
+ for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \
+ if (res##_names[i].type == type) \
+ return res##_names[i].name; \
+ } \
+ return "(invalid)"; \
+}
+
+struct type_name encoder_type_names[] = {
+ { DRM_MODE_ENCODER_NONE, "none" },
+ { DRM_MODE_ENCODER_DAC, "DAC" },
+ { DRM_MODE_ENCODER_TMDS, "TMDS" },
+ { DRM_MODE_ENCODER_LVDS, "LVDS" },
+ { DRM_MODE_ENCODER_TVDAC, "TVDAC" },
+};
+
+type_name_fn(encoder_type)
+
+struct type_name connector_status_names[] = {
+ { DRM_MODE_CONNECTED, "connected" },
+ { DRM_MODE_DISCONNECTED, "disconnected" },
+ { DRM_MODE_UNKNOWNCONNECTION, "unknown" },
+};
+
+type_name_fn(connector_status)
+
+struct type_name connector_type_names[] = {
+ { DRM_MODE_CONNECTOR_Unknown, "unknown" },
+ { DRM_MODE_CONNECTOR_VGA, "VGA" },
+ { DRM_MODE_CONNECTOR_DVII, "DVI-I" },
+ { DRM_MODE_CONNECTOR_DVID, "DVI-D" },
+ { DRM_MODE_CONNECTOR_DVIA, "DVI-A" },
+ { DRM_MODE_CONNECTOR_Composite, "composite" },
+ { DRM_MODE_CONNECTOR_SVIDEO, "s-video" },
+ { DRM_MODE_CONNECTOR_LVDS, "LVDS" },
+ { DRM_MODE_CONNECTOR_Component, "component" },
+ { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" },
+ { DRM_MODE_CONNECTOR_DisplayPort, "DP" },
+ { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" },
+ { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" },
+ { DRM_MODE_CONNECTOR_TV, "TV" },
+ { DRM_MODE_CONNECTOR_eDP, "eDP" },
+};
+
+type_name_fn(connector_type)
+
+static const char *mode_stereo_name(const drmModeModeInfo *mode)
+{
+ switch (mode->flags & DRM_MODE_FLAG_3D_MASK) {
+ case DRM_MODE_FLAG_3D_FRAME_PACKING:
+ return "FP";
+ case DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE:
+ return "FA";
+ case DRM_MODE_FLAG_3D_LINE_ALTERNATIVE:
+ return "LA";
+ case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL:
+ return "SBSF";
+ case DRM_MODE_FLAG_3D_L_DEPTH:
+ return "LD";
+ case DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH:
+ return "LDGFX";
+ case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM:
+ return "TB";
+ case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF:
+ return "SBSH";
+ default:
+ return NULL;
+ }
+}
+
+void kmstest_dump_mode(drmModeModeInfo *mode)
+{
+ const char *stereo = mode_stereo_name(mode);
+
+ printf(" %s %d %d %d %d %d %d %d %d %d 0x%x 0x%x %d%s%s%s\n",
+ mode->name,
+ mode->vrefresh,
+ mode->hdisplay,
+ mode->hsync_start,
+ mode->hsync_end,
+ mode->htotal,
+ mode->vdisplay,
+ mode->vsync_start,
+ mode->vsync_end,
+ mode->vtotal,
+ mode->flags,
+ mode->type,
+ mode->clock,
+ stereo ? " (3D:" : "",
+ stereo ? stereo : "",
+ stereo ? ")" : "");
+ fflush(stdout);
+}
+
+int kmstest_get_pipe_from_crtc_id(int fd, int crtc_id)
+{
+ struct drm_i915_get_pipe_from_crtc_id pfci;
+ int ret;
+
+ memset(&pfci, 0, sizeof(pfci));
+ pfci.crtc_id = crtc_id;
+ ret = drmIoctl(fd, DRM_IOCTL_I915_GET_PIPE_FROM_CRTC_ID, &pfci);
+ igt_assert(ret == 0);
+
+ return pfci.pipe;
+}
+
+static signed long set_vt_mode(unsigned long mode)
+{
+ int fd;
+ unsigned long prev_mode;
+
+ fd = open("/dev/tty0", O_RDONLY);
+ if (fd < 0)
+ return -errno;
+
+ prev_mode = 0;
+ if (drmIoctl(fd, KDGETMODE, &prev_mode))
+ goto err;
+ if (drmIoctl(fd, KDSETMODE, (void *)mode))
+ goto err;
+
+ close(fd);
+
+ return prev_mode;
+err:
+ close(fd);
+
+ return -errno;
+}
+
+static unsigned long orig_vt_mode = -1UL;
+
+static void restore_vt_mode_at_exit(int sig)
+{
+ if (orig_vt_mode != -1UL)
+ set_vt_mode(orig_vt_mode);
+}
+
+/*
+ * Set the VT to graphics mode and install an exit handler to restore the
+ * original mode.
+ */
+
+void igt_set_vt_graphics_mode(void)
+{
+ igt_install_exit_handler(restore_vt_mode_at_exit);
+
+ igt_disable_exit_handler();
+ orig_vt_mode = set_vt_mode(KD_GRAPHICS);
+ if (orig_vt_mode < 0)
+ orig_vt_mode = -1UL;
+ igt_enable_exit_handler();
+
+ igt_assert(orig_vt_mode >= 0);
+}
+
+int kmstest_get_connector_default_mode(int drm_fd, drmModeConnector *connector,
+ drmModeModeInfo *mode)
+{
+ drmModeRes *resources;
+ int i;
+
+ resources = drmModeGetResources(drm_fd);
+ if (!resources) {
+ perror("drmModeGetResources failed");
+
+ return -1;
+ }
+
+ if (!connector->count_modes) {
+ fprintf(stderr, "no modes for connector %d\n",
+ connector->connector_id);
+ drmModeFreeResources(resources);
+
+ return -1;
+ }
+
+ for (i = 0; i < connector->count_modes; i++) {
+ if (i == 0 ||
+ connector->modes[i].type & DRM_MODE_TYPE_PREFERRED) {
+ *mode = connector->modes[i];
+ if (mode->type & DRM_MODE_TYPE_PREFERRED)
+ break;
+ }
+ }
+
+ drmModeFreeResources(resources);
+
+ return 0;
+}
+
+int kmstest_get_connector_config(int drm_fd, uint32_t connector_id,
+ unsigned long crtc_idx_mask,
+ struct kmstest_connector_config *config)
+{
+ drmModeRes *resources;
+ drmModeConnector *connector;
+ drmModeEncoder *encoder;
+ int i, j;
+
+ resources = drmModeGetResources(drm_fd);
+ if (!resources) {
+ perror("drmModeGetResources failed");
+ goto err1;
+ }
+
+ /* First, find the connector & mode */
+ connector = drmModeGetConnector(drm_fd, connector_id);
+ if (!connector)
+ goto err2;
+
+ if (connector->connection != DRM_MODE_CONNECTED)
+ goto err3;
+
+ if (!connector->count_modes) {
+ fprintf(stderr, "connector %d has no modes\n", connector_id);
+ goto err3;
+ }
+
+ if (connector->connector_id != connector_id) {
+ fprintf(stderr, "connector id doesn't match (%d != %d)\n",
+ connector->connector_id, connector_id);
+ goto err3;
+ }
+
+ /*
+ * Find given CRTC if crtc_id != 0 or else the first CRTC not in use.
+ * In both cases find the first compatible encoder and skip the CRTC
+ * if there is non such.
+ */
+ encoder = NULL; /* suppress GCC warning */
+ for (i = 0; i < resources->count_crtcs; i++) {
+ if (!resources->crtcs[i] || !(crtc_idx_mask & (1 << i)))
+ continue;
+
+ /* Now get a compatible encoder */
+ for (j = 0; j < connector->count_encoders; j++) {
+ encoder = drmModeGetEncoder(drm_fd,
+ connector->encoders[j]);
+
+ if (!encoder) {
+ fprintf(stderr, "could not get encoder %d: %s\n",
+ resources->encoders[j], strerror(errno));
+
+ continue;
+ }
+
+ if (encoder->possible_crtcs & (1 << i))
+ goto found;
+
+ drmModeFreeEncoder(encoder);
+ }
+ }
+
+ goto err3;
+
+found:
+ if (kmstest_get_connector_default_mode(drm_fd, connector,
+ &config->default_mode) < 0)
+ goto err4;
+
+ config->connector = connector;
+ config->encoder = encoder;
+ config->crtc = drmModeGetCrtc(drm_fd, resources->crtcs[i]);
+ config->crtc_idx = i;
+ config->pipe = kmstest_get_pipe_from_crtc_id(drm_fd,
+ config->crtc->crtc_id);
+
+ drmModeFreeResources(resources);
+
+ return 0;
+err4:
+ drmModeFreeEncoder(encoder);
+err3:
+ drmModeFreeConnector(connector);
+err2:
+ drmModeFreeResources(resources);
+err1:
+ return -1;
+}
+
+void kmstest_free_connector_config(struct kmstest_connector_config *config)
+{
+ drmModeFreeCrtc(config->crtc);
+ drmModeFreeEncoder(config->encoder);
+ drmModeFreeConnector(config->connector);
+}
+
diff --git a/lib/igt_kms.h b/lib/igt_kms.h
new file mode 100644
index 00000000..f61f8e53
--- /dev/null
+++ b/lib/igt_kms.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * 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 (including the next
+ * paragraph) 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.
+ *
+ */
+
+#ifndef __IGT_KMS_H__
+#define __IGT_KMS_H__
+
+#include <cairo.h>
+
+struct kmstest_connector_config {
+ drmModeCrtc *crtc;
+ drmModeConnector *connector;
+ drmModeEncoder *encoder;
+ drmModeModeInfo default_mode;
+ int crtc_idx;
+ int pipe;
+};
+
+int kmstest_get_connector_default_mode(int drm_fd, drmModeConnector *connector,
+ drmModeModeInfo *mode);
+int kmstest_get_connector_config(int drm_fd, uint32_t connector_id,
+ unsigned long crtc_idx_mask,
+ struct kmstest_connector_config *config);
+void kmstest_free_connector_config(struct kmstest_connector_config *config);
+
+/* helpers to create nice-looking framebuffers */
+struct kmstest_fb {
+ uint32_t fb_id;
+ uint32_t gem_handle;
+ uint32_t drm_format;
+ int width;
+ int height;
+ int depth;
+ unsigned stride;
+ unsigned tiling;
+ unsigned size;
+ cairo_t *cairo_ctx;
+};
+
+enum kmstest_text_align {
+ align_left,
+ align_bottom = align_left,
+ align_right = 0x01,
+ align_top = 0x02,
+ align_vcenter = 0x04,
+ align_hcenter = 0x08,
+};
+
+int kmstest_cairo_printf_line(cairo_t *cr, enum kmstest_text_align align,
+ double yspacing, const char *fmt, ...)
+ __attribute__((format (printf, 4, 5)));
+
+unsigned int kmstest_create_fb(int fd, int width, int height, int bpp,
+ int depth, bool tiled,
+ struct kmstest_fb *fb_info);
+unsigned int kmstest_create_fb2(int fd, int width, int height, uint32_t format,
+ bool tiled, struct kmstest_fb *fb);
+void kmstest_remove_fb(int fd, struct kmstest_fb *fb_info);
+cairo_t *kmstest_get_cairo_ctx(int fd, struct kmstest_fb *fb);
+void kmstest_paint_color(cairo_t *cr, int x, int y, int w, int h,
+ double r, double g, double b);
+void kmstest_paint_color_alpha(cairo_t *cr, int x, int y, int w, int h,
+ double r, double g, double b, double a);
+void kmstest_paint_color_gradient(cairo_t *cr, int x, int y, int w, int h,
+ int r, int g, int b);
+void kmstest_paint_test_pattern(cairo_t *cr, int width, int height);
+void kmstest_paint_image(cairo_t *cr, const char *filename,
+ int dst_x, int dst_y, int dst_width, int dst_height);
+void kmstest_write_fb(int fd, struct kmstest_fb *fb, const char *filename);
+void kmstest_dump_mode(drmModeModeInfo *mode);
+int kmstest_get_pipe_from_crtc_id(int fd, int crtc_id);
+const char *kmstest_format_str(uint32_t drm_format);
+const char *kmstest_pipe_str(int pipe);
+void kmstest_get_all_formats(const uint32_t **formats, int *format_count);
+const char *kmstest_encoder_type_str(int type);
+const char *kmstest_connector_status_str(int type);
+const char *kmstest_connector_type_str(int type);
+
+uint32_t drm_format_to_bpp(uint32_t drm_format);
+
+#endif /* __IGT_KMS_H__ */
+
diff --git a/tests/kms_cursor_crc.c b/tests/kms_cursor_crc.c
index 2c9ca359..4ecc9c82 100644
--- a/tests/kms_cursor_crc.c
+++ b/tests/kms_cursor_crc.c
@@ -33,6 +33,7 @@
#include "drmtest.h"
#include "igt_debugfs.h"
+#include "igt_kms.h"
enum cursor_type {
WHITE_VISIBLE,
diff --git a/tests/kms_flip.c b/tests/kms_flip.c
index 10d8ae0a..daaed8ea 100644
--- a/tests/kms_flip.c
+++ b/tests/kms_flip.c
@@ -40,6 +40,7 @@
#include "drmtest.h"
#include "testdisplay.h"
#include "rendercopy.h"
+#include "igt_kms.h"
#define TEST_DPMS (1 << 0)
#define TEST_WITH_DUMMY_BCS (1 << 1)
diff --git a/tests/kms_pipe_crc_basic.c b/tests/kms_pipe_crc_basic.c
index 25452331..3bc9eb0e 100644
--- a/tests/kms_pipe_crc_basic.c
+++ b/tests/kms_pipe_crc_basic.c
@@ -31,6 +31,7 @@
#include "drmtest.h"
#include "igt_debugfs.h"
+#include "igt_kms.h"
typedef struct {
struct kmstest_connector_config config;
diff --git a/tests/kms_render.c b/tests/kms_render.c
index dc009322..055ebbb8 100644
--- a/tests/kms_render.c
+++ b/tests/kms_render.c
@@ -36,6 +36,7 @@
#include "intel_bufmgr.h"
#include "intel_batchbuffer.h"
#include "intel_gpu_tools.h"
+#include "igt_kms.h"
drmModeRes *resources;
int drm_fd;
diff --git a/tests/kms_setmode.c b/tests/kms_setmode.c
index 6bc7db15..3d18fc7b 100644
--- a/tests/kms_setmode.c
+++ b/tests/kms_setmode.c
@@ -38,6 +38,7 @@
#include "intel_bufmgr.h"
#include "intel_batchbuffer.h"
#include "intel_gpu_tools.h"
+#include "igt_kms.h"
#define MAX_CONNECTORS 10
#define MAX_CRTCS 3
diff --git a/tests/pm_pc8.c b/tests/pm_pc8.c
index cddb11bd..e17be1b7 100644
--- a/tests/pm_pc8.c
+++ b/tests/pm_pc8.c
@@ -45,6 +45,7 @@
#include "intel_batchbuffer.h"
#include "intel_gpu_tools.h"
#include "i915_drm.h"
+#include "igt_kms.h"
#define MSR_PC8_RES 0x630
#define MSR_PC9_RES 0x631
diff --git a/tests/testdisplay.c b/tests/testdisplay.c
index fd172f3e..dd9e56dd 100644
--- a/tests/testdisplay.c
+++ b/tests/testdisplay.c
@@ -65,6 +65,7 @@
#include "i915_drm.h"
#include "drmtest.h"
#include "testdisplay.h"
+#include "igt_kms.h"
#include <stdlib.h>
#include <signal.h>