From patchwork Tue Nov 12 11:50:38 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: oscar.mateo@intel.com X-Patchwork-Id: 3171591 Return-Path: X-Original-To: patchwork-intel-gfx@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 16433C045B for ; Tue, 12 Nov 2013 10:54:23 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 48E522037F for ; Tue, 12 Nov 2013 10:54:20 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 5AA3620216 for ; Tue, 12 Nov 2013 10:54:17 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id E8CECFA935; Tue, 12 Nov 2013 02:54:15 -0800 (PST) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by gabe.freedesktop.org (Postfix) with ESMTP id E2D73FA937 for ; Tue, 12 Nov 2013 02:54:12 -0800 (PST) Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga101.jf.intel.com with ESMTP; 12 Nov 2013 02:54:12 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.93,535,1378882800"; d="scan'208";a="433802903" Received: from omateolo-linux2.isw.intel.com ([10.102.226.43]) by orsmga002.jf.intel.com with ESMTP; 12 Nov 2013 02:54:10 -0800 From: oscar.mateo@intel.com To: intel-gfx@lists.freedesktop.org Date: Tue, 12 Nov 2013 11:50:38 +0000 Message-Id: <1384257045-15524-5-git-send-email-oscar.mateo@intel.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1384257045-15524-1-git-send-email-oscar.mateo@intel.com> References: <1384257045-15524-1-git-send-email-oscar.mateo@intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] =?utf-8?q?=5BPATCH_v2_04/11=5D_lib=3A_Move_kms_stuff_?= =?utf-8?q?from_drmtest=2Ec_over_to_igt=5Fkms=2Ec?= X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: intel-gfx-bounces@lists.freedesktop.org Errors-To: intel-gfx-bounces@lists.freedesktop.org X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Oscar Mateo This makes cairo dependencies easier to handle. Otherwise, we would have to litter drmtest all over with "#ifndef ANDROID" Signed-off-by: Oscar Mateo --- lib/Makefile.sources | 2 + lib/drmtest.c | 732 ------------------------------------------ lib/drmtest.h | 72 ----- lib/igt_kms.c | 764 ++++++++++++++++++++++++++++++++++++++++++++ lib/igt_kms.h | 102 ++++++ tests/kms_cursor_crc.c | 1 + tests/kms_flip.c | 1 + tests/kms_pipe_crc_basic.c | 1 + tests/kms_render.c | 1 + tests/kms_setmode.c | 1 + tests/pm_pc8.c | 1 + tests/testdisplay.c | 1 + 12 files changed, 875 insertions(+), 804 deletions(-) create mode 100644 lib/igt_kms.c create mode 100644 lib/igt_kms.h diff --git a/lib/Makefile.sources b/lib/Makefile.sources index d71f837..78e2034 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 d8fc60f..38463f8 100644 --- a/lib/drmtest.c +++ b/lib/drmtest.c @@ -35,13 +35,10 @@ #include #include #include -#include #include #include -#include #include #include -#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 a9fd0bc..ce9d18d 100644 --- a/lib/drmtest.h +++ b/lib/drmtest.h @@ -34,7 +34,6 @@ #include #include #include -#include #include #include @@ -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 0000000..14efea0 --- /dev/null +++ b/lib/igt_kms.c @@ -0,0 +1,764 @@ +/* + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#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 0000000..f61f8e5 --- /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 + +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 2c9ca35..4ecc9c8 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 10d8ae0..daaed8e 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 2545233..3bc9eb0 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 dc00932..055ebbb 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 6bc7db1..3d18fc7 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 cddb11b..e17be1b 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 fd172f3..dd9e56d 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 #include