2 * Copyright 2019 Collabora Ltd.
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:
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
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.
24 #include <gtest/gtest.h>
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"
32 #include "util/u_inlines.h"
33 #include "util/u_memory.h"
36 struct pipe_reference reference
;
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
,
52 struct virgl_hw_res
*hw_res
= CALLOC_STRUCT(virgl_hw_res
);
54 pipe_reference_init(&hw_res
->reference
, 1);
56 hw_res
->target
= target
;
59 hw_res
->data
= CALLOC(size
, 1);
65 fake_resource_reference(struct virgl_winsys
*vws
,
66 struct virgl_hw_res
**dres
,
67 struct virgl_hw_res
*sres
)
69 struct virgl_hw_res
*old
= *dres
;
71 if (pipe_reference(&(*dres
)->reference
, &sres
->reference
)) {
80 fake_resource_map(struct virgl_winsys
*vws
, struct virgl_hw_res
*hw_res
)
85 static struct pipe_context
*
86 fake_virgl_context_create()
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
);
92 vctx
->base
.screen
= &vs
->base
;
95 vs
->vws
->resource_create
= fake_resource_create
;
96 vs
->vws
->resource_reference
= fake_resource_reference
;
97 vs
->vws
->resource_map
= fake_resource_map
;
103 fake_virgl_context_destroy(struct pipe_context
*ctx
)
105 struct virgl_context
*vctx
= virgl_context(ctx
);
106 struct virgl_screen
*vs
= virgl_screen(ctx
->screen
);
114 resource_map(struct virgl_hw_res
*hw_res
)
120 release_resources(struct virgl_hw_res
*resources
[], unsigned len
)
122 for (unsigned i
= 0; i
< len
; ++i
)
123 fake_resource_reference(NULL
, &resources
[i
], NULL
);
126 class VirglStagingMgr
: public ::testing::Test
129 VirglStagingMgr() : ctx(fake_virgl_context_create())
131 virgl_staging_init(&staging
, ctx
, staging_size
);
136 virgl_staging_destroy(&staging
);
137 fake_virgl_context_destroy(ctx
);
140 static const unsigned staging_size
;
141 struct pipe_context
* const ctx
;
142 struct virgl_staging_mgr staging
;
145 const unsigned VirglStagingMgr::staging_size
= 4096;
147 class VirglStagingMgrWithAlignment
: public VirglStagingMgr
,
148 public ::testing::WithParamInterface
<unsigned>
151 VirglStagingMgrWithAlignment() : alignment(GetParam()) {}
152 const unsigned alignment
;
155 TEST_P(VirglStagingMgrWithAlignment
,
156 suballocations_are_non_overlapping_in_same_resource
)
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;
164 bool alloc_succeeded
;
166 for (unsigned i
= 0; i
< num_resources
; ++i
) {
168 virgl_staging_alloc(&staging
, alloc_sizes
[i
], alignment
, &out_offset
,
169 &out_resource
[i
], &map_ptr
);
171 EXPECT_TRUE(alloc_succeeded
);
172 EXPECT_EQ(out_offset
, expected_offset
);
173 ASSERT_NE(out_resource
[i
], nullptr);
175 EXPECT_EQ(out_resource
[i
], out_resource
[i
- 1]);
178 (uint8_t*)resource_map(out_resource
[i
]) + expected_offset
);
180 expected_offset
+= alloc_sizes
[i
];
181 expected_offset
= align(expected_offset
, alignment
);
184 release_resources(out_resource
, num_resources
);
187 INSTANTIATE_TEST_CASE_P(WithAlignment
,
188 VirglStagingMgrWithAlignment
,
189 ::testing::Values(1, 16),
190 testing::PrintToStringParamName());
192 TEST_F(VirglStagingMgr
,
193 non_fitting_allocation_reallocates_resource
)
195 struct virgl_hw_res
*out_resource
[2] = {0};
198 bool alloc_succeeded
;
201 virgl_staging_alloc(&staging
, staging_size
- 1, 1, &out_offset
,
202 &out_resource
[0], &map_ptr
);
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]));
210 virgl_staging_alloc(&staging
, 2, 1, &out_offset
,
211 &out_resource
[1], &map_ptr
);
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
);
221 release_resources(out_resource
, 2);
224 TEST_F(VirglStagingMgr
,
225 non_fitting_aligned_allocation_reallocates_resource
)
227 struct virgl_hw_res
*out_resource
[2] = {0};
230 bool alloc_succeeded
;
233 virgl_staging_alloc(&staging
, staging_size
- 1, 1, &out_offset
,
234 &out_resource
[0], &map_ptr
);
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]));
242 virgl_staging_alloc(&staging
, 1, 16, &out_offset
,
243 &out_resource
[1], &map_ptr
);
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
);
253 release_resources(out_resource
, 2);
256 TEST_F(VirglStagingMgr
,
257 large_non_fitting_allocation_reallocates_large_resource
)
259 struct virgl_hw_res
*out_resource
[2] = {0};
262 bool alloc_succeeded
;
264 ASSERT_LT(staging_size
, 5123);
267 virgl_staging_alloc(&staging
, 5123, 1, &out_offset
,
268 &out_resource
[0], &map_ptr
);
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);
277 virgl_staging_alloc(&staging
, 19345, 1, &out_offset
,
278 &out_resource
[1], &map_ptr
);
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]));
285 EXPECT_NE(out_resource
[1], out_resource
[0]);
286 EXPECT_GE(out_resource
[1]->size
, 19345);
288 release_resources(out_resource
, 2);
291 TEST_F(VirglStagingMgr
, releases_resource_on_destruction
)
293 struct virgl_hw_res
*out_resource
= NULL
;
296 bool alloc_succeeded
;
299 virgl_staging_alloc(&staging
, 128, 1, &out_offset
,
300 &out_resource
, &map_ptr
);
302 EXPECT_TRUE(alloc_succeeded
);
303 ASSERT_NE(out_resource
, nullptr);
304 /* The resource is referenced both by staging internally,
307 EXPECT_EQ(out_resource
->reference
.count
, 2);
309 /* Destroying staging releases the internal reference. */
310 virgl_staging_destroy(&staging
);
311 EXPECT_EQ(out_resource
->reference
.count
, 1);
313 release_resources(&out_resource
, 1);
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
,
328 TEST_F(VirglStagingMgr
, fails_gracefully_if_resource_create_fails
)
330 struct virgl_screen
*vs
= virgl_screen(ctx
->screen
);
331 struct virgl_hw_res
*out_resource
= NULL
;
334 bool alloc_succeeded
;
336 vs
->vws
->resource_create
= failing_resource_create
;
339 virgl_staging_alloc(&staging
, 128, 1, &out_offset
,
340 &out_resource
, &map_ptr
);
342 EXPECT_FALSE(alloc_succeeded
);
343 EXPECT_EQ(out_resource
, nullptr);
344 EXPECT_EQ(map_ptr
, nullptr);
348 failing_resource_map(struct virgl_winsys
*vws
, struct virgl_hw_res
*hw_res
)
353 TEST_F(VirglStagingMgr
, fails_gracefully_if_map_fails
)
355 struct virgl_screen
*vs
= virgl_screen(ctx
->screen
);
356 struct virgl_hw_res
*out_resource
= NULL
;
359 bool alloc_succeeded
;
361 vs
->vws
->resource_map
= failing_resource_map
;
364 virgl_staging_alloc(&staging
, 128, 1, &out_offset
,
365 &out_resource
, &map_ptr
);
367 EXPECT_FALSE(alloc_succeeded
);
368 EXPECT_EQ(out_resource
, nullptr);
369 EXPECT_EQ(map_ptr
, nullptr);
372 TEST_F(VirglStagingMgr
, uses_staging_buffer_resource
)
374 struct virgl_hw_res
*out_resource
= NULL
;
377 bool alloc_succeeded
;
380 virgl_staging_alloc(&staging
, 128, 1, &out_offset
,
381 &out_resource
, &map_ptr
);
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
);
388 release_resources(&out_resource
, 1);