kms_rotation_crc: Allow the sprite test to run even without universal planes
[platform/upstream/intel-gpu-tools.git] / tests / eviction_common.c
1 /*
2  * Copyright © 2007, 2011, 2013, 2014 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  *    Daniel Vetter <daniel.vetter@ffwll.ch>
26  *    Tvrtko Ursulin <tvrtko.ursulin@intel.com>
27  *
28  */
29
30 #include <stdlib.h>
31
32 #include "drmtest.h"
33 #include "igt_aux.h"
34
35 struct igt_eviction_test_ops
36 {
37         uint32_t (*create)(int fd, int size);
38         void     (*close)(int fd, uint32_t bo);
39         int      (*copy)(int fd, uint32_t dst, uint32_t src,
40                          uint32_t *all_bo, int nr_bos);
41         void     (*clear)(int fd, uint32_t bo, int size);
42 };
43
44 #define FORKING_EVICTIONS_INTERRUPTIBLE   (1 << 0)
45 #define FORKING_EVICTIONS_SWAPPING        (1 << 1)
46 #define FORKING_EVICTIONS_DUP_DRMFD       (1 << 2)
47 #define FORKING_EVICTIONS_MEMORY_PRESSURE (1 << 3)
48 #define ALL_FORKING_EVICTIONS   (FORKING_EVICTIONS_INTERRUPTIBLE | \
49                                  FORKING_EVICTIONS_SWAPPING | \
50                                  FORKING_EVICTIONS_DUP_DRMFD | \
51                                  FORKING_EVICTIONS_MEMORY_PRESSURE)
52
53 static void exchange_uint32_t(void *array, unsigned i, unsigned j)
54 {
55         uint32_t *i_arr = array;
56         uint32_t i_tmp;
57
58         i_tmp = i_arr[i];
59         i_arr[i] = i_arr[j];
60         i_arr[j] = i_tmp;
61 }
62
63 static int minor_evictions(int fd, struct igt_eviction_test_ops *ops,
64                            int surface_size, int nr_surfaces)
65 {
66         uint32_t *bo, *sel;
67         int n, m, pass, fail;
68         int total_surfaces;
69
70         /* Make sure nr_surfaces is not divisible by seven
71          * to avoid duplicates in the selection loop below.
72          */
73         nr_surfaces /= 7;
74         nr_surfaces *= 7;
75         nr_surfaces += 3;
76
77         total_surfaces = gem_aperture_size(fd) / surface_size + 1;
78         igt_require(nr_surfaces < total_surfaces);
79         igt_require(intel_check_memory(total_surfaces, surface_size, CHECK_RAM));
80
81         bo = malloc((nr_surfaces + total_surfaces)*sizeof(*bo));
82         igt_assert(bo);
83
84         for (n = 0; n < total_surfaces; n++)
85                 bo[n] = ops->create(fd, surface_size);
86
87         sel = bo + n;
88         for (fail = 0, m = 0; fail < 10; fail++) {
89                 int ret;
90                 for (pass = 0; pass < 100; pass++) {
91                         for (n = 0; n < nr_surfaces; n++, m += 7)
92                                 sel[n] = bo[m%total_surfaces];
93                         ret = ops->copy(fd, sel[0], sel[1], sel, nr_surfaces);
94                         igt_assert(ret == 0);
95                 }
96                 ret = ops->copy(fd, bo[0], bo[0], bo, total_surfaces);
97                 igt_assert(ret == ENOSPC);
98         }
99
100         for (n = 0; n < total_surfaces; n++)
101                 ops->close(fd, bo[n]);
102         free(bo);
103
104         return 0;
105 }
106
107 static int major_evictions(int fd, struct igt_eviction_test_ops *ops,
108                            int surface_size, int nr_surfaces)
109 {
110         int n, m, loop;
111         uint32_t *bo;
112         int ret;
113
114         igt_require(intel_check_memory(nr_surfaces, surface_size, CHECK_RAM));
115
116         bo = malloc(nr_surfaces*sizeof(*bo));
117         igt_assert(bo);
118
119         for (n = 0; n < nr_surfaces; n++)
120                 bo[n] = ops->create(fd, surface_size);
121
122         for (loop = 0, m = 0; loop < 100; loop++, m += 17) {
123                 n = m % nr_surfaces;
124                 ret = ops->copy(fd, bo[n], bo[n], &bo[n], 1);
125                 igt_assert(ret == 0);
126         }
127
128         for (n = 0; n < nr_surfaces; n++)
129                 ops->close(fd, bo[n]);
130         free(bo);
131
132         return 0;
133 }
134
135 static int swapping_evictions(int fd, struct igt_eviction_test_ops *ops,
136                               int surface_size,
137                               int working_surfaces,
138                               int trash_surfaces)
139 {
140         uint32_t *bo;
141         int i, n, pass, ret;
142
143         igt_require(intel_check_memory(working_surfaces, surface_size, CHECK_RAM));
144
145         if (trash_surfaces < working_surfaces)
146                 trash_surfaces = working_surfaces;
147
148         igt_require(intel_check_memory(trash_surfaces, surface_size, CHECK_RAM | CHECK_SWAP));
149
150         bo = malloc(trash_surfaces*sizeof(*bo));
151         igt_assert(bo);
152
153         for (n = 0; n < trash_surfaces; n++)
154                 bo[n] = ops->create(fd, surface_size);
155
156         for (i = 0; i < trash_surfaces/32; i++) {
157                 igt_permute_array(bo, trash_surfaces, exchange_uint32_t);
158
159                 for (pass = 0; pass < 100; pass++) {
160                         ret = ops->copy(fd, bo[0], bo[1], bo, working_surfaces);
161                         igt_assert(ret == 0);
162                 }
163         }
164
165         for (n = 0; n < trash_surfaces; n++)
166                 ops->close(fd, bo[n]);
167         free(bo);
168
169         return 0;
170 }
171
172 #define min(a, b) ((a) < (b) ? (a) : (b))
173
174 static int forking_evictions(int fd, struct igt_eviction_test_ops *ops,
175                                 int surface_size, int working_surfaces,
176                                 int trash_surfaces, unsigned flags)
177 {
178         uint32_t *bo;
179         int n, pass, l, ret;
180         int num_threads = sysconf(_SC_NPROCESSORS_ONLN);
181         int bo_count;
182
183         igt_require(intel_check_memory(working_surfaces, surface_size, CHECK_RAM));
184
185         if (flags & FORKING_EVICTIONS_SWAPPING) {
186                 bo_count = trash_surfaces;
187                 if (bo_count < working_surfaces)
188                         bo_count = working_surfaces;
189
190         } else
191                 bo_count = working_surfaces;
192
193         igt_require(intel_check_memory(bo_count, surface_size, CHECK_RAM | CHECK_SWAP));
194
195         bo = malloc(bo_count*sizeof(*bo));
196         igt_assert(bo);
197
198         for (n = 0; n < bo_count; n++)
199                 bo[n] = ops->create(fd, surface_size);
200
201         igt_fork(i, min(num_threads * 4, 12)) {
202                 int realfd = fd;
203                 int num_passes = flags & FORKING_EVICTIONS_SWAPPING ? 10 : 100;
204
205                 /* Every fork should have a different permutation! */
206                 srand(i * 63);
207
208                 if (flags & FORKING_EVICTIONS_INTERRUPTIBLE)
209                         igt_fork_signal_helper();
210
211                 igt_permute_array(bo, bo_count, exchange_uint32_t);
212
213                 if (flags & FORKING_EVICTIONS_DUP_DRMFD) {
214                         realfd = drm_open_any();
215
216                         /* We can overwrite the bo array since we're forked. */
217                         for (l = 0; l < bo_count; l++) {
218                                 uint32_t flink;
219
220                                 flink = gem_flink(fd, bo[l]);
221                                 bo[l] = gem_open(realfd, flink);
222                         }
223                 }
224
225                 for (pass = 0; pass < num_passes; pass++) {
226                         ret = ops->copy(realfd, bo[0], bo[1], bo, working_surfaces);
227                         igt_assert(ret == 0);
228
229                         for (l = 0; l < working_surfaces &&
230                           (flags & FORKING_EVICTIONS_MEMORY_PRESSURE);
231                             l++) {
232                                 ops->clear(realfd, bo[l], surface_size);
233                         }
234                 }
235
236                 if (flags & FORKING_EVICTIONS_INTERRUPTIBLE)
237                         igt_stop_signal_helper();
238
239                 /* drmfd closing will take care of additional bo refs */
240                 if (flags & FORKING_EVICTIONS_DUP_DRMFD)
241                         close(realfd);
242         }
243
244         igt_waitchildren();
245
246         for (n = 0; n < bo_count; n++)
247                 ops->close(fd, bo[n]);
248         free(bo);
249
250         return 0;
251 }