2 * Copyright © 2013 Intel Corporation
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
32 #include "drm_fourcc.h"
35 #include "igt_debugfs.h"
37 #include "rendercopy.h"
46 TEST_PAGE_FLIP_AND_MMAP_CPU,
47 TEST_PAGE_FLIP_AND_MMAP_GTT,
48 TEST_PAGE_FLIP_AND_BLT,
49 TEST_PAGE_FLIP_AND_RENDER,
50 TEST_PAGE_FLIP_AND_CONTEXT,
54 struct kmstest_connector_config config;
56 struct kmstest_fb fb[2];
61 igt_debugfs_t debugfs;
62 drmModeRes *resources;
65 igt_pipe_crc_t **pipe_crc;
66 drm_intel_bufmgr *bufmgr;
67 drm_intel_context *ctx[2];
75 static const char *test_mode_str(enum test_mode mode)
77 static const char * const test_modes[] = {
78 [TEST_PAGE_FLIP] = "page_flip",
79 [TEST_MMAP_CPU] = "mmap_cpu",
80 [TEST_MMAP_GTT] = "mmap_gtt",
82 [TEST_RENDER] = "render",
83 [TEST_CONTEXT] = "context",
84 [TEST_PAGE_FLIP_AND_MMAP_CPU] = "page_flip_and_mmap_cpu",
85 [TEST_PAGE_FLIP_AND_MMAP_GTT] = "page_flip_and_mmap_gtt",
86 [TEST_PAGE_FLIP_AND_BLT] = "page_flip_and_blt",
87 [TEST_PAGE_FLIP_AND_RENDER] = "page_flip_and_render",
88 [TEST_PAGE_FLIP_AND_CONTEXT] = "page_flip_and_context",
91 return test_modes[mode];
94 static uint32_t create_fb(data_t *data,
96 double r, double g, double b,
97 struct kmstest_fb *fb)
102 fb_id = kmstest_create_fb2(data->drm_fd, w, h,
103 DRM_FORMAT_XRGB8888, true, fb);
106 cr = kmstest_get_cairo_ctx(data->drm_fd, fb);
107 kmstest_paint_color(cr, 0, 0, w, h, r, g, b);
108 igt_assert(cairo_status(cr) == 0);
114 connector_set_mode(data_t *data, connector_t *connector,
115 drmModeModeInfo *mode, uint32_t fb_id)
117 struct kmstest_connector_config *config = &connector->config;
121 fprintf(stdout, "Using pipe %c, %dx%d\n", pipe_name(config->pipe),
122 mode->hdisplay, mode->vdisplay);
125 ret = drmModeSetCrtc(data->drm_fd,
126 config->crtc->crtc_id,
129 &config->connector->connector_id,
132 igt_assert(ret == 0);
137 static void display_init(data_t *data)
139 data->resources = drmModeGetResources(data->drm_fd);
140 igt_assert(data->resources);
142 data->pipe_crc = calloc(data->resources->count_crtcs, sizeof(data->pipe_crc[0]));
145 static void display_fini(data_t *data)
147 free(data->pipe_crc);
150 static void fill_blt(data_t *data, uint32_t handle, unsigned char color)
152 drm_intel_bo *dst = gem_handle_to_libdrm_bo(data->bufmgr,
155 struct intel_batchbuffer *batch;
157 batch = intel_batchbuffer_alloc(data->bufmgr, data->devid);
161 OUT_BATCH(COLOR_BLT_CMD);
162 OUT_BATCH((1 << 24) | (0xf0 << 16) | 0);
163 OUT_BATCH(1 << 16 | 4);
164 OUT_RELOC(dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
168 intel_batchbuffer_flush(batch);
169 intel_batchbuffer_free(batch);
171 gem_bo_busy(data->drm_fd, handle);
174 static void scratch_buf_init(struct scratch_buf *buf, drm_intel_bo *bo)
178 buf->tiling = I915_TILING_X;
182 static void exec_nop(data_t *data, uint32_t handle, drm_intel_context *context)
185 struct intel_batchbuffer *batch;
187 dst = gem_handle_to_libdrm_bo(data->bufmgr, data->drm_fd, "", handle);
190 batch = intel_batchbuffer_alloc(data->bufmgr, data->devid);
193 /* add the reloc to make sure the kernel will think we write to dst */
195 OUT_BATCH(MI_BATCH_BUFFER_END);
197 OUT_RELOC(dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
201 intel_batchbuffer_flush_with_context(batch, context);
202 intel_batchbuffer_free(batch);
205 static void fill_render(data_t *data, uint32_t handle,
206 drm_intel_context *context, unsigned char color)
208 drm_intel_bo *src, *dst;
209 struct intel_batchbuffer *batch;
210 struct scratch_buf src_buf, dst_buf;
211 const uint8_t buf[4] = { color, color, color, color };
212 render_copyfunc_t rendercopy = get_render_copyfunc(data->devid);
214 igt_skip_on(!rendercopy);
216 dst = gem_handle_to_libdrm_bo(data->bufmgr, data->drm_fd, "", handle);
219 src = drm_intel_bo_alloc(data->bufmgr, "", 4096, 4096);
222 gem_write(data->drm_fd, src->handle, 0, buf, 4);
224 scratch_buf_init(&src_buf, src);
225 scratch_buf_init(&dst_buf, dst);
227 batch = intel_batchbuffer_alloc(data->bufmgr, data->devid);
230 rendercopy(batch, context,
231 &src_buf, 0, 0, 1, 1,
234 intel_batchbuffer_free(batch);
236 gem_bo_busy(data->drm_fd, handle);
239 static bool fbc_enabled(data_t *data)
244 status = igt_debugfs_fopen(&data->debugfs, "i915_fbc_status", "r");
245 fread(str, sizeof(str) - 1, 1, status);
247 return strstr(str, "FBC enabled") != NULL;
250 static void test_crc(data_t *data, enum test_mode mode)
252 static const unsigned char buf[1] = { 0xcc };
253 igt_pipe_crc_t *pipe_crc = data->pipe_crc[data->crtc_idx];
254 igt_crc_t *crcs = NULL;
255 uint32_t handle = data->handle[0];
257 igt_assert(fbc_enabled(data));
259 if (mode >= TEST_PAGE_FLIP_AND_MMAP_CPU) {
260 handle = data->handle[1];
261 igt_assert(drmModePageFlip(data->drm_fd, data->crtc_id,
262 data->fb_id[1], 0, NULL) == 0);
265 igt_assert(fbc_enabled(data));
271 igt_assert(drmModePageFlip(data->drm_fd, data->crtc_id,
272 data->fb_id[1], 0, NULL) == 0);
275 case TEST_PAGE_FLIP_AND_MMAP_CPU:
276 ptr = gem_mmap__cpu(data->drm_fd, handle, 4096, PROT_WRITE);
277 gem_set_domain(data->drm_fd, handle, I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
278 memset(ptr, 0xff, 4);
280 gem_sw_finish(data->drm_fd, handle);
283 case TEST_PAGE_FLIP_AND_MMAP_GTT:
284 ptr = gem_mmap__gtt(data->drm_fd, handle, 4096, PROT_WRITE);
285 gem_set_domain(data->drm_fd, handle, I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
286 memset(ptr, 0xff, 4);
290 case TEST_PAGE_FLIP_AND_BLT:
291 fill_blt(data, handle, 0xff);
295 case TEST_PAGE_FLIP_AND_RENDER:
296 case TEST_PAGE_FLIP_AND_CONTEXT:
297 fill_render(data, handle,
298 (mode == TEST_CONTEXT || mode == TEST_PAGE_FLIP_AND_CONTEXT) ?
299 data->ctx[1] : NULL, 0xff);
304 * Make sure we're looking at new data (two vblanks
305 * to leave some leeway for the kernel if we ever do
306 * some kind of delayed FBC disable for GTT mmaps.
308 igt_wait_for_vblank(data->drm_fd, data->crtc_idx);
309 igt_wait_for_vblank(data->drm_fd, data->crtc_idx);
311 igt_pipe_crc_start(pipe_crc);
312 igt_pipe_crc_get_crcs(pipe_crc, 1, &crcs);
313 igt_pipe_crc_stop(pipe_crc);
314 igt_assert(!igt_crc_equal(&crcs[0], &data->ref_crc[0]));
315 if (mode == TEST_PAGE_FLIP)
316 igt_assert(igt_crc_equal(&crcs[0], &data->ref_crc[1]));
318 igt_assert(!igt_crc_equal(&crcs[0], &data->ref_crc[1]));
322 * Allow time for FBC to kick in again if it
323 * got disabled during dirtyfb or page flip.
327 igt_assert(fbc_enabled(data));
329 igt_pipe_crc_start(pipe_crc);
330 igt_pipe_crc_get_crcs(pipe_crc, 1, &crcs);
331 igt_pipe_crc_stop(pipe_crc);
332 igt_assert(!igt_crc_equal(&crcs[0], &data->ref_crc[0]));
333 if (mode == TEST_PAGE_FLIP)
334 igt_assert(igt_crc_equal(&crcs[0], &data->ref_crc[1]));
336 igt_assert(!igt_crc_equal(&crcs[0], &data->ref_crc[1]));
340 static bool prepare_crtc(data_t *data, uint32_t connector_id, enum test_mode mode)
342 igt_pipe_crc_t *pipe_crc;
343 igt_crc_t *crcs = NULL;
344 connector_t connector;
347 ret = kmstest_get_connector_config(data->drm_fd,
354 igt_pipe_crc_free(data->pipe_crc[data->crtc_idx]);
355 data->pipe_crc[data->crtc_idx] = NULL;
357 pipe_crc = igt_pipe_crc_new(&data->debugfs,
358 data->drm_fd, data->crtc_idx,
359 INTEL_PIPE_CRC_SOURCE_AUTO);
361 printf("auto crc not supported on this connector with crtc %i\n",
366 data->pipe_crc[data->crtc_idx] = pipe_crc;
368 data->fb_id[0] = create_fb(data,
369 connector.config.default_mode.hdisplay,
370 connector.config.default_mode.vdisplay,
371 0.0, 0.0, 0.0, &connector.fb[0]);
372 igt_assert(data->fb_id[0]);
374 data->fb_id[1] = create_fb(data,
375 connector.config.default_mode.hdisplay,
376 connector.config.default_mode.vdisplay,
377 0.1, 0.1, 0.1, &connector.fb[1]);
378 igt_assert(data->fb_id[1]);
380 data->handle[0] = connector.fb[0].gem_handle;
381 data->handle[1] = connector.fb[1].gem_handle;
383 /* scanout = fb[1] */
384 connector_set_mode(data, &connector, &connector.config.default_mode,
388 igt_skip_on(!fbc_enabled(data));
390 igt_wait_for_vblank(data->drm_fd, data->crtc_idx);
392 /* get reference crc for fb[1] */
393 igt_pipe_crc_start(pipe_crc);
394 igt_pipe_crc_get_crcs(pipe_crc, 1, &crcs);
395 data->ref_crc[1] = crcs[0];
396 igt_pipe_crc_stop(pipe_crc);
399 if (mode == TEST_CONTEXT || mode == TEST_PAGE_FLIP_AND_CONTEXT) {
400 data->ctx[0] = drm_intel_gem_context_create(data->bufmgr);
401 igt_require(data->ctx[0]);
402 data->ctx[1] = drm_intel_gem_context_create(data->bufmgr);
403 igt_require(data->ctx[1]);
406 * Disable FBC RT address for both contexts
407 * (by "rendering" to a non-scanout buffer).
409 exec_nop(data, data->handle[0], data->ctx[1]);
410 exec_nop(data, data->handle[0], data->ctx[0]);
411 exec_nop(data, data->handle[0], data->ctx[1]);
412 exec_nop(data, data->handle[0], data->ctx[0]);
415 /* scanout = fb[0] */
416 connector_set_mode(data, &connector, &connector.config.default_mode,
420 igt_skip_on(!fbc_enabled(data));
422 if (mode == TEST_CONTEXT || mode == TEST_PAGE_FLIP_AND_CONTEXT) {
424 * make ctx[0] FBC RT address point to fb[0], ctx[1]
425 * FBC RT address is left as disabled.
427 exec_nop(data, connector.fb[0].gem_handle, data->ctx[0]);
430 igt_wait_for_vblank(data->drm_fd, data->crtc_idx);
432 /* get reference crc for fb[0] */
433 igt_pipe_crc_start(pipe_crc);
434 igt_pipe_crc_get_crcs(pipe_crc, 1, &crcs);
435 data->ref_crc[0] = crcs[0];
436 igt_pipe_crc_stop(pipe_crc);
439 kmstest_free_connector_config(&connector.config);
444 static void finish_crtc(data_t *data, enum test_mode mode)
446 igt_pipe_crc_free(data->pipe_crc[data->crtc_idx]);
447 data->pipe_crc[data->crtc_idx] = NULL;
449 if (mode == TEST_CONTEXT || mode == TEST_PAGE_FLIP_AND_CONTEXT) {
450 drm_intel_gem_context_destroy(data->ctx[0]);
451 drm_intel_gem_context_destroy(data->ctx[1]);
455 static void run_test(data_t *data, enum test_mode mode)
459 for (i = 0; i < data->resources->count_connectors; i++) {
460 uint32_t connector_id = data->resources->connectors[i];
462 for (n = 0; n < data->resources->count_crtcs; n++) {
464 data->crtc_id = data->resources->crtcs[n];
466 if (!prepare_crtc(data, connector_id, mode))
469 fprintf(stdout, "Beginning %s on crtc %d, connector %d\n",
470 igt_subtest_name(), data->crtc_id, connector_id);
471 test_crc(data, mode);
473 fprintf(stdout, "\n%s on crtc %d, connector %d: PASSED\n\n",
474 igt_subtest_name(), data->crtc_id, connector_id);
476 finish_crtc(data, mode);
486 igt_skip_on_simulation();
491 const char *cmd = "pipe A none";
495 data.drm_fd = drm_open_any();
496 igt_require(data.drm_fd);
497 igt_set_vt_graphics_mode();
499 data.devid = intel_get_drm_devid(data.drm_fd);
501 igt_debugfs_init(&data.debugfs);
502 data.ctl = igt_debugfs_fopen(&data.debugfs,
503 "i915_display_crc_ctl", "r+");
504 igt_require_f(data.ctl,
505 "No display_crc_ctl found, kernel too old\n");
506 written = fwrite(cmd, 1, strlen(cmd), data.ctl);
507 ret = fflush(data.ctl);
508 igt_require_f((written == strlen(cmd) && ret == 0) || errno != ENODEV,
509 "CRCs not supported on this platform\n");
511 status = igt_debugfs_fopen(&data.debugfs, "i915_fbc_status", "r");
512 igt_require_f(status, "No i915_fbc_status found\n");
513 fread(buf, sizeof(buf), 1, status);
515 buf[sizeof(buf) - 1] = '\0';
516 igt_require_f(!strstr(buf, "unsupported by this chipset") &&
517 !strstr(buf, "disabled per module param") &&
518 !strstr(buf, "disabled per chip default"),
519 "FBC not supported/enabled\n");
521 data.bufmgr = drm_intel_bufmgr_gem_init(data.drm_fd, 4096);
522 igt_assert(data.bufmgr);
523 drm_intel_bufmgr_gem_enable_reuse(data.bufmgr);
528 for (mode = TEST_PAGE_FLIP; mode <= TEST_PAGE_FLIP_AND_CONTEXT; mode++) {
529 igt_subtest_f("%s", test_mode_str(mode)) {
530 run_test(&data, mode);
535 drm_intel_bufmgr_destroy(data.bufmgr);