lib: add igt_main macro
[platform/upstream/intel-gpu-tools.git] / tests / gem_concurrent_blit.c
1 /*
2  * Copyright © 2009,2012,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  * Authors:
24  *    Eric Anholt <eric@anholt.net>
25  *    Chris Wilson <chris@chris-wilson.co.uk>
26  *    Daniel Vetter <daniel.vetter@ffwll.ch>
27  *
28  */
29
30 /** @file gem_concurrent_blit.c
31  *
32  * This is a test of pread/pwrite behavior when writing to active
33  * buffers.
34  *
35  * Based on gem_gtt_concurrent_blt.
36  */
37
38 #include <stdlib.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <fcntl.h>
42 #include <inttypes.h>
43 #include <errno.h>
44 #include <sys/stat.h>
45 #include <sys/time.h>
46 #include <sys/wait.h>
47 #include "drm.h"
48 #include "i915_drm.h"
49 #include "drmtest.h"
50 #include "intel_bufmgr.h"
51 #include "intel_batchbuffer.h"
52 #include "intel_gpu_tools.h"
53
54 static void
55 prw_set_bo(drm_intel_bo *bo, uint32_t val, int width, int height)
56 {
57         int size = width * height;
58         uint32_t *vaddr, *tmp;
59
60         vaddr = tmp = malloc(size*4);
61         while (size--)
62                 *vaddr++ = val;
63         drm_intel_bo_subdata(bo, 0, width*height*4, tmp);
64         free(tmp);
65 }
66
67 static void
68 prw_cmp_bo(drm_intel_bo *bo, uint32_t val, int width, int height)
69 {
70         int size = width * height;
71         uint32_t *vaddr, *tmp;
72
73         vaddr = tmp = malloc(size*4);
74         drm_intel_bo_get_subdata(bo, 0, size*4, tmp);
75         while (size--)
76                 igt_assert(*vaddr++ == val);
77         free(tmp);
78 }
79
80 static drm_intel_bo *
81 unmapped_create_bo(drm_intel_bufmgr *bufmgr, uint32_t val, int width, int height)
82 {
83         drm_intel_bo *bo;
84
85         bo = drm_intel_bo_alloc(bufmgr, "bo", 4*width*height, 0);
86         igt_assert(bo);
87
88         return bo;
89 }
90
91 static void
92 gtt_set_bo(drm_intel_bo *bo, uint32_t val, int width, int height)
93 {
94         int size = width * height;
95         uint32_t *vaddr;
96
97         drm_intel_gem_bo_start_gtt_access(bo, true);
98         vaddr = bo->virtual;
99         while (size--)
100                 *vaddr++ = val;
101 }
102
103 static void
104 gtt_cmp_bo(drm_intel_bo *bo, uint32_t val, int width, int height)
105 {
106         int size = width * height;
107         uint32_t *vaddr;
108
109         drm_intel_gem_bo_start_gtt_access(bo, false);
110         vaddr = bo->virtual;
111         while (size--)
112                 igt_assert(*vaddr++ == val);
113 }
114
115 static drm_intel_bo *
116 gtt_create_bo(drm_intel_bufmgr *bufmgr, uint32_t val, int width, int height)
117 {
118         drm_intel_bo *bo;
119
120         bo = drm_intel_bo_alloc(bufmgr, "bo", 4*width*height, 0);
121         igt_assert(bo);
122
123         /* gtt map doesn't have a write parameter, so just keep the mapping
124          * around (to avoid the set_domain with the gtt write domain set) and
125          * manually tell the kernel when we start access the gtt. */
126         do_or_die(drm_intel_gem_bo_map_gtt(bo));
127
128         return bo;
129 }
130
131 static void
132 cpu_set_bo(drm_intel_bo *bo, uint32_t val, int width, int height)
133 {
134         int size = width * height;
135         uint32_t *vaddr;
136
137         do_or_die(drm_intel_bo_map(bo, true));
138         vaddr = bo->virtual;
139         while (size--)
140                 *vaddr++ = val;
141         drm_intel_bo_unmap(bo);
142 }
143
144 static void
145 cpu_cmp_bo(drm_intel_bo *bo, uint32_t val, int width, int height)
146 {
147         int size = width * height;
148         uint32_t *vaddr;
149
150         do_or_die(drm_intel_bo_map(bo, false));
151         vaddr = bo->virtual;
152         while (size--)
153                 igt_assert(*vaddr++ == val);
154         drm_intel_bo_unmap(bo);
155 }
156
157 struct access_mode {
158         void (*set_bo)(drm_intel_bo *bo, uint32_t val, int w, int h);
159         void (*cmp_bo)(drm_intel_bo *bo, uint32_t val, int w, int h);
160         drm_intel_bo *(*create_bo)(drm_intel_bufmgr *bufmgr,
161                                    uint32_t val, int width, int height);
162         const char *name;
163 };
164
165 struct access_mode access_modes[] = {
166         { .set_bo = prw_set_bo, .cmp_bo = prw_cmp_bo,
167                 .create_bo = unmapped_create_bo, .name = "prw" },
168         { .set_bo = cpu_set_bo, .cmp_bo = cpu_cmp_bo,
169                 .create_bo = unmapped_create_bo, .name = "cpu" },
170         { .set_bo = gtt_set_bo, .cmp_bo = gtt_cmp_bo,
171                 .create_bo = gtt_create_bo, .name = "gtt" },
172 };
173
174 #define MAX_NUM_BUFFERS 1024
175 int num_buffers = MAX_NUM_BUFFERS, fd;
176 drm_intel_bufmgr *bufmgr;
177 struct intel_batchbuffer *batch;
178 int width = 512, height = 512;
179
180 static void do_overwrite_source(struct access_mode *mode,
181                                 drm_intel_bo **src, drm_intel_bo **dst,
182                                 drm_intel_bo *dummy)
183 {
184         int i;
185
186         gem_quiescent_gpu(fd);
187         for (i = 0; i < num_buffers; i++) {
188                 mode->set_bo(src[i], i, width, height);
189                 mode->set_bo(dst[i], i, width, height);
190         }
191         for (i = 0; i < num_buffers; i++)
192                 intel_copy_bo(batch, dst[i], src[i], width, height);
193         for (i = num_buffers; i--; )
194                 mode->set_bo(src[i], 0xdeadbeef, width, height);
195         for (i = 0; i < num_buffers; i++)
196                 mode->cmp_bo(dst[i], i, width, height);
197 }
198
199 static void do_early_read(struct access_mode *mode,
200                           drm_intel_bo **src, drm_intel_bo **dst,
201                           drm_intel_bo *dummy)
202 {
203         int i;
204
205         gem_quiescent_gpu(fd);
206         for (i = num_buffers; i--; )
207                 mode->set_bo(src[i], 0xdeadbeef, width, height);
208         for (i = 0; i < num_buffers; i++)
209                 intel_copy_bo(batch, dst[i], src[i], width, height);
210         for (i = num_buffers; i--; )
211                 mode->cmp_bo(dst[i], 0xdeadbeef, width, height);
212 }
213
214 static void do_gpu_read_after_write(struct access_mode *mode,
215                                     drm_intel_bo **src, drm_intel_bo **dst,
216                                     drm_intel_bo *dummy)
217 {
218         int i;
219
220         gem_quiescent_gpu(fd);
221         for (i = num_buffers; i--; )
222                 mode->set_bo(src[i], 0xabcdabcd, width, height);
223         for (i = 0; i < num_buffers; i++)
224                 intel_copy_bo(batch, dst[i], src[i], width, height);
225         for (i = num_buffers; i--; )
226                 intel_copy_bo(batch, dummy, dst[i], width, height);
227         for (i = num_buffers; i--; )
228                 mode->cmp_bo(dst[i], 0xabcdabcd, width, height);
229 }
230
231 typedef void (*do_test)(struct access_mode *mode,
232                         drm_intel_bo **src, drm_intel_bo **dst,
233                         drm_intel_bo *dummy);
234
235 typedef void (*run_wrap)(struct access_mode *mode,
236                          drm_intel_bo **src, drm_intel_bo **dst,
237                          drm_intel_bo *dummy,
238                          do_test do_test_func);
239
240 static void run_single(struct access_mode *mode,
241                        drm_intel_bo **src, drm_intel_bo **dst,
242                        drm_intel_bo *dummy,
243                        do_test do_test_func)
244 {
245         do_test_func(mode, src, dst, dummy);
246 }
247
248
249 static void run_interruptible(struct access_mode *mode,
250                               drm_intel_bo **src, drm_intel_bo **dst,
251                               drm_intel_bo *dummy,
252                               do_test do_test_func)
253 {
254         int loop;
255
256         igt_fork_signal_helper();
257
258         for (loop = 0; loop < 10; loop++)
259                 do_test_func(mode, src, dst, dummy);
260
261         igt_stop_signal_helper();
262 }
263
264 static void run_forked(struct access_mode *mode,
265                        drm_intel_bo **src, drm_intel_bo **dst,
266                        drm_intel_bo *dummy,
267                        do_test do_test_func)
268 {
269         const int old_num_buffers = num_buffers;
270
271         num_buffers /= 16;
272         num_buffers += 2;
273
274         igt_fork_signal_helper();
275
276         igt_fork(child, 16) {
277                 /* recreate process local variables */
278                 bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
279                 drm_intel_bufmgr_gem_enable_reuse(bufmgr);
280                 batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd));
281                 for (int i = 0; i < num_buffers; i++) {
282                         src[i] = mode->create_bo(bufmgr, i, width, height);
283                         dst[i] = mode->create_bo(bufmgr, ~i, width, height);
284                 }
285                 dummy = mode->create_bo(bufmgr, 0, width, height);
286                 for (int loop = 0; loop < 10; loop++)
287                         do_test_func(mode, src, dst, dummy);
288                 /* as we borrow the fd, we need to reap our bo */
289                 for (int i = 0; i < num_buffers; i++) {
290                         drm_intel_bo_unreference(src[i]);
291                         drm_intel_bo_unreference(dst[i]);
292                 }
293                 drm_intel_bo_unreference(dummy);
294                 intel_batchbuffer_free(batch);
295                 drm_intel_bufmgr_destroy(bufmgr);
296         }
297
298         igt_waitchildren();
299
300         igt_stop_signal_helper();
301
302         num_buffers = old_num_buffers;
303 }
304
305 static void
306 run_basic_modes(struct access_mode *mode,
307                 drm_intel_bo **src, drm_intel_bo **dst,
308                 drm_intel_bo *dummy, const char *suffix,
309                 run_wrap run_wrap_func)
310 {
311         /* try to overwrite the source values */
312         igt_subtest_f("%s-overwrite-source%s", mode->name, suffix)
313                 run_wrap_func(mode, src, dst, dummy, do_overwrite_source);
314
315         /* try to read the results before the copy completes */
316         igt_subtest_f("%s-early-read%s", mode->name, suffix)
317                 run_wrap_func(mode, src, dst, dummy, do_early_read);
318
319         /* and finally try to trick the kernel into loosing the pending write */
320         igt_subtest_f("%s-gpu-read-after-write%s", mode->name, suffix)
321                 run_wrap_func(mode, src, dst, dummy, do_gpu_read_after_write);
322 }
323
324 static void
325 run_modes(struct access_mode *mode)
326 {
327         drm_intel_bo *src[MAX_NUM_BUFFERS], *dst[MAX_NUM_BUFFERS], *dummy = NULL;
328
329         igt_fixture {
330                 bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
331                 drm_intel_bufmgr_gem_enable_reuse(bufmgr);
332                 batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd));
333
334                 for (int i = 0; i < num_buffers; i++) {
335                         src[i] = mode->create_bo(bufmgr, i, width, height);
336                         dst[i] = mode->create_bo(bufmgr, ~i, width, height);
337                 }
338                 dummy = mode->create_bo(bufmgr, 0, width, height);
339         }
340
341         run_basic_modes(mode, src, dst, dummy, "", run_single);
342         run_basic_modes(mode, src, dst, dummy, "-interruptible", run_interruptible);
343
344         igt_fixture {
345                 for (int i = 0; i < num_buffers; i++) {
346                         drm_intel_bo_unreference(src[i]);
347                         drm_intel_bo_unreference(dst[i]);
348                 }
349                 drm_intel_bo_unreference(dummy);
350                 intel_batchbuffer_free(batch);
351                 drm_intel_bufmgr_destroy(bufmgr);
352         }
353
354         run_basic_modes(mode, src, dst, dummy, "-forked", run_forked);
355 }
356
357 igt_main
358 {
359         int max, i;
360
361         igt_skip_on_simulation();
362
363         igt_fixture {
364                 fd = drm_open_any();
365
366                 max = gem_aperture_size (fd) / (1024 * 1024) / 2;
367                 if (num_buffers > max)
368                         num_buffers = max;
369         }
370
371         for (i = 0; i < ARRAY_SIZE(access_modes); i++)
372                 run_modes(&access_modes[i]);
373 }