c4c729a9a288bd6f1aefa92dad7117c37ebf4acd
[platform/upstream/intel-gpu-tools.git] / tests / gem_partial_pwrite_pread.c
1 /*
2  * Copyright © 2011 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  *    Daniel Vetter <daniel.vetter@ffwll.ch>
25  *
26  */
27
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <assert.h>
32 #include <fcntl.h>
33 #include <inttypes.h>
34 #include <errno.h>
35 #include <sys/stat.h>
36 #include <sys/time.h>
37 #include "drm.h"
38 #include "i915_drm.h"
39 #include "drmtest.h"
40 #include "intel_bufmgr.h"
41 #include "intel_batchbuffer.h"
42 #include "intel_gpu_tools.h"
43
44 /*
45  * Testcase: pwrite/pread consistency when touching partial cachelines
46  *
47  * Some fancy new pwrite/pread optimizations clflush in-line while
48  * reading/writing. Check whether all required clflushes happen.
49  *
50  */
51
52 static drm_intel_bufmgr *bufmgr;
53 struct intel_batchbuffer *batch;
54
55 drm_intel_bo *scratch_bo;
56 drm_intel_bo *staging_bo;
57 #define BO_SIZE (4*4096)
58 uint32_t devid;
59 uint64_t mappable_gtt_limit;
60 int fd;
61
62 static void
63 copy_bo(drm_intel_bo *src, drm_intel_bo *dst)
64 {
65         BEGIN_BATCH(8);
66         OUT_BATCH(XY_SRC_COPY_BLT_CMD |
67                   XY_SRC_COPY_BLT_WRITE_ALPHA |
68                   XY_SRC_COPY_BLT_WRITE_RGB);
69         OUT_BATCH((3 << 24) | /* 32 bits */
70                   (0xcc << 16) | /* copy ROP */
71                   4096);
72         OUT_BATCH(0 << 16 | 0);
73         OUT_BATCH((BO_SIZE/4096) << 16 | 1024);
74         OUT_RELOC_FENCED(dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
75         OUT_BATCH(0 << 16 | 0);
76         OUT_BATCH(4096);
77         OUT_RELOC_FENCED(src, I915_GEM_DOMAIN_RENDER, 0, 0);
78         ADVANCE_BATCH();
79
80         intel_batchbuffer_flush(batch);
81 }
82
83 static void
84 blt_bo_fill(drm_intel_bo *tmp_bo, drm_intel_bo *bo, int val)
85 {
86         uint8_t *gtt_ptr;
87         int i;
88
89         drm_intel_gem_bo_map_gtt(tmp_bo);
90         gtt_ptr = tmp_bo->virtual;
91
92         for (i = 0; i < BO_SIZE; i++)
93                 gtt_ptr[i] = val;
94
95         drm_intel_gem_bo_unmap_gtt(tmp_bo);
96
97         if (bo->offset < mappable_gtt_limit &&
98             (IS_G33(devid) || intel_gen(devid) >= 4))
99                 igt_trash_aperture();
100
101         copy_bo(tmp_bo, bo);
102 }
103
104 #define MAX_BLT_SIZE 128
105 #define ROUNDS 1000
106 uint8_t tmp[BO_SIZE];
107
108 static void test_partial_reads(void)
109 {
110         int i, j;
111
112         printf("checking partial reads\n");
113         for (i = 0; i < ROUNDS; i++) {
114                 int start, len;
115                 int val = i % 256;
116
117                 blt_bo_fill(staging_bo, scratch_bo, i);
118
119                 start = random() % BO_SIZE;
120                 len = random() % (BO_SIZE-start) + 1;
121
122                 drm_intel_bo_get_subdata(scratch_bo, start, len, tmp);
123                 for (j = 0; j < len; j++) {
124                         if (tmp[j] != val) {
125                                 printf("mismatch at %i, got: %i, expected: %i\n",
126                                        j, tmp[j], val);
127                                 exit(1);
128                         }
129                 }
130
131                 igt_progress("partial reads test: ", i, ROUNDS);
132         }
133
134 }
135
136 static void test_partial_writes(void)
137 {
138         int i, j;
139         uint8_t *gtt_ptr;
140
141         printf("checking partial writes\n");
142         for (i = 0; i < ROUNDS; i++) {
143                 int start, len;
144                 int val = i % 256;
145
146                 blt_bo_fill(staging_bo, scratch_bo, i);
147
148                 start = random() % BO_SIZE;
149                 len = random() % (BO_SIZE-start) + 1;
150
151                 memset(tmp, i + 63, BO_SIZE);
152
153                 drm_intel_bo_subdata(scratch_bo, start, len, tmp);
154
155                 copy_bo(scratch_bo, staging_bo);
156                 drm_intel_gem_bo_map_gtt(staging_bo);
157                 gtt_ptr = staging_bo->virtual;
158
159                 for (j = 0; j < start; j++) {
160                         if (gtt_ptr[j] != val) {
161                                 printf("mismatch at %i, got: %i, expected: %i\n",
162                                        j, tmp[j], val);
163                                 exit(1);
164                         }
165                 }
166                 for (; j < start + len; j++) {
167                         if (gtt_ptr[j] != tmp[0]) {
168                                 printf("mismatch at %i, got: %i, expected: %i\n",
169                                        j, tmp[j], i);
170                                 exit(1);
171                         }
172                 }
173                 for (; j < BO_SIZE; j++) {
174                         if (gtt_ptr[j] != val) {
175                                 printf("mismatch at %i, got: %i, expected: %i\n",
176                                        j, tmp[j], val);
177                                 exit(1);
178                         }
179                 }
180                 drm_intel_gem_bo_unmap_gtt(staging_bo);
181
182                 igt_progress("partial writes test: ", i, ROUNDS);
183         }
184
185 }
186
187 static void test_partial_read_writes(void)
188 {
189         int i, j;
190         uint8_t *gtt_ptr;
191
192         printf("checking partial writes after partial reads\n");
193         for (i = 0; i < ROUNDS; i++) {
194                 int start, len;
195                 int val = i % 256;
196
197                 blt_bo_fill(staging_bo, scratch_bo, i);
198
199                 /* partial read */
200                 start = random() % BO_SIZE;
201                 len = random() % (BO_SIZE-start) + 1;
202
203                 drm_intel_bo_get_subdata(scratch_bo, start, len, tmp);
204                 for (j = 0; j < len; j++) {
205                         if (tmp[j] != val) {
206                                 printf("mismatch in read at %i, got: %i, expected: %i\n",
207                                        j, tmp[j], val);
208                                 exit(1);
209                         }
210                 }
211
212                 /* Change contents through gtt to make the pread cachelines
213                  * stale. */
214                 val = (i + 17) % 256;
215                 blt_bo_fill(staging_bo, scratch_bo, val);
216
217                 /* partial write */
218                 start = random() % BO_SIZE;
219                 len = random() % (BO_SIZE-start) + 1;
220
221                 memset(tmp, i + 63, BO_SIZE);
222
223                 drm_intel_bo_subdata(scratch_bo, start, len, tmp);
224
225                 copy_bo(scratch_bo, staging_bo);
226                 drm_intel_gem_bo_map_gtt(staging_bo);
227                 gtt_ptr = staging_bo->virtual;
228
229                 for (j = 0; j < start; j++) {
230                         if (gtt_ptr[j] != val) {
231                                 printf("mismatch at %i, got: %i, expected: %i\n",
232                                        j, tmp[j], val);
233                                 exit(1);
234                         }
235                 }
236                 for (; j < start + len; j++) {
237                         if (gtt_ptr[j] != tmp[0]) {
238                                 printf("mismatch at %i, got: %i, expected: %i\n",
239                                        j, tmp[j], tmp[0]);
240                                 exit(1);
241                         }
242                 }
243                 for (; j < BO_SIZE; j++) {
244                         if (gtt_ptr[j] != val) {
245                                 printf("mismatch at %i, got: %i, expected: %i\n",
246                                        j, tmp[j], val);
247                                 exit(1);
248                         }
249                 }
250                 drm_intel_gem_bo_unmap_gtt(staging_bo);
251
252                 igt_progress("partial read/writes test: ", i, ROUNDS);
253         }
254 }
255
256 static void do_tests(int cache_level, const char *suffix)
257 {
258         char name[80];
259
260         if (cache_level != -1)
261                 gem_set_caching(fd, scratch_bo->handle, cache_level);
262
263         snprintf(name, sizeof(name), "reads%s", suffix);
264         igt_subtest(name)
265                 test_partial_reads();
266
267         snprintf(name, sizeof(name), "writes%s", suffix);
268         igt_subtest(name)
269                 test_partial_writes();
270
271         snprintf(name, sizeof(name), "writes-after-reads%s", suffix);
272         igt_subtest(name)
273                 test_partial_read_writes();
274 }
275
276 int main(int argc, char **argv)
277 {
278         srandom(0xdeadbeef);
279
280         igt_subtest_init(argc, argv);
281         igt_skip_on_simulation();
282
283         fd = drm_open_any();
284
285         bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
286         //drm_intel_bufmgr_gem_enable_reuse(bufmgr);
287         devid = intel_get_drm_devid(fd);
288         batch = intel_batchbuffer_alloc(bufmgr, devid);
289
290         /* overallocate the buffers we're actually using because */
291         scratch_bo = drm_intel_bo_alloc(bufmgr, "scratch bo", BO_SIZE, 4096);
292         staging_bo = drm_intel_bo_alloc(bufmgr, "staging bo", BO_SIZE, 4096);
293
294         igt_init_aperture_trashers(bufmgr);
295         mappable_gtt_limit = gem_mappable_aperture_size();
296
297         do_tests(-1, "");
298
299         /* Repeat the tests using different levels of snooping */
300         do_tests(0, "-uncached");
301         do_tests(1, "-snoop");
302         do_tests(2, "-display");
303
304         igt_cleanup_aperture_trashers();
305         drm_intel_bufmgr_destroy(bufmgr);
306
307         close(fd);
308
309         return igt_retval();
310 }