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