5ab048f56f1ba7eaf55a6955492719c30ca93a6e
[platform/upstream/intel-gpu-tools.git] / tests / kms_fbc_crc.c
1 /*
2  * Copyright © 2013 Intel Corporation
3  *
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:
10  *
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
13  * Software.
14  *
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
21  * IN THE SOFTWARE.
22  *
23  */
24
25 #include <errno.h>
26 #include <stdbool.h>
27 #include <stdio.h>
28 #include <string.h>
29
30 #include "drmtest.h"
31 #include "igt_debugfs.h"
32 #include "igt_kms.h"
33 #include "intel_chipset.h"
34 #include "intel_batchbuffer.h"
35 #include "ioctl_wrappers.h"
36
37 enum test_mode {
38         TEST_PAGE_FLIP,
39         TEST_MMAP_CPU,
40         TEST_MMAP_GTT,
41         TEST_BLT,
42         TEST_RENDER,
43         TEST_CONTEXT,
44         TEST_PAGE_FLIP_AND_MMAP_CPU,
45         TEST_PAGE_FLIP_AND_MMAP_GTT,
46         TEST_PAGE_FLIP_AND_BLT,
47         TEST_PAGE_FLIP_AND_RENDER,
48         TEST_PAGE_FLIP_AND_CONTEXT,
49 };
50
51 typedef struct {
52         int drm_fd;
53         igt_crc_t ref_crc[2];
54         igt_pipe_crc_t *pipe_crc;
55         drm_intel_bufmgr *bufmgr;
56         drm_intel_context *ctx[2];
57         uint32_t devid;
58         uint32_t handle[2];
59         igt_display_t display;
60         igt_output_t *output;
61         enum pipe pipe;
62         igt_plane_t *primary;
63         struct igt_fb fb[2];
64         uint32_t fb_id[2];
65 } data_t;
66
67 static const char *test_mode_str(enum test_mode mode)
68 {
69         static const char * const test_modes[] = {
70                 [TEST_PAGE_FLIP] = "page_flip",
71                 [TEST_MMAP_CPU] = "mmap_cpu",
72                 [TEST_MMAP_GTT] = "mmap_gtt",
73                 [TEST_BLT] = "blt",
74                 [TEST_RENDER] = "render",
75                 [TEST_CONTEXT] = "context",
76                 [TEST_PAGE_FLIP_AND_MMAP_CPU] = "page_flip_and_mmap_cpu",
77                 [TEST_PAGE_FLIP_AND_MMAP_GTT] = "page_flip_and_mmap_gtt",
78                 [TEST_PAGE_FLIP_AND_BLT] = "page_flip_and_blt",
79                 [TEST_PAGE_FLIP_AND_RENDER] = "page_flip_and_render",
80                 [TEST_PAGE_FLIP_AND_CONTEXT] = "page_flip_and_context",
81         };
82
83         return test_modes[mode];
84 }
85
86 static void fill_blt(data_t *data, uint32_t handle, unsigned char color)
87 {
88         drm_intel_bo *dst = gem_handle_to_libdrm_bo(data->bufmgr,
89                                                     data->drm_fd,
90                                                     "", handle);
91         struct intel_batchbuffer *batch;
92
93         batch = intel_batchbuffer_alloc(data->bufmgr, data->devid);
94         igt_assert(batch);
95
96         COLOR_BLIT_COPY_BATCH_START(batch->devid, 0);
97         OUT_BATCH((0 << 24) | (0xf0 << 16) | 0);
98         OUT_BATCH(0);
99         OUT_BATCH(1 << 16 | 4);
100         OUT_RELOC(dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
101         BLIT_RELOC_UDW(batch->devid);
102         OUT_BATCH(color);
103         ADVANCE_BATCH();
104
105         intel_batchbuffer_flush(batch);
106         intel_batchbuffer_free(batch);
107
108         gem_bo_busy(data->drm_fd, handle);
109 }
110
111 static void scratch_buf_init(struct igt_buf *buf, drm_intel_bo *bo)
112 {
113         buf->bo = bo;
114         buf->stride = 4096;
115         buf->tiling = I915_TILING_X;
116         buf->size = 4096;
117 }
118
119 static void exec_nop(data_t *data, uint32_t handle, drm_intel_context *context)
120 {
121         drm_intel_bo *dst;
122         struct intel_batchbuffer *batch;
123
124         dst = gem_handle_to_libdrm_bo(data->bufmgr, data->drm_fd, "", handle);
125         igt_assert(dst);
126
127         batch = intel_batchbuffer_alloc(data->bufmgr, data->devid);
128         igt_assert(batch);
129
130         /* add the reloc to make sure the kernel will think we write to dst */
131         BEGIN_BATCH(4);
132         OUT_BATCH(MI_BATCH_BUFFER_END);
133         OUT_BATCH(MI_NOOP);
134         OUT_RELOC(dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
135         OUT_BATCH(MI_NOOP);
136         ADVANCE_BATCH();
137
138         intel_batchbuffer_flush_with_context(batch, context);
139         intel_batchbuffer_free(batch);
140 }
141
142 static void fill_render(data_t *data, uint32_t handle,
143                         drm_intel_context *context, unsigned char color)
144 {
145         drm_intel_bo *src, *dst;
146         struct intel_batchbuffer *batch;
147         struct igt_buf src_buf, dst_buf;
148         const uint8_t buf[4] = { color, color, color, color };
149         igt_render_copyfunc_t rendercopy = igt_get_render_copyfunc(data->devid);
150
151         igt_skip_on(!rendercopy);
152
153         dst = gem_handle_to_libdrm_bo(data->bufmgr, data->drm_fd, "", handle);
154         igt_assert(dst);
155
156         src = drm_intel_bo_alloc(data->bufmgr, "", 4096, 4096);
157         igt_assert(src);
158
159         gem_write(data->drm_fd, src->handle, 0, buf, 4);
160
161         scratch_buf_init(&src_buf, src);
162         scratch_buf_init(&dst_buf, dst);
163
164         batch = intel_batchbuffer_alloc(data->bufmgr, data->devid);
165         igt_assert(batch);
166
167         rendercopy(batch, context,
168                    &src_buf, 0, 0, 1, 1,
169                    &dst_buf, 0, 0);
170
171         intel_batchbuffer_free(batch);
172
173         gem_bo_busy(data->drm_fd, handle);
174 }
175
176 static bool fbc_enabled(data_t *data)
177 {
178         FILE *status;
179         char str[64] = {};
180
181         status = igt_debugfs_fopen("i915_fbc_status", "r");
182         igt_assert(status);
183
184         fread(str, sizeof(str) - 1, 1, status);
185         fclose(status);
186         return strstr(str, "FBC enabled") != NULL;
187 }
188
189 static void test_crc(data_t *data, enum test_mode mode)
190 {
191         uint32_t crtc_id = data->output->config.crtc->crtc_id;
192         igt_pipe_crc_t *pipe_crc = data->pipe_crc;
193         igt_crc_t *crcs = NULL;
194         uint32_t handle = data->handle[0];
195
196         igt_assert(fbc_enabled(data));
197
198         if (mode >= TEST_PAGE_FLIP_AND_MMAP_CPU) {
199                 handle = data->handle[1];
200                 igt_assert(drmModePageFlip(data->drm_fd, crtc_id,
201                                            data->fb_id[1], 0, NULL) == 0);
202                 usleep(300000);
203
204                 igt_assert(fbc_enabled(data));
205         }
206
207         switch (mode) {
208                 void *ptr;
209         case TEST_PAGE_FLIP:
210                 igt_assert(drmModePageFlip(data->drm_fd, crtc_id,
211                                            data->fb_id[1], 0, NULL) == 0);
212                 break;
213         case TEST_MMAP_CPU:
214         case TEST_PAGE_FLIP_AND_MMAP_CPU:
215                 ptr = gem_mmap__cpu(data->drm_fd, handle, 4096, PROT_WRITE);
216                 gem_set_domain(data->drm_fd, handle, I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
217                 memset(ptr, 0xff, 4);
218                 munmap(ptr, 4096);
219                 gem_sw_finish(data->drm_fd, handle);
220                 break;
221         case TEST_MMAP_GTT:
222         case TEST_PAGE_FLIP_AND_MMAP_GTT:
223                 ptr = gem_mmap__gtt(data->drm_fd, handle, 4096, PROT_WRITE);
224                 gem_set_domain(data->drm_fd, handle, I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
225                 memset(ptr, 0xff, 4);
226                 munmap(ptr, 4096);
227                 break;
228         case TEST_BLT:
229         case TEST_PAGE_FLIP_AND_BLT:
230                 fill_blt(data, handle, 0xff);
231                 break;
232         case TEST_RENDER:
233         case TEST_CONTEXT:
234         case TEST_PAGE_FLIP_AND_RENDER:
235         case TEST_PAGE_FLIP_AND_CONTEXT:
236                 fill_render(data, handle,
237                             (mode == TEST_CONTEXT || mode == TEST_PAGE_FLIP_AND_CONTEXT) ?
238                             data->ctx[1] : NULL, 0xff);
239                 break;
240         }
241
242         /*
243          * Make sure we're looking at new data (two vblanks
244          * to leave some leeway for the kernel if we ever do
245          * some kind of delayed FBC disable for GTT mmaps.
246          */
247         igt_wait_for_vblank(data->drm_fd, data->pipe);
248         igt_wait_for_vblank(data->drm_fd, data->pipe);
249
250         igt_pipe_crc_start(pipe_crc);
251         igt_pipe_crc_get_crcs(pipe_crc, 1, &crcs);
252         igt_pipe_crc_stop(pipe_crc);
253         igt_assert(!igt_crc_equal(&crcs[0], &data->ref_crc[0]));
254         if (mode == TEST_PAGE_FLIP)
255                 igt_assert(igt_crc_equal(&crcs[0], &data->ref_crc[1]));
256         else
257                 igt_assert(!igt_crc_equal(&crcs[0], &data->ref_crc[1]));
258         free(crcs);
259
260         /*
261          * Allow time for FBC to kick in again if it
262          * got disabled during dirtyfb or page flip.
263          */
264         usleep(300000);
265
266         igt_assert(fbc_enabled(data));
267
268         igt_pipe_crc_start(pipe_crc);
269         igt_pipe_crc_get_crcs(pipe_crc, 1, &crcs);
270         igt_pipe_crc_stop(pipe_crc);
271         igt_assert(!igt_crc_equal(&crcs[0], &data->ref_crc[0]));
272         if (mode == TEST_PAGE_FLIP)
273                 igt_assert(igt_crc_equal(&crcs[0], &data->ref_crc[1]));
274         else
275                 igt_assert(!igt_crc_equal(&crcs[0], &data->ref_crc[1]));
276         free(crcs);
277 }
278
279 static bool prepare_crtc(data_t *data)
280 {
281         igt_display_t *display = &data->display;
282         igt_output_t *output = data->output;
283
284         /* select the pipe we want to use */
285         igt_output_set_pipe(output, data->pipe);
286         igt_display_commit(display);
287
288         if (!output->valid) {
289                 igt_output_set_pipe(output, PIPE_ANY);
290                 igt_display_commit(display);
291                 return false;
292         }
293
294         return true;
295 }
296
297 static bool prepare_test(data_t *data, enum test_mode test_mode)
298 {
299         igt_display_t *display = &data->display;
300         igt_output_t *output = data->output;
301         drmModeModeInfo *mode;
302         igt_pipe_crc_t *pipe_crc;
303         igt_crc_t *crcs = NULL;
304
305         data->primary = igt_output_get_plane(data->output, IGT_PLANE_PRIMARY);
306         mode = igt_output_get_mode(data->output);
307
308         data->fb_id[0] = igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
309                                              DRM_FORMAT_XRGB8888,
310                                              I915_TILING_X,
311                                              0.0, 0.0, 0.0, &data->fb[0]);
312         igt_assert(data->fb_id[0]);
313         data->fb_id[1] = igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
314                                              DRM_FORMAT_XRGB8888,
315                                              I915_TILING_X,
316                                              0.1, 0.1, 0.1,
317                                              &data->fb[1]);
318         igt_assert(data->fb_id[1]);
319
320         data->handle[0] = data->fb[0].gem_handle;
321         data->handle[1] = data->fb[1].gem_handle;
322
323         /* scanout = fb[1] */
324         igt_plane_set_fb(data->primary, &data->fb[1]);
325         igt_display_commit(display);
326         usleep(300000);
327
328         if (!fbc_enabled(data)) {
329                 igt_info("FBC not enabled\n");
330
331                 igt_plane_set_fb(data->primary, NULL);
332                 igt_output_set_pipe(output, PIPE_ANY);
333                 igt_display_commit(display);
334
335                 igt_remove_fb(data->drm_fd, &data->fb[0]);
336                 igt_remove_fb(data->drm_fd, &data->fb[1]);
337                 return false;
338         }
339
340         igt_pipe_crc_free(data->pipe_crc);
341         data->pipe_crc = NULL;
342
343         pipe_crc = igt_pipe_crc_new(data->pipe,
344                                     INTEL_PIPE_CRC_SOURCE_AUTO);
345         if (!pipe_crc) {
346                 igt_info("auto crc not supported on this connector with crtc %i\n",
347                          data->pipe);
348
349                 igt_plane_set_fb(data->primary, NULL);
350                 igt_output_set_pipe(output, PIPE_ANY);
351                 igt_display_commit(display);
352
353                 igt_remove_fb(data->drm_fd, &data->fb[0]);
354                 igt_remove_fb(data->drm_fd, &data->fb[1]);
355                 return false;
356         }
357
358         data->pipe_crc = pipe_crc;
359
360         igt_wait_for_vblank(data->drm_fd, data->pipe);
361
362         /* get reference crc for fb[1] */
363         igt_pipe_crc_start(pipe_crc);
364         igt_pipe_crc_get_crcs(pipe_crc, 1, &crcs);
365         data->ref_crc[1] = crcs[0];
366         igt_pipe_crc_stop(pipe_crc);
367         free(crcs);
368
369         if (test_mode == TEST_CONTEXT || test_mode == TEST_PAGE_FLIP_AND_CONTEXT) {
370                 data->ctx[0] = drm_intel_gem_context_create(data->bufmgr);
371                 igt_assert(data->ctx[0]);
372                 data->ctx[1] = drm_intel_gem_context_create(data->bufmgr);
373                 igt_assert(data->ctx[1]);
374
375                 /*
376                  * Disable FBC RT address for both contexts
377                  * (by "rendering" to a non-scanout buffer).
378                  */
379                 exec_nop(data, data->handle[0], data->ctx[1]);
380                 exec_nop(data, data->handle[0], data->ctx[0]);
381                 exec_nop(data, data->handle[0], data->ctx[1]);
382                 exec_nop(data, data->handle[0], data->ctx[0]);
383         }
384
385         /* scanout = fb[0] */
386         igt_plane_set_fb(data->primary, &data->fb[0]);
387         igt_display_commit(display);
388         usleep(300000);
389
390         igt_assert(fbc_enabled(data));
391
392         if (test_mode == TEST_CONTEXT || test_mode == TEST_PAGE_FLIP_AND_CONTEXT) {
393                 /*
394                  * make ctx[0] FBC RT address point to fb[0], ctx[1]
395                  * FBC RT address is left as disabled.
396                  */
397                 exec_nop(data, data->fb[0].gem_handle, data->ctx[0]);
398         }
399
400         igt_wait_for_vblank(data->drm_fd, data->pipe);
401
402         /* get reference crc for fb[0] */
403         igt_pipe_crc_start(pipe_crc);
404         igt_pipe_crc_get_crcs(pipe_crc, 1, &crcs);
405         data->ref_crc[0] = crcs[0];
406         igt_pipe_crc_stop(pipe_crc);
407         free(crcs);
408
409         return true;
410 }
411
412 static void finish_crtc(data_t *data, enum test_mode mode)
413 {
414         igt_pipe_crc_free(data->pipe_crc);
415         data->pipe_crc = NULL;
416
417         if (mode == TEST_CONTEXT || mode == TEST_PAGE_FLIP_AND_CONTEXT) {
418                 drm_intel_gem_context_destroy(data->ctx[0]);
419                 drm_intel_gem_context_destroy(data->ctx[1]);
420         }
421
422         igt_plane_set_fb(data->primary, NULL);
423         igt_output_set_pipe(data->output, PIPE_ANY);
424         igt_display_commit(&data->display);
425
426         igt_remove_fb(data->drm_fd, &data->fb[0]);
427         igt_remove_fb(data->drm_fd, &data->fb[1]);
428 }
429
430 static void reset_display(data_t *data)
431 {
432         igt_display_t *display = &data->display;
433
434         for_each_connected_output(display, data->output) {
435                 if (data->output->valid) {
436                         data->primary =  igt_output_get_plane(data->output, IGT_PLANE_PRIMARY);
437                         igt_plane_set_fb(data->primary, NULL);
438                 }
439                 igt_output_set_pipe(data->output, PIPE_ANY);
440         }
441 }
442
443 static void run_test(data_t *data, enum test_mode mode)
444 {
445         igt_display_t *display = &data->display;
446         int valid_tests = 0;
447
448         if (mode == TEST_CONTEXT || mode == TEST_PAGE_FLIP_AND_CONTEXT) {
449                 drm_intel_context *ctx = drm_intel_gem_context_create(data->bufmgr);
450                 igt_require(ctx);
451                 drm_intel_gem_context_destroy(ctx);
452         }
453
454         reset_display(data);
455
456         for_each_connected_output(display, data->output) {
457                 for_each_pipe(display, data->pipe) {
458                         if (!prepare_crtc(data))
459                                 continue;
460
461                         igt_info("Beginning %s on pipe %s, connector %s\n",
462                                  igt_subtest_name(),
463                                  kmstest_pipe_name(data->pipe),
464                                  igt_output_name(data->output));
465
466                         if (!prepare_test(data, mode)) {
467                                 igt_info("%s on pipe %s, connector %s: SKIPPED\n",
468                                          igt_subtest_name(),
469                                          kmstest_pipe_name(data->pipe),
470                                          igt_output_name(data->output));
471                                 continue;
472                         }
473
474                         valid_tests++;
475
476                         test_crc(data, mode);
477
478                         igt_info("%s on pipe %s, connector %s: PASSED\n",
479                                  igt_subtest_name(),
480                                  kmstest_pipe_name(data->pipe),
481                                  igt_output_name(data->output));
482
483                         finish_crtc(data, mode);
484                 }
485         }
486
487         igt_require_f(valid_tests, "no valid crtc/connector combinations found\n");
488 }
489
490 igt_main
491 {
492         data_t data = {};
493         enum test_mode mode;
494
495         igt_skip_on_simulation();
496
497         igt_fixture {
498                 char buf[64];
499                 FILE *status;
500
501                 data.drm_fd = drm_open_any();
502                 kmstest_set_vt_graphics_mode();
503
504                 data.devid = intel_get_drm_devid(data.drm_fd);
505
506                 igt_require_pipe_crc();
507
508                 status = igt_debugfs_fopen("i915_fbc_status", "r");
509                 igt_require_f(status, "No i915_fbc_status found\n");
510                 fread(buf, sizeof(buf), 1, status);
511                 fclose(status);
512                 buf[sizeof(buf) - 1] = '\0';
513                 igt_require_f(!strstr(buf, "unsupported by this chipset") &&
514                               !strstr(buf, "disabled per module param") &&
515                               !strstr(buf, "disabled per chip default"),
516                               "FBC not supported/enabled\n");
517
518                 data.bufmgr = drm_intel_bufmgr_gem_init(data.drm_fd, 4096);
519                 igt_assert(data.bufmgr);
520                 drm_intel_bufmgr_gem_enable_reuse(data.bufmgr);
521
522                 igt_display_init(&data.display, data.drm_fd);
523         }
524
525         for (mode = TEST_PAGE_FLIP; mode <= TEST_PAGE_FLIP_AND_CONTEXT; mode++) {
526                 igt_subtest_f("%s", test_mode_str(mode)) {
527                         run_test(&data, mode);
528                 }
529         }
530
531         igt_fixture {
532                 drm_intel_bufmgr_destroy(data.bufmgr);
533                 igt_display_fini(&data.display);
534         }
535 }