blob: 69477748060cdf2e255c103cd613f94852f57507 [file] [log] [blame]
Daniel Vetter3dba47e2013-08-06 22:27:37 +02001/*
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
Daniel Vetter43779e32013-08-14 14:50:50 +020030/** @file gem_concurrent_blit.c
Daniel Vetter3dba47e2013-08-06 22:27:37 +020031 *
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>
Daniel Vetter3dba47e2013-08-06 22:27:37 +020041#include <fcntl.h>
42#include <inttypes.h>
43#include <errno.h>
44#include <sys/stat.h>
45#include <sys/time.h>
Chris Wilson99431a42013-08-14 11:03:34 +010046#include <sys/wait.h>
Daniel Vetter3dba47e2013-08-06 22:27:37 +020047#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
54static void
Daniel Vetter43779e32013-08-14 14:50:50 +020055prw_set_bo(drm_intel_bo *bo, uint32_t val, int width, int height)
Daniel Vetter3dba47e2013-08-06 22:27:37 +020056{
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
67static void
Daniel Vetter43779e32013-08-14 14:50:50 +020068prw_cmp_bo(drm_intel_bo *bo, uint32_t val, int width, int height)
Daniel Vetter3dba47e2013-08-06 22:27:37 +020069{
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--)
Daniel Vetter83440952013-08-13 12:35:58 +020076 igt_assert(*vaddr++ == val);
Daniel Vetter3dba47e2013-08-06 22:27:37 +020077 free(tmp);
78}
79
80static drm_intel_bo *
Daniel Vetter43779e32013-08-14 14:50:50 +020081unmapped_create_bo(drm_intel_bufmgr *bufmgr, uint32_t val, int width, int height)
Daniel Vetter3dba47e2013-08-06 22:27:37 +020082{
83 drm_intel_bo *bo;
84
85 bo = drm_intel_bo_alloc(bufmgr, "bo", 4*width*height, 0);
Daniel Vetter83440952013-08-13 12:35:58 +020086 igt_assert(bo);
Daniel Vetter3dba47e2013-08-06 22:27:37 +020087
88 return bo;
89}
90
Daniel Vetter43779e32013-08-14 14:50:50 +020091static void
92gtt_set_bo(drm_intel_bo *bo, uint32_t val, int width, int height)
Daniel Vetter3dba47e2013-08-06 22:27:37 +020093{
Daniel Vetter43779e32013-08-14 14:50:50 +020094 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
103static void
104gtt_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
115static drm_intel_bo *
116gtt_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
131static void
132cpu_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
144static void
145cpu_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
157struct 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
165struct 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
Chris Wilson1ca607b2013-08-16 09:44:13 +0100174#define MAX_NUM_BUFFERS 1024
175int num_buffers = MAX_NUM_BUFFERS, fd;
Daniel Vetter43779e32013-08-14 14:50:50 +0200176drm_intel_bufmgr *bufmgr;
177struct intel_batchbuffer *batch;
Daniel Vetter5a598c92013-08-14 15:08:05 +0200178int width = 512, height = 512;
179
180static 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
199static 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
214static 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
Daniel Vetterec283d62013-08-14 15:18:37 +0200231typedef void (*do_test)(struct access_mode *mode,
232 drm_intel_bo **src, drm_intel_bo **dst,
233 drm_intel_bo *dummy);
234
235typedef 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
240static 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
Chris Wilson1ca607b2013-08-16 09:44:13 +0100249static 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)
Daniel Vetterec283d62013-08-14 15:18:37 +0200253{
254 int loop;
255
Chris Wilson1ca607b2013-08-16 09:44:13 +0100256 igt_fork_signal_helper();
257
Daniel Vetterec283d62013-08-14 15:18:37 +0200258 for (loop = 0; loop < 10; loop++)
259 do_test_func(mode, src, dst, dummy);
Chris Wilson1ca607b2013-08-16 09:44:13 +0100260
261 igt_stop_signal_helper();
Daniel Vetterec283d62013-08-14 15:18:37 +0200262}
263
264static 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{
Chris Wilson1ca607b2013-08-16 09:44:13 +0100269 const int old_num_buffers = num_buffers;
Daniel Vetterec283d62013-08-14 15:18:37 +0200270 pid_t children[16];
271
Chris Wilson1ca607b2013-08-16 09:44:13 +0100272 num_buffers /= ARRAY_SIZE(children);
273 num_buffers += 2;
274
275 igt_fork_signal_helper();
276
Chris Wilson1b17cb92013-08-16 11:23:22 +0100277 for (int nc = 0; nc < ARRAY_SIZE(children); nc++) {
Daniel Vetterec283d62013-08-14 15:18:37 +0200278 switch ((children[nc] = fork())) {
279 case -1: igt_assert(0);
280 default: break;
281 case 0:
282 /* recreate process local variables */
283 bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
284 drm_intel_bufmgr_gem_enable_reuse(bufmgr);
285 batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd));
Chris Wilson1b17cb92013-08-16 11:23:22 +0100286 for (int i = 0; i < num_buffers; i++) {
Daniel Vetterec283d62013-08-14 15:18:37 +0200287 src[i] = mode->create_bo(bufmgr, i, width, height);
288 dst[i] = mode->create_bo(bufmgr, ~i, width, height);
289 }
290 dummy = mode->create_bo(bufmgr, 0, width, height);
Chris Wilson1b17cb92013-08-16 11:23:22 +0100291 for (int loop = 0; loop < 10; loop++)
Daniel Vetterec283d62013-08-14 15:18:37 +0200292 do_test_func(mode, src, dst, dummy);
Chris Wilson1b17cb92013-08-16 11:23:22 +0100293 /* as we borrow the fd, we need to reap our bo */
294 for (int i = 0; i < num_buffers; i++) {
295 drm_intel_bo_unreference(src[i]);
296 drm_intel_bo_unreference(dst[i]);
297 }
298 drm_intel_bo_unreference(dummy);
Chris Wilson0d320fd2013-08-16 12:07:56 +0100299 intel_batchbuffer_free(batch);
300 drm_intel_bufmgr_destroy(bufmgr);
Daniel Vetterec283d62013-08-14 15:18:37 +0200301 exit(0);
302 }
303 }
Chris Wilson1b17cb92013-08-16 11:23:22 +0100304 for (int nc = 0; nc < ARRAY_SIZE(children); nc++) {
Daniel Vetterec283d62013-08-14 15:18:37 +0200305 int status = -1;
306 while (waitpid(children[nc], &status, 0) == -1 &&
307 errno == -EINTR)
308 ;
309 igt_assert(status == 0);
310 }
Chris Wilson1ca607b2013-08-16 09:44:13 +0100311
312 igt_stop_signal_helper();
313
314 num_buffers = old_num_buffers;
Daniel Vetterec283d62013-08-14 15:18:37 +0200315}
Daniel Vetter5a598c92013-08-14 15:08:05 +0200316
317static void
318run_basic_modes(struct access_mode *mode,
319 drm_intel_bo **src, drm_intel_bo **dst,
Daniel Vetterec283d62013-08-14 15:18:37 +0200320 drm_intel_bo *dummy, const char *suffix,
321 run_wrap run_wrap_func)
Daniel Vetter5a598c92013-08-14 15:08:05 +0200322{
Daniel Vetter5a598c92013-08-14 15:08:05 +0200323 /* try to overwrite the source values */
Daniel Vetterec283d62013-08-14 15:18:37 +0200324 igt_subtest_f("%s-overwrite-source%s", mode->name, suffix)
325 run_wrap_func(mode, src, dst, dummy, do_overwrite_source);
Daniel Vetter5a598c92013-08-14 15:08:05 +0200326
327 /* try to read the results before the copy completes */
Daniel Vetterec283d62013-08-14 15:18:37 +0200328 igt_subtest_f("%s-early-read%s", mode->name, suffix)
329 run_wrap_func(mode, src, dst, dummy, do_early_read);
Daniel Vetter5a598c92013-08-14 15:08:05 +0200330
331 /* and finally try to trick the kernel into loosing the pending write */
Daniel Vetterec283d62013-08-14 15:18:37 +0200332 igt_subtest_f("%s-gpu-read-after-write%s", mode->name, suffix)
333 run_wrap_func(mode, src, dst, dummy, do_gpu_read_after_write);
Daniel Vetter5a598c92013-08-14 15:08:05 +0200334}
Daniel Vetter43779e32013-08-14 14:50:50 +0200335
336static void
337run_modes(struct access_mode *mode)
338{
Daniel Vetterad0f0812013-08-26 20:41:00 +0200339 drm_intel_bo *src[MAX_NUM_BUFFERS], *dst[MAX_NUM_BUFFERS], *dummy = NULL;
340
Daniel Vetter2dbd9982013-08-14 15:48:54 +0200341 igt_fixture {
Chris Wilson0d320fd2013-08-16 12:07:56 +0100342 bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
343 drm_intel_bufmgr_gem_enable_reuse(bufmgr);
344 batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd));
345
Chris Wilson1ca607b2013-08-16 09:44:13 +0100346 for (int i = 0; i < num_buffers; i++) {
Daniel Vetter43779e32013-08-14 14:50:50 +0200347 src[i] = mode->create_bo(bufmgr, i, width, height);
348 dst[i] = mode->create_bo(bufmgr, ~i, width, height);
Daniel Vetter3dba47e2013-08-06 22:27:37 +0200349 }
Daniel Vetter43779e32013-08-14 14:50:50 +0200350 dummy = mode->create_bo(bufmgr, 0, width, height);
Daniel Vetter3dba47e2013-08-06 22:27:37 +0200351 }
352
Daniel Vetterec283d62013-08-14 15:18:37 +0200353 run_basic_modes(mode, src, dst, dummy, "", run_single);
Chris Wilson1ca607b2013-08-16 09:44:13 +0100354 run_basic_modes(mode, src, dst, dummy, "-interruptible", run_interruptible);
Daniel Vetter3dba47e2013-08-06 22:27:37 +0200355
Daniel Vetter2dbd9982013-08-14 15:48:54 +0200356 igt_fixture {
Chris Wilson1ca607b2013-08-16 09:44:13 +0100357 for (int i = 0; i < num_buffers; i++) {
Daniel Vetter43779e32013-08-14 14:50:50 +0200358 drm_intel_bo_unreference(src[i]);
359 drm_intel_bo_unreference(dst[i]);
360 }
361 drm_intel_bo_unreference(dummy);
Chris Wilson0d320fd2013-08-16 12:07:56 +0100362 intel_batchbuffer_free(batch);
363 drm_intel_bufmgr_destroy(bufmgr);
Daniel Vetter43779e32013-08-14 14:50:50 +0200364 }
Chris Wilson1ca607b2013-08-16 09:44:13 +0100365
366 run_basic_modes(mode, src, dst, dummy, "-forked", run_forked);
Daniel Vetter43779e32013-08-14 14:50:50 +0200367}
368
369int
370main(int argc, char **argv)
371{
372 int max, i;
373
374 igt_subtest_init(argc, argv);
375 igt_skip_on_simulation();
376
Daniel Vetter2dbd9982013-08-14 15:48:54 +0200377 igt_fixture {
378 fd = drm_open_any();
Daniel Vetter43779e32013-08-14 14:50:50 +0200379
Daniel Vetter2dbd9982013-08-14 15:48:54 +0200380 max = gem_aperture_size (fd) / (1024 * 1024) / 2;
381 if (num_buffers > max)
382 num_buffers = max;
Daniel Vetter2dbd9982013-08-14 15:48:54 +0200383 }
Daniel Vetter43779e32013-08-14 14:50:50 +0200384
385 for (i = 0; i < ARRAY_SIZE(access_modes); i++)
386 run_modes(&access_modes[i]);
387
Daniel Vettera1ca8ef2013-08-14 16:02:24 +0200388 igt_exit();
Daniel Vetter3dba47e2013-08-06 22:27:37 +0200389}