~mmach/netext73/mesa-haswell

« back to all changes in this revision

Viewing changes to src/gallium/drivers/virgl/tests/virgl_staging_mgr_test.cpp

  • Committer: mmach
  • Date: 2022-09-22 19:56:13 UTC
  • Revision ID: netbit73@gmail.com-20220922195613-wtik9mmy20tmor0i
2022-09-22 21:17:09

Show diffs side-by-side

added added

removed removed

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