radeonsi/gfx10: update a tunable max_es_verts_base for NGG
[mesa.git] / src / gallium / drivers / virgl / tests / virgl_staging_mgr_test.cpp
1 /*
2 * Copyright 2019 Collabora Ltd.
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 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the 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 NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24 #include <gtest/gtest.h>
25
26 #include "virgl_context.h"
27 #include "virgl_resource.h"
28 #include "virgl_screen.h"
29 #include "virgl_staging_mgr.h"
30 #include "virgl_winsys.h"
31
32 #include "util/u_inlines.h"
33 #include "util/u_memory.h"
34
35 struct virgl_hw_res {
36 struct pipe_reference reference;
37 uint32_t target;
38 uint32_t bind;
39 uint32_t size;
40 void *data;
41 };
42
43 static struct virgl_hw_res *
44 fake_resource_create(struct virgl_winsys *vws,
45 enum pipe_texture_target target,
46 uint32_t format, uint32_t bind,
47 uint32_t width, uint32_t height,
48 uint32_t depth, uint32_t array_size,
49 uint32_t last_level, uint32_t nr_samples,
50 uint32_t size)
51 {
52 struct virgl_hw_res *hw_res = CALLOC_STRUCT(virgl_hw_res);
53
54 pipe_reference_init(&hw_res->reference, 1);
55
56 hw_res->target = target;
57 hw_res->bind = bind;
58 hw_res->size = size;
59 hw_res->data = CALLOC(size, 1);
60
61 return hw_res;
62 }
63
64 static void
65 fake_resource_reference(struct virgl_winsys *vws,
66 struct virgl_hw_res **dres,
67 struct virgl_hw_res *sres)
68 {
69 struct virgl_hw_res *old = *dres;
70
71 if (pipe_reference(&(*dres)->reference, &sres->reference)) {
72 FREE(old->data);
73 FREE(old);
74 }
75
76 *dres = sres;
77 }
78
79 static void *
80 fake_resource_map(struct virgl_winsys *vws, struct virgl_hw_res *hw_res)
81 {
82 return hw_res->data;
83 }
84
85 static struct pipe_context *
86 fake_virgl_context_create()
87 {
88 struct virgl_context *vctx = CALLOC_STRUCT(virgl_context);
89 struct virgl_screen *vs = CALLOC_STRUCT(virgl_screen);
90 struct virgl_winsys *vws = CALLOC_STRUCT(virgl_winsys);
91
92 vctx->base.screen = &vs->base;
93 vs->vws = vws;
94
95 vs->vws->resource_create = fake_resource_create;
96 vs->vws->resource_reference = fake_resource_reference;
97 vs->vws->resource_map = fake_resource_map;
98
99 return &vctx->base;
100 }
101
102 static void
103 fake_virgl_context_destroy(struct pipe_context *ctx)
104 {
105 struct virgl_context *vctx = virgl_context(ctx);
106 struct virgl_screen *vs = virgl_screen(ctx->screen);
107
108 FREE(vs->vws);
109 FREE(vs);
110 FREE(vctx);
111 }
112
113 static void *
114 resource_map(struct virgl_hw_res *hw_res)
115 {
116 return hw_res->data;
117 }
118
119 static void
120 release_resources(struct virgl_hw_res *resources[], unsigned len)
121 {
122 for (unsigned i = 0; i < len; ++i)
123 fake_resource_reference(NULL, &resources[i], NULL);
124 }
125
126 class VirglStagingMgr : public ::testing::Test
127 {
128 protected:
129 VirglStagingMgr() : ctx(fake_virgl_context_create())
130 {
131 virgl_staging_init(&staging, ctx, staging_size);
132 }
133
134 ~VirglStagingMgr()
135 {
136 virgl_staging_destroy(&staging);
137 fake_virgl_context_destroy(ctx);
138 }
139
140 static const unsigned staging_size;
141 struct pipe_context * const ctx;
142 struct virgl_staging_mgr staging;
143 };
144
145 const unsigned VirglStagingMgr::staging_size = 4096;
146
147 class VirglStagingMgrWithAlignment : public VirglStagingMgr,
148 public ::testing::WithParamInterface<unsigned>
149 {
150 protected:
151 VirglStagingMgrWithAlignment() : alignment(GetParam()) {}
152 const unsigned alignment;
153 };
154
155 TEST_P(VirglStagingMgrWithAlignment,
156 suballocations_are_non_overlapping_in_same_resource)
157 {
158 const unsigned alloc_sizes[] = {16, 450, 79, 240, 128, 1001};
159 const unsigned num_resources = sizeof(alloc_sizes) / sizeof(alloc_sizes[0]);
160 struct virgl_hw_res *out_resource[num_resources] = {0};
161 unsigned expected_offset = 0;
162 unsigned out_offset;
163 void *map_ptr;
164 bool alloc_succeeded;
165
166 for (unsigned i = 0; i < num_resources; ++i) {
167 alloc_succeeded =
168 virgl_staging_alloc(&staging, alloc_sizes[i], alignment, &out_offset,
169 &out_resource[i], &map_ptr);
170
171 EXPECT_TRUE(alloc_succeeded);
172 EXPECT_EQ(out_offset, expected_offset);
173 ASSERT_NE(out_resource[i], nullptr);
174 if (i > 0) {
175 EXPECT_EQ(out_resource[i], out_resource[i - 1]);
176 }
177 EXPECT_EQ(map_ptr,
178 (uint8_t*)resource_map(out_resource[i]) + expected_offset);
179
180 expected_offset += alloc_sizes[i];
181 expected_offset = align(expected_offset, alignment);
182 }
183
184 release_resources(out_resource, num_resources);
185 }
186
187 INSTANTIATE_TEST_CASE_P(WithAlignment,
188 VirglStagingMgrWithAlignment,
189 ::testing::Values(1, 16),
190 testing::PrintToStringParamName());
191
192 TEST_F(VirglStagingMgr,
193 non_fitting_allocation_reallocates_resource)
194 {
195 struct virgl_hw_res *out_resource[2] = {0};
196 unsigned out_offset;
197 void *map_ptr;
198 bool alloc_succeeded;
199
200 alloc_succeeded =
201 virgl_staging_alloc(&staging, staging_size - 1, 1, &out_offset,
202 &out_resource[0], &map_ptr);
203
204 EXPECT_TRUE(alloc_succeeded);
205 EXPECT_EQ(out_offset, 0);
206 ASSERT_NE(out_resource[0], nullptr);
207 EXPECT_EQ(map_ptr, resource_map(out_resource[0]));
208
209 alloc_succeeded =
210 virgl_staging_alloc(&staging, 2, 1, &out_offset,
211 &out_resource[1], &map_ptr);
212
213 EXPECT_TRUE(alloc_succeeded);
214 EXPECT_EQ(out_offset, 0);
215 ASSERT_NE(out_resource[1], nullptr);
216 EXPECT_EQ(map_ptr, resource_map(out_resource[1]));
217 /* New resource with same size as old resource. */
218 EXPECT_NE(out_resource[1], out_resource[0]);
219 EXPECT_EQ(out_resource[1]->size, out_resource[0]->size);
220
221 release_resources(out_resource, 2);
222 }
223
224 TEST_F(VirglStagingMgr,
225 non_fitting_aligned_allocation_reallocates_resource)
226 {
227 struct virgl_hw_res *out_resource[2] = {0};
228 unsigned out_offset;
229 void *map_ptr;
230 bool alloc_succeeded;
231
232 alloc_succeeded =
233 virgl_staging_alloc(&staging, staging_size - 1, 1, &out_offset,
234 &out_resource[0], &map_ptr);
235
236 EXPECT_TRUE(alloc_succeeded);
237 EXPECT_EQ(out_offset, 0);
238 ASSERT_NE(out_resource[0], nullptr);
239 EXPECT_EQ(map_ptr, resource_map(out_resource[0]));
240
241 alloc_succeeded =
242 virgl_staging_alloc(&staging, 1, 16, &out_offset,
243 &out_resource[1], &map_ptr);
244
245 EXPECT_TRUE(alloc_succeeded);
246 EXPECT_EQ(out_offset, 0);
247 ASSERT_NE(out_resource[1], nullptr);
248 EXPECT_EQ(map_ptr, resource_map(out_resource[1]));
249 /* New resource with same size as old resource. */
250 EXPECT_NE(out_resource[1], out_resource[0]);
251 EXPECT_EQ(out_resource[1]->size, out_resource[0]->size);
252
253 release_resources(out_resource, 2);
254 }
255
256 TEST_F(VirglStagingMgr,
257 large_non_fitting_allocation_reallocates_large_resource)
258 {
259 struct virgl_hw_res *out_resource[2] = {0};
260 unsigned out_offset;
261 void *map_ptr;
262 bool alloc_succeeded;
263
264 ASSERT_LT(staging_size, 5123);
265
266 alloc_succeeded =
267 virgl_staging_alloc(&staging, 5123, 1, &out_offset,
268 &out_resource[0], &map_ptr);
269
270 EXPECT_TRUE(alloc_succeeded);
271 EXPECT_EQ(out_offset, 0);
272 ASSERT_NE(out_resource[0], nullptr);
273 EXPECT_EQ(map_ptr, resource_map(out_resource[0]));
274 EXPECT_GE(out_resource[0]->size, 5123);
275
276 alloc_succeeded =
277 virgl_staging_alloc(&staging, 19345, 1, &out_offset,
278 &out_resource[1], &map_ptr);
279
280 EXPECT_TRUE(alloc_succeeded);
281 EXPECT_EQ(out_offset, 0);
282 ASSERT_NE(out_resource[1], nullptr);
283 EXPECT_EQ(map_ptr, resource_map(out_resource[1]));
284 /* New resource */
285 EXPECT_NE(out_resource[1], out_resource[0]);
286 EXPECT_GE(out_resource[1]->size, 19345);
287
288 release_resources(out_resource, 2);
289 }
290
291 TEST_F(VirglStagingMgr, releases_resource_on_destruction)
292 {
293 struct virgl_hw_res *out_resource = NULL;
294 unsigned out_offset;
295 void *map_ptr;
296 bool alloc_succeeded;
297
298 alloc_succeeded =
299 virgl_staging_alloc(&staging, 128, 1, &out_offset,
300 &out_resource, &map_ptr);
301
302 EXPECT_TRUE(alloc_succeeded);
303 ASSERT_NE(out_resource, nullptr);
304 /* The resource is referenced both by staging internally,
305 * and out_resource.
306 */
307 EXPECT_EQ(out_resource->reference.count, 2);
308
309 /* Destroying staging releases the internal reference. */
310 virgl_staging_destroy(&staging);
311 EXPECT_EQ(out_resource->reference.count, 1);
312
313 release_resources(&out_resource, 1);
314 }
315
316 static struct virgl_hw_res *
317 failing_resource_create(struct virgl_winsys *vws,
318 enum pipe_texture_target target,
319 uint32_t format, uint32_t bind,
320 uint32_t width, uint32_t height,
321 uint32_t depth, uint32_t array_size,
322 uint32_t last_level, uint32_t nr_samples,
323 uint32_t size)
324 {
325 return NULL;
326 }
327
328 TEST_F(VirglStagingMgr, fails_gracefully_if_resource_create_fails)
329 {
330 struct virgl_screen *vs = virgl_screen(ctx->screen);
331 struct virgl_hw_res *out_resource = NULL;
332 unsigned out_offset;
333 void *map_ptr;
334 bool alloc_succeeded;
335
336 vs->vws->resource_create = failing_resource_create;
337
338 alloc_succeeded =
339 virgl_staging_alloc(&staging, 128, 1, &out_offset,
340 &out_resource, &map_ptr);
341
342 EXPECT_FALSE(alloc_succeeded);
343 EXPECT_EQ(out_resource, nullptr);
344 EXPECT_EQ(map_ptr, nullptr);
345 }
346
347 static void *
348 failing_resource_map(struct virgl_winsys *vws, struct virgl_hw_res *hw_res)
349 {
350 return NULL;
351 }
352
353 TEST_F(VirglStagingMgr, fails_gracefully_if_map_fails)
354 {
355 struct virgl_screen *vs = virgl_screen(ctx->screen);
356 struct virgl_hw_res *out_resource = NULL;
357 unsigned out_offset;
358 void *map_ptr;
359 bool alloc_succeeded;
360
361 vs->vws->resource_map = failing_resource_map;
362
363 alloc_succeeded =
364 virgl_staging_alloc(&staging, 128, 1, &out_offset,
365 &out_resource, &map_ptr);
366
367 EXPECT_FALSE(alloc_succeeded);
368 EXPECT_EQ(out_resource, nullptr);
369 EXPECT_EQ(map_ptr, nullptr);
370 }
371
372 TEST_F(VirglStagingMgr, uses_staging_buffer_resource)
373 {
374 struct virgl_hw_res *out_resource = NULL;
375 unsigned out_offset;
376 void *map_ptr;
377 bool alloc_succeeded;
378
379 alloc_succeeded =
380 virgl_staging_alloc(&staging, 128, 1, &out_offset,
381 &out_resource, &map_ptr);
382
383 EXPECT_TRUE(alloc_succeeded);
384 ASSERT_NE(out_resource, nullptr);
385 EXPECT_EQ(out_resource->target, PIPE_BUFFER);
386 EXPECT_EQ(out_resource->bind, VIRGL_BIND_STAGING);
387
388 release_resources(&out_resource, 1);
389 }