~mmach/netext73/mesa-haswell

« back to all changes in this revision

Viewing changes to src/vulkan/runtime/vk_sync.c

  • 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 © 2021 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
 
 
24
 
#include "vk_sync.h"
25
 
 
26
 
#include <assert.h>
27
 
#include <string.h>
28
 
 
29
 
#include "util/debug.h"
30
 
#include "util/macros.h"
31
 
#include "util/os_time.h"
32
 
 
33
 
#include "vk_alloc.h"
34
 
#include "vk_device.h"
35
 
#include "vk_log.h"
36
 
 
37
 
static void
38
 
vk_sync_type_validate(const struct vk_sync_type *type)
39
 
{
40
 
   assert(type->init);
41
 
   assert(type->finish);
42
 
 
43
 
   assert(type->features & (VK_SYNC_FEATURE_BINARY |
44
 
                            VK_SYNC_FEATURE_TIMELINE));
45
 
 
46
 
   if (type->features & VK_SYNC_FEATURE_TIMELINE) {
47
 
      assert(type->features & VK_SYNC_FEATURE_GPU_WAIT);
48
 
      assert(type->features & VK_SYNC_FEATURE_CPU_WAIT);
49
 
      assert(type->features & VK_SYNC_FEATURE_CPU_SIGNAL);
50
 
      assert(type->features & (VK_SYNC_FEATURE_WAIT_BEFORE_SIGNAL |
51
 
                               VK_SYNC_FEATURE_WAIT_PENDING));
52
 
      assert(type->signal);
53
 
      assert(type->get_value);
54
 
   }
55
 
 
56
 
   if (!(type->features & VK_SYNC_FEATURE_BINARY)) {
57
 
      assert(!(type->features & (VK_SYNC_FEATURE_GPU_MULTI_WAIT |
58
 
                                 VK_SYNC_FEATURE_CPU_RESET)));
59
 
      assert(!type->import_sync_file);
60
 
      assert(!type->export_sync_file);
61
 
   }
62
 
 
63
 
   if (type->features & VK_SYNC_FEATURE_CPU_WAIT) {
64
 
      assert(type->wait || type->wait_many);
65
 
   } else {
66
 
      assert(!(type->features & (VK_SYNC_FEATURE_WAIT_ANY |
67
 
                                 VK_SYNC_FEATURE_WAIT_PENDING)));
68
 
   }
69
 
 
70
 
   if (type->features & VK_SYNC_FEATURE_GPU_MULTI_WAIT)
71
 
      assert(type->features & VK_SYNC_FEATURE_GPU_WAIT);
72
 
 
73
 
   if (type->features & VK_SYNC_FEATURE_CPU_RESET)
74
 
      assert(type->reset);
75
 
 
76
 
   if (type->features & VK_SYNC_FEATURE_CPU_SIGNAL)
77
 
      assert(type->signal);
78
 
}
79
 
 
80
 
VkResult
81
 
vk_sync_init(struct vk_device *device,
82
 
             struct vk_sync *sync,
83
 
             const struct vk_sync_type *type,
84
 
             enum vk_sync_flags flags,
85
 
             uint64_t initial_value)
86
 
{
87
 
   vk_sync_type_validate(type);
88
 
 
89
 
   if (flags & VK_SYNC_IS_TIMELINE)
90
 
      assert(type->features & VK_SYNC_FEATURE_TIMELINE);
91
 
   else
92
 
      assert(type->features & VK_SYNC_FEATURE_BINARY);
93
 
 
94
 
   assert(type->size >= sizeof(*sync));
95
 
   memset(sync, 0, type->size);
96
 
   sync->type = type;
97
 
   sync->flags = flags;
98
 
 
99
 
   return type->init(device, sync, initial_value);
100
 
}
101
 
 
102
 
void
103
 
vk_sync_finish(struct vk_device *device,
104
 
               struct vk_sync *sync)
105
 
{
106
 
   sync->type->finish(device, sync);
107
 
}
108
 
 
109
 
VkResult
110
 
vk_sync_create(struct vk_device *device,
111
 
               const struct vk_sync_type *type,
112
 
               enum vk_sync_flags flags,
113
 
               uint64_t initial_value,
114
 
               struct vk_sync **sync_out)
115
 
{
116
 
   struct vk_sync *sync;
117
 
 
118
 
   sync = vk_alloc(&device->alloc, type->size, 8,
119
 
                   VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
120
 
   if (sync == NULL)
121
 
      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
122
 
 
123
 
   VkResult result = vk_sync_init(device, sync, type, flags, initial_value);
124
 
   if (result != VK_SUCCESS) {
125
 
      vk_free(&device->alloc, sync);
126
 
      return result;
127
 
   }
128
 
 
129
 
   *sync_out = sync;
130
 
 
131
 
   return VK_SUCCESS;
132
 
}
133
 
 
134
 
void
135
 
vk_sync_destroy(struct vk_device *device,
136
 
                struct vk_sync *sync)
137
 
{
138
 
   vk_sync_finish(device, sync);
139
 
   vk_free(&device->alloc, sync);
140
 
}
141
 
 
142
 
VkResult
143
 
vk_sync_signal(struct vk_device *device,
144
 
               struct vk_sync *sync,
145
 
               uint64_t value)
146
 
{
147
 
   assert(sync->type->features & VK_SYNC_FEATURE_CPU_SIGNAL);
148
 
 
149
 
   if (sync->flags & VK_SYNC_IS_TIMELINE)
150
 
      assert(value > 0);
151
 
   else
152
 
      assert(value == 0);
153
 
 
154
 
   return sync->type->signal(device, sync, value);
155
 
}
156
 
 
157
 
VkResult
158
 
vk_sync_get_value(struct vk_device *device,
159
 
                  struct vk_sync *sync,
160
 
                  uint64_t *value)
161
 
{
162
 
   assert(sync->flags & VK_SYNC_IS_TIMELINE);
163
 
   return sync->type->get_value(device, sync, value);
164
 
}
165
 
 
166
 
VkResult
167
 
vk_sync_reset(struct vk_device *device,
168
 
              struct vk_sync *sync)
169
 
{
170
 
   assert(sync->type->features & VK_SYNC_FEATURE_CPU_RESET);
171
 
   assert(!(sync->flags & VK_SYNC_IS_TIMELINE));
172
 
   return sync->type->reset(device, sync);
173
 
}
174
 
 
175
 
VkResult vk_sync_move(struct vk_device *device,
176
 
                      struct vk_sync *dst,
177
 
                      struct vk_sync *src)
178
 
{
179
 
   assert(!(dst->flags & VK_SYNC_IS_TIMELINE));
180
 
   assert(!(src->flags & VK_SYNC_IS_TIMELINE));
181
 
   assert(dst->type == src->type);
182
 
 
183
 
   return src->type->move(device, dst, src);
184
 
}
185
 
 
186
 
static void
187
 
assert_valid_wait(struct vk_sync *sync,
188
 
                  uint64_t wait_value,
189
 
                  enum vk_sync_wait_flags wait_flags)
190
 
{
191
 
   assert(sync->type->features & VK_SYNC_FEATURE_CPU_WAIT);
192
 
 
193
 
   if (!(sync->flags & VK_SYNC_IS_TIMELINE))
194
 
      assert(wait_value == 0);
195
 
 
196
 
   if (wait_flags & VK_SYNC_WAIT_PENDING)
197
 
      assert(sync->type->features & VK_SYNC_FEATURE_WAIT_PENDING);
198
 
}
199
 
 
200
 
static uint64_t
201
 
get_max_abs_timeout_ns(void)
202
 
{
203
 
   static int max_timeout_ms = -1;
204
 
   if (max_timeout_ms < 0)
205
 
      max_timeout_ms = env_var_as_unsigned("MESA_VK_MAX_TIMEOUT", 0);
206
 
 
207
 
   if (max_timeout_ms == 0)
208
 
      return UINT64_MAX;
209
 
   else
210
 
      return os_time_get_absolute_timeout(max_timeout_ms * 1000000ull);
211
 
}
212
 
 
213
 
static VkResult
214
 
__vk_sync_wait(struct vk_device *device,
215
 
               struct vk_sync *sync,
216
 
               uint64_t wait_value,
217
 
               enum vk_sync_wait_flags wait_flags,
218
 
               uint64_t abs_timeout_ns)
219
 
{
220
 
   assert_valid_wait(sync, wait_value, wait_flags);
221
 
 
222
 
   /* This doesn't make sense for a single wait */
223
 
   assert(!(wait_flags & VK_SYNC_WAIT_ANY));
224
 
 
225
 
   if (sync->type->wait) {
226
 
      return sync->type->wait(device, sync, wait_value,
227
 
                              wait_flags, abs_timeout_ns);
228
 
   } else {
229
 
      struct vk_sync_wait wait = {
230
 
         .sync = sync,
231
 
         .stage_mask = ~(VkPipelineStageFlags2KHR)0,
232
 
         .wait_value = wait_value,
233
 
      };
234
 
      return sync->type->wait_many(device, 1, &wait, wait_flags,
235
 
                                   abs_timeout_ns);
236
 
   }
237
 
}
238
 
 
239
 
VkResult
240
 
vk_sync_wait(struct vk_device *device,
241
 
             struct vk_sync *sync,
242
 
             uint64_t wait_value,
243
 
             enum vk_sync_wait_flags wait_flags,
244
 
             uint64_t abs_timeout_ns)
245
 
{
246
 
   uint64_t max_abs_timeout_ns = get_max_abs_timeout_ns();
247
 
   if (abs_timeout_ns > max_abs_timeout_ns) {
248
 
      VkResult result =
249
 
         __vk_sync_wait(device, sync, wait_value, wait_flags,
250
 
                        max_abs_timeout_ns);
251
 
      if (unlikely(result == VK_TIMEOUT))
252
 
         return vk_device_set_lost(device, "Maximum timeout exceeded!");
253
 
      return result;
254
 
   } else {
255
 
      return __vk_sync_wait(device, sync, wait_value, wait_flags,
256
 
                            abs_timeout_ns);
257
 
   }
258
 
}
259
 
 
260
 
static bool
261
 
can_wait_many(uint32_t wait_count,
262
 
              const struct vk_sync_wait *waits,
263
 
              enum vk_sync_wait_flags wait_flags)
264
 
{
265
 
   if (waits[0].sync->type->wait_many == NULL)
266
 
      return false;
267
 
 
268
 
   if ((wait_flags & VK_SYNC_WAIT_ANY) &&
269
 
       !(waits[0].sync->type->features & VK_SYNC_FEATURE_WAIT_ANY))
270
 
      return false;
271
 
 
272
 
   for (uint32_t i = 0; i < wait_count; i++) {
273
 
      assert_valid_wait(waits[i].sync, waits[i].wait_value, wait_flags);
274
 
      if (waits[i].sync->type != waits[0].sync->type)
275
 
         return false;
276
 
   }
277
 
 
278
 
   return true;
279
 
}
280
 
 
281
 
static VkResult
282
 
__vk_sync_wait_many(struct vk_device *device,
283
 
                    uint32_t wait_count,
284
 
                    const struct vk_sync_wait *waits,
285
 
                    enum vk_sync_wait_flags wait_flags,
286
 
                    uint64_t abs_timeout_ns)
287
 
{
288
 
   if (wait_count == 0)
289
 
      return VK_SUCCESS;
290
 
 
291
 
   if (wait_count == 1) {
292
 
      return __vk_sync_wait(device, waits[0].sync, waits[0].wait_value,
293
 
                            wait_flags & ~VK_SYNC_WAIT_ANY, abs_timeout_ns);
294
 
   }
295
 
 
296
 
   if (can_wait_many(wait_count, waits, wait_flags)) {
297
 
      return waits[0].sync->type->wait_many(device, wait_count, waits,
298
 
                                            wait_flags, abs_timeout_ns);
299
 
   } else if (wait_flags & VK_SYNC_WAIT_ANY) {
300
 
      /* If we have multiple syncs and they don't support wait_any or they're
301
 
       * not all the same type, there's nothing better we can do than spin.
302
 
       */
303
 
      do {
304
 
         for (uint32_t i = 0; i < wait_count; i++) {
305
 
            VkResult result = __vk_sync_wait(device, waits[i].sync,
306
 
                                             waits[i].wait_value,
307
 
                                             wait_flags & ~VK_SYNC_WAIT_ANY,
308
 
                                             0 /* abs_timeout_ns */);
309
 
            if (result != VK_TIMEOUT)
310
 
               return result;
311
 
         }
312
 
      } while (os_time_get_nano() < abs_timeout_ns);
313
 
 
314
 
      return VK_TIMEOUT;
315
 
   } else {
316
 
      for (uint32_t i = 0; i < wait_count; i++) {
317
 
         VkResult result = __vk_sync_wait(device, waits[i].sync,
318
 
                                          waits[i].wait_value,
319
 
                                          wait_flags, abs_timeout_ns);
320
 
         if (result != VK_SUCCESS)
321
 
            return result;
322
 
      }
323
 
      return VK_SUCCESS;
324
 
   }
325
 
}
326
 
 
327
 
VkResult
328
 
vk_sync_wait_many(struct vk_device *device,
329
 
                  uint32_t wait_count,
330
 
                  const struct vk_sync_wait *waits,
331
 
                  enum vk_sync_wait_flags wait_flags,
332
 
                  uint64_t abs_timeout_ns)
333
 
{
334
 
   uint64_t max_abs_timeout_ns = get_max_abs_timeout_ns();
335
 
   if (abs_timeout_ns > max_abs_timeout_ns) {
336
 
      VkResult result =
337
 
         __vk_sync_wait_many(device, wait_count, waits, wait_flags,
338
 
                             max_abs_timeout_ns);
339
 
      if (unlikely(result == VK_TIMEOUT))
340
 
         return vk_device_set_lost(device, "Maximum timeout exceeded!");
341
 
      return result;
342
 
   } else {
343
 
      return __vk_sync_wait_many(device, wait_count, waits, wait_flags,
344
 
                                 abs_timeout_ns);
345
 
   }
346
 
}
347
 
 
348
 
VkResult
349
 
vk_sync_import_opaque_fd(struct vk_device *device,
350
 
                         struct vk_sync *sync,
351
 
                         int fd)
352
 
{
353
 
   VkResult result = sync->type->import_opaque_fd(device, sync, fd);
354
 
   if (unlikely(result != VK_SUCCESS))
355
 
      return result;
356
 
 
357
 
   sync->flags |= VK_SYNC_IS_SHAREABLE |
358
 
                  VK_SYNC_IS_SHARED;
359
 
 
360
 
   return VK_SUCCESS;
361
 
}
362
 
 
363
 
VkResult
364
 
vk_sync_export_opaque_fd(struct vk_device *device,
365
 
                         struct vk_sync *sync,
366
 
                         int *fd)
367
 
{
368
 
   assert(sync->flags & VK_SYNC_IS_SHAREABLE);
369
 
 
370
 
   VkResult result = sync->type->export_opaque_fd(device, sync, fd);
371
 
   if (unlikely(result != VK_SUCCESS))
372
 
      return result;
373
 
 
374
 
   sync->flags |= VK_SYNC_IS_SHARED;
375
 
 
376
 
   return VK_SUCCESS;
377
 
}
378
 
 
379
 
VkResult
380
 
vk_sync_import_sync_file(struct vk_device *device,
381
 
                         struct vk_sync *sync,
382
 
                         int sync_file)
383
 
{
384
 
   assert(!(sync->flags & VK_SYNC_IS_TIMELINE));
385
 
 
386
 
   /* Silently handle negative file descriptors in case the driver doesn't
387
 
    * want to bother.
388
 
    */
389
 
   if (sync_file < 0 && sync->type->signal)
390
 
      return sync->type->signal(device, sync, 0);
391
 
 
392
 
   return sync->type->import_sync_file(device, sync, sync_file);
393
 
}
394
 
 
395
 
VkResult
396
 
vk_sync_export_sync_file(struct vk_device *device,
397
 
                         struct vk_sync *sync,
398
 
                         int *sync_file)
399
 
{
400
 
   assert(!(sync->flags & VK_SYNC_IS_TIMELINE));
401
 
   return sync->type->export_sync_file(device, sync, sync_file);
402
 
}