diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c index cfdf7617a65a..9707ca48ec70 100644 --- a/lib/igt_chamelium.c +++ b/lib/igt_chamelium.c @@ -1172,7 +1174,7 @@ static pixman_image_t *convert_frame_format(pixman_image_t *src, return converted; } -static cairo_surface_t *convert_frame_dump_argb32(const struct chamelium_frame_dump *dump) +cairo_surface_t *convert_frame_dump_argb32(const struct chamelium_frame_dump *dump) { cairo_surface_t *dump_surface; pixman_image_t *image_bgr; diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h index 33362b266ce4..5666ebb1134c 100644 --- a/lib/igt_chamelium.h +++ b/lib/igt_chamelium.h @@ -157,4 +157,6 @@ void chamelium_crop_analog_frame(struct chamelium_frame_dump *dump, int width, void chamelium_destroy_frame_dump(struct chamelium_frame_dump *dump); void chamelium_destroy_audio_file(struct chamelium_audio_file *audio_file); +cairo_surface_t *convert_frame_dump_argb32(const struct chamelium_frame_dump *dump); + #endif /* IGT_CHAMELIUM_H */ diff --git a/tests/kms_draw_crc.c b/tests/kms_draw_crc.c index ea14db9a0a26..85dd066dc0dd 100644 --- a/tests/kms_draw_crc.c +++ b/tests/kms_draw_crc.c @@ -31,8 +31,11 @@ struct modeset_params { uint32_t crtc_id; uint32_t connector_id; + enum pipe pipe; drmModeModeInfoPtr mode; -}; + struct chamelium *chamelium; + struct chamelium_port *cham_port; +} ms; int drm_fd; drmModeResPtr drm_res; @@ -60,7 +63,46 @@ struct base_crc { }; struct base_crc base_crcs[N_FORMATS]; -struct modeset_params ms; +static drmModeConnection +reprobe_connector(struct chamelium_port *port) +{ + drmModeConnector *connector; + drmModeConnection status; + + igt_debug("Reprobing %s...\n", chamelium_port_get_name(port)); + connector = chamelium_port_get_connector(ms.chamelium, port, true); + igt_assert(connector); + status = connector->connection; + + drmModeFreeConnector(connector); + return status; +} + +static void +wait_for_connector(struct chamelium_port *port, + drmModeConnection status) +{ + bool finished = false; + + igt_debug("Waiting for %s to %sconnect...\n", + chamelium_port_get_name(port), + status == DRM_MODE_DISCONNECTED ? "dis" : ""); + + /* + * Rely on simple reprobing so we don't fail tests that don't require + * that hpd events work in the event that hpd doesn't work on the system + */ + igt_until_timeout(20) { + if (reprobe_connector(port) == status) { + finished = true; + return; + } + + usleep(50000); + } + + igt_assert(finished); +} static void find_modeset_params(void) { @@ -69,9 +111,40 @@ static void find_modeset_params(void) drmModeConnectorPtr connector = NULL; drmModeModeInfoPtr mode = NULL; + ms.chamelium = chamelium_init(drm_fd); + if (ms.chamelium) { + int count; + struct chamelium_port **ports; + + ports = chamelium_get_ports(ms.chamelium, &count); + + for (i = count - 1; i >= 0; i--) { + int edid_id; + unsigned char *edid; + size_t edid_len; + struct chamelium_port *port = ports[i]; + + kmstest_edid_add_4k(igt_kms_get_base_edid(), EDID_LENGTH, &edid, &edid_len); + edid_id = chamelium_new_edid(ms.chamelium, edid); + + chamelium_port_set_edid(ms.chamelium, port, edid_id); + chamelium_plug(ms.chamelium, port); + wait_for_connector(port, DRM_MODE_CONNECTED); + + ms.cham_port = port; + connector = chamelium_port_get_connector(ms.chamelium, + ports[i], false); + mode = &connector->modes[0]; + break; + } + } + for (i = 0; i < drm_res->count_connectors; i++) { drmModeConnectorPtr c = drm_connectors[i]; + if (connector) + break; + if (c->count_modes) { connector = c; mode = &c->modes[0]; @@ -87,7 +160,7 @@ static void find_modeset_params(void) ms.connector_id = connector->connector_id; ms.crtc_id = crtc_id; ms.mode = mode; - + ms.pipe = kmstest_get_crtc_idx(drm_res, crtc_id); } static uint32_t get_color(uint32_t drm_format, bool r, bool g, bool b) @@ -246,6 +319,264 @@ static void fill_fb_subtest(void) igt_remove_fb(drm_fd, &fb); } +enum color { + COLOR_RED, + COLOR_GREEN, + COLOR_BLUE, + COLOR_MAGENTA, + COLOR_CYAN, + COLOR_SCND_BG, + COLOR_PRIM_BG = COLOR_BLUE, + COLOR_OFFSCREEN_BG = COLOR_SCND_BG, +}; + +static uint32_t pick_color(struct igt_fb *fb, enum color ecolor) +{ + uint32_t color, r, g, b, b2, a; + bool alpha = false; + + switch (fb->drm_format) { + case DRM_FORMAT_RGB565: + a = 0x0; + r = 0x1F << 11; + g = 0x3F << 5; + b = 0x1F; + b2 = 0x10; + break; + case DRM_FORMAT_ARGB8888: + alpha = true; + case DRM_FORMAT_XRGB8888: + a = 0xFF << 24; + r = 0xFF << 16; + g = 0xFF << 8; + b = 0xFF; + b2 = 0x80; + break; + case DRM_FORMAT_ARGB2101010: + alpha = true; + case DRM_FORMAT_XRGB2101010: + a = 0x3 << 30; + r = 0x3FF << 20; + g = 0x3FF << 10; + b = 0x3FF; + b2 = 0x200; + break; + default: + igt_assert(false); + } + + switch (ecolor) { + case COLOR_RED: + color = r; + break; + case COLOR_GREEN: + color = g; + break; + case COLOR_BLUE: + color = b; + break; + case COLOR_MAGENTA: + color = r | b; + break; + case COLOR_CYAN: + color = g | b; + break; + case COLOR_SCND_BG: + color = b2; + break; + default: + igt_assert(false); + } + + if (alpha) + color |= a; + + return color; +} + +struct rect { + int x; + int y; + int w; + int h; + uint32_t color; +}; + +static struct rect pat1_get_rect(struct igt_fb *fb, int r) +{ + struct rect rect; + + switch (r) { + case 0: + rect.x = 0; + rect.y = 0; + rect.w = fb->width; + rect.h = fb->height; + rect.color = pick_color(fb, COLOR_BLUE); + break; + case 1: + rect.x = 0; + rect.y = 0; + rect.w = fb->width / 8; + rect.h = fb->height / 8; + rect.color = pick_color(fb, COLOR_GREEN); + break; + case 2: + rect.x = fb->width / 8 * 4; + rect.y = fb->height / 8 * 4; + rect.w = fb->width / 8 * 2; + rect.h = fb->height / 8 * 2; + rect.color = pick_color(fb, COLOR_RED); + break; + case 3: + rect.x = fb->width / 16 + 1; + rect.y = fb->height / 16 + 1; + rect.w = fb->width / 8 + 1; + rect.h = fb->height / 8 + 1; + rect.color = pick_color(fb, COLOR_MAGENTA); + break; + case 4: + rect.x = fb->width - 1; + rect.y = fb->height - 1; + rect.w = 1; + rect.h = 1; + rect.color = pick_color(fb, COLOR_CYAN); + break; + default: + igt_assert(false); + } + + return rect; +} + +static void dump_frame(int idx, char *name) +{ + struct chamelium_frame_dump *frame = chamelium_read_captured_frame(ms.chamelium, idx); + cairo_surface_t *surf; + igt_assert(frame); + + surf = convert_frame_dump_argb32(frame); + igt_assert_eq(cairo_surface_write_to_png(surf, name), CAIRO_STATUS_SUCCESS); + cairo_surface_destroy(surf); + chamelium_destroy_frame_dump(frame); +} + +static void check_crc_equal(igt_crc_t *ref, struct igt_fb *fb_ref, igt_crc_t *crc, struct igt_fb *fb, igt_display_t *display, igt_plane_t *plane, struct igt_fb *panic_fb) +{ + int count, i = 0, lim; + cairo_surface_t *surf; + igt_crc_t *crcs; + char name[256]; + + if (!ms.chamelium) + return igt_assert_crc_equal(ref, crc); + + if (igt_check_crc_equal(ref, crc)) + return; + + igt_wait_for_vblank(drm_fd, ms.pipe); + igt_wait_for_vblank(drm_fd, ms.pipe); + igt_wait_for_vblank(drm_fd, ms.pipe); + igt_wait_for_vblank(drm_fd, ms.pipe); + igt_wait_for_vblank(drm_fd, ms.pipe); + igt_wait_for_vblank(drm_fd, ms.pipe); + chamelium_stop_capture(ms.chamelium, 0); + crcs = chamelium_read_captured_crcs(ms.chamelium, &count); + + lim = chamelium_get_frame_limit(ms.chamelium, ms.cham_port, 0, 0); + igt_info("Read %i of %i frames\n", count, lim); + + snprintf(name, sizeof(name), "p%u-reference.png", getpid()); + + surf = igt_get_cairo_surface(drm_fd, fb); + igt_assert_eq(cairo_surface_write_to_png(surf, name), CAIRO_STATUS_SUCCESS); + cairo_surface_destroy(surf); + + for (i = 0; i < count; i++) { + snprintf(name, sizeof(name), "p%u-frame-%02i.png", getpid(), i); + dump_frame(i, name); + } + + free(crcs); + + igt_assert(0); +} + +static void draw_dirtyfb_subtest(enum igt_draw_method method, + uint32_t format_index, uint64_t tiling) +{ + struct igt_fb fb_ref[5], fb, panic_fb; + int i, j; + uint32_t drm_format = formats[format_index]; + struct rect rect; + igt_crc_t ref_crc[5], crc; + uint32_t w = min(ms.mode->hdisplay * 2, 3840); + uint32_t h = min(ms.mode->vdisplay, 256); + igt_display_t display; + igt_plane_t *plane; + igt_pipe_t *pipe; + igt_output_t *output = NULL; + + igt_display_require(&display, drm_fd); + pipe = &display.pipes[ms.pipe]; + plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY); + for (i = 0; i < display.n_outputs; i++) + if (display.outputs[i].id == ms.connector_id) { + output = &display.outputs[i]; + break; + } + igt_assert(output); + + igt_output_set_pipe(output, ms.pipe); + igt_create_pattern_fb(drm_fd, ms.mode->hdisplay, ms.mode->vdisplay, drm_format, tiling, &panic_fb); + + for (i = 0; i < 5; i++) { + igt_create_fb(drm_fd, w, h, + drm_format, tiling, &fb_ref[i]); + + for (j = 0; j <= i; j++) { + rect = pat1_get_rect(&fb_ref[i], j); + + igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb_ref[i], IGT_DRAW_MMAP_GTT, + rect.x, rect.y, rect.w, rect.h, rect.color); + } + + gem_set_domain(drm_fd, fb_ref[i].gem_handle, I915_GEM_DOMAIN_GTT, 0); + + igt_plane_set_fb(plane, &fb_ref[i]); + igt_fb_set_size(NULL, plane, w, h); + igt_plane_set_size(plane, ms.mode->hdisplay, ms.mode->vdisplay); + igt_display_commit2(&display, COMMIT_ATOMIC); + + if (i == 0 && ms.cham_port) + chamelium_start_capture(ms.chamelium, ms.cham_port, 0, 0, 0, 0); + + igt_pipe_crc_collect_crc(pipe_crc, &ref_crc[i]); + } + + for (j = 0; j < 25; j++) { + igt_create_fb(drm_fd, w, h, drm_format, tiling, &fb); + igt_plane_set_fb(plane, &fb); + igt_fb_set_size(NULL, plane, w, h); + igt_plane_set_size(plane, ms.mode->hdisplay, ms.mode->vdisplay); + igt_display_commit2(&display, COMMIT_ATOMIC); + + for (i = 0; i < 5; i++) { + rect = pat1_get_rect(&fb, i); + + igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, method, + rect.x, rect.y, rect.w, rect.h, rect.color); + gem_set_domain(drm_fd, fb.gem_handle, I915_GEM_DOMAIN_GTT, 0); + igt_dirty_fb(drm_fd, &fb); + igt_wait_for_vblank(drm_fd, ms.pipe); + + igt_pipe_crc_collect_crc(pipe_crc, &crc); + check_crc_equal(&ref_crc[i], &fb_ref[i], &crc, &fb, &display, plane, &panic_fb); + } + igt_remove_fb(drm_fd, &fb); + } +} + static void setup_environment(void) { int i; @@ -268,7 +599,7 @@ static void setup_environment(void) drm_intel_bufmgr_gem_enable_reuse(bufmgr); find_modeset_params(); - pipe_crc = igt_pipe_crc_new(drm_fd, kmstest_get_crtc_idx(drm_res, ms.crtc_id), + pipe_crc = igt_pipe_crc_new(drm_fd, ms.pipe, INTEL_PIPE_CRC_SOURCE_AUTO); } @@ -332,6 +663,13 @@ igt_main tiling_str(tiling_idx)) draw_method_subtest(method, format_idx, tilings[tiling_idx]); + + igt_subtest_f("draw-dirtyfb-%s-%s-%s", + format_str(format_idx), + igt_draw_get_method_name(method), + tiling_str(tiling_idx)) + draw_dirtyfb_subtest(method, format_idx, + tilings[tiling_idx]); } } } igt_subtest("fill-fb")