anv_allocator.c 46.1 KB
Newer Older
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/*
 * Copyright © 2015 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include <stdlib.h>
#include <unistd.h>
26
#include <limits.h>
Kristian Høgsberg's avatar
Kristian Høgsberg committed
27
28
29
30
#include <assert.h>
#include <linux/memfd.h>
#include <sys/mman.h>

31
#include "anv_private.h"
Kristian Høgsberg's avatar
Kristian Høgsberg committed
32

Jason Ekstrand's avatar
Jason Ekstrand committed
33
#include "util/hash_table.h"
34
#include "util/simple_mtx.h"
Jason Ekstrand's avatar
Jason Ekstrand committed
35

36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#ifdef HAVE_VALGRIND
#define VG_NOACCESS_READ(__ptr) ({                       \
   VALGRIND_MAKE_MEM_DEFINED((__ptr), sizeof(*(__ptr))); \
   __typeof(*(__ptr)) __val = *(__ptr);                  \
   VALGRIND_MAKE_MEM_NOACCESS((__ptr), sizeof(*(__ptr)));\
   __val;                                                \
})
#define VG_NOACCESS_WRITE(__ptr, __val) ({                  \
   VALGRIND_MAKE_MEM_UNDEFINED((__ptr), sizeof(*(__ptr)));  \
   *(__ptr) = (__val);                                      \
   VALGRIND_MAKE_MEM_NOACCESS((__ptr), sizeof(*(__ptr)));   \
})
#else
#define VG_NOACCESS_READ(__ptr) (*(__ptr))
#define VG_NOACCESS_WRITE(__ptr, __val) (*(__ptr) = (__val))
#endif

Kristian Høgsberg's avatar
Kristian Høgsberg committed
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/* Design goals:
 *
 *  - Lock free (except when resizing underlying bos)
 *
 *  - Constant time allocation with typically only one atomic
 *
 *  - Multiple allocation sizes without fragmentation
 *
 *  - Can grow while keeping addresses and offset of contents stable
 *
 *  - All allocations within one bo so we can point one of the
 *    STATE_BASE_ADDRESS pointers at it.
 *
 * The overall design is a two-level allocator: top level is a fixed size, big
 * block (8k) allocator, which operates out of a bo.  Allocation is done by
 * either pulling a block from the free list or growing the used range of the
 * bo.  Growing the range may run out of space in the bo which we then need to
 * grow.  Growing the bo is tricky in a multi-threaded, lockless environment:
 * we need to keep all pointers and contents in the old map valid.  GEM bos in
 * general can't grow, but we use a trick: we create a memfd and use ftruncate
 * to grow it as necessary.  We mmap the new size and then create a gem bo for
 * it using the new gem userptr ioctl.  Without heavy-handed locking around
 * our allocation fast-path, there isn't really a way to munmap the old mmap,
 * so we just keep it around until garbage collection time.  While the block
 * allocator is lockless for normal operations, we block other threads trying
 * to allocate while we're growing the map.  It sholdn't happen often, and
 * growing is fast anyway.
 *
 * At the next level we can use various sub-allocators.  The state pool is a
 * pool of smaller, fixed size objects, which operates much like the block
 * pool.  It uses a free list for freeing objects, but when it runs out of
 * space it just allocates a new block from the block pool.  This allocator is
 * intended for longer lived state objects such as SURFACE_STATE and most
 * other persistent state objects in the API.  We may need to track more info
 * with these object and a pointer back to the CPU object (eg VkImage).  In
 * those cases we just allocate a slightly bigger object and put the extra
 * state after the GPU state object.
 *
 * The state stream allocator works similar to how the i965 DRI driver streams
 * all its state.  Even with Vulkan, we need to emit transient state (whether
 * surface state base or dynamic state base), and for that we can just get a
 * block and fill it up.  These cases are local to a command buffer and the
 * sub-allocator need not be thread safe.  The streaming allocator gets a new
 * block when it runs out of space and chains them together so they can be
 * easily freed.
 */

/* Allocations are always at least 64 byte aligned, so 1 is an invalid value.
 * We use it to indicate the free list is empty. */
#define EMPTY 1

struct anv_mmap_cleanup {
   void *map;
   size_t size;
   uint32_t gem_handle;
};

#define ANV_MMAP_CLEANUP_INIT ((struct anv_mmap_cleanup){0})

112
#ifndef HAVE_MEMFD_CREATE
Kristian Høgsberg's avatar
Kristian Høgsberg committed
113
114
115
116
117
static inline int
memfd_create(const char *name, unsigned int flags)
{
   return syscall(SYS_memfd_create, name, flags);
}
118
#endif
Kristian Høgsberg's avatar
Kristian Høgsberg committed
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133

static inline uint32_t
ilog2_round_up(uint32_t value)
{
   assert(value != 0);
   return 32 - __builtin_clz(value - 1);
}

static inline uint32_t
round_to_power_of_two(uint32_t value)
{
   return 1 << ilog2_round_up(value);
}

static bool
134
anv_free_list_pop(union anv_free_list *list, void **map, int32_t *offset)
Kristian Høgsberg's avatar
Kristian Høgsberg committed
135
{
136
   union anv_free_list current, new, old;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
137

138
   current.u64 = list->u64;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
139
140
141
142
143
144
145
146
   while (current.offset != EMPTY) {
      /* We have to add a memory barrier here so that the list head (and
       * offset) gets read before we read the map pointer.  This way we
       * know that the map pointer is valid for the given offset at the
       * point where we read it.
       */
      __sync_synchronize();

147
      int32_t *next_ptr = *map + current.offset;
148
149
150
      new.offset = VG_NOACCESS_READ(next_ptr);
      new.count = current.count + 1;
      old.u64 = __sync_val_compare_and_swap(&list->u64, current.u64, new.u64);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
151
152
153
154
155
156
157
158
159
160
161
      if (old.u64 == current.u64) {
         *offset = current.offset;
         return true;
      }
      current = old;
   }

   return false;
}

static void
162
163
anv_free_list_push(union anv_free_list *list, void *map, int32_t offset,
                   uint32_t size, uint32_t count)
Kristian Høgsberg's avatar
Kristian Høgsberg committed
164
165
{
   union anv_free_list current, old, new;
166
   int32_t *next_ptr = map + offset;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
167

168
169
170
171
172
173
174
175
176
177
   /* If we're returning more than one chunk, we need to build a chain to add
    * to the list.  Fortunately, we can do this without any atomics since we
    * own everything in the chain right now.  `offset` is left pointing to the
    * head of our chain list while `next_ptr` points to the tail.
    */
   for (uint32_t i = 1; i < count; i++) {
      VG_NOACCESS_WRITE(next_ptr, offset + i * size);
      next_ptr = map + offset + i * size;
   }

Kristian Høgsberg's avatar
Kristian Høgsberg committed
178
179
180
   old = *list;
   do {
      current = old;
181
      VG_NOACCESS_WRITE(next_ptr, current.offset);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
182
183
184
185
186
187
      new.offset = offset;
      new.count = current.count + 1;
      old.u64 = __sync_val_compare_and_swap(&list->u64, current.u64, new.u64);
   } while (old.u64 != current.u64);
}

188
189
190
191
/* All pointers in the ptr_free_list are assumed to be page-aligned.  This
 * means that the bottom 12 bits should all be zero.
 */
#define PFL_COUNT(x) ((uintptr_t)(x) & 0xfff)
192
#define PFL_PTR(x) ((void *)((uintptr_t)(x) & ~(uintptr_t)0xfff))
193
#define PFL_PACK(ptr, count) ({           \
194
   (void *)(((uintptr_t)(ptr) & ~(uintptr_t)0xfff) | ((count) & 0xfff)); \
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
})

static bool
anv_ptr_free_list_pop(void **list, void **elem)
{
   void *current = *list;
   while (PFL_PTR(current) != NULL) {
      void **next_ptr = PFL_PTR(current);
      void *new_ptr = VG_NOACCESS_READ(next_ptr);
      unsigned new_count = PFL_COUNT(current) + 1;
      void *new = PFL_PACK(new_ptr, new_count);
      void *old = __sync_val_compare_and_swap(list, current, new);
      if (old == current) {
         *elem = PFL_PTR(current);
         return true;
      }
      current = old;
   }

   return false;
}

static void
anv_ptr_free_list_push(void **list, void *elem)
{
   void *old, *current;
   void **next_ptr = elem;

223
224
225
226
227
228
   /* The pointer-based free list requires that the pointer be
    * page-aligned.  This is because we use the bottom 12 bits of the
    * pointer to store a counter to solve the ABA concurrency problem.
    */
   assert(((uintptr_t)elem & 0xfff) == 0);

229
230
231
232
233
234
235
236
237
238
   old = *list;
   do {
      current = old;
      VG_NOACCESS_WRITE(next_ptr, PFL_PTR(current));
      unsigned new_count = PFL_COUNT(current) + 1;
      void *new = PFL_PACK(elem, new_count);
      old = __sync_val_compare_and_swap(list, current, new);
   } while (old != current);
}

239
240
241
static VkResult
anv_block_pool_expand_range(struct anv_block_pool *pool,
                            uint32_t center_bo_offset, uint32_t size);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
242

243
VkResult
Kristian Høgsberg's avatar
Kristian Høgsberg committed
244
anv_block_pool_init(struct anv_block_pool *pool,
245
                    struct anv_device *device,
246
247
                    uint32_t initial_size,
                    uint64_t bo_flags)
Kristian Høgsberg's avatar
Kristian Høgsberg committed
248
{
249
250
   VkResult result;

Kristian Høgsberg's avatar
Kristian Høgsberg committed
251
   pool->device = device;
252
   pool->bo_flags = bo_flags;
253
   anv_bo_init(&pool->bo, 0, 0);
254
255
256

   pool->fd = memfd_create("block pool", MFD_CLOEXEC);
   if (pool->fd == -1)
257
      return vk_error(VK_ERROR_INITIALIZATION_FAILED);
258
259
260
261
262

   /* Just make it 2GB up-front.  The Linux kernel won't actually back it
    * with pages until we either map and fault on one of them or we use
    * userptr and send a chunk of it off to the GPU.
    */
263
264
265
266
   if (ftruncate(pool->fd, BLOCK_POOL_MEMFD_SIZE) == -1) {
      result = vk_error(VK_ERROR_INITIALIZATION_FAILED);
      goto fail_fd;
   }
267

268
269
270
271
272
273
   if (!u_vector_init(&pool->mmap_cleanups,
                      round_to_power_of_two(sizeof(struct anv_mmap_cleanup)),
                      128)) {
      result = vk_error(VK_ERROR_INITIALIZATION_FAILED);
      goto fail_fd;
   }
Kristian Høgsberg's avatar
Kristian Høgsberg committed
274

275
   pool->state.next = 0;
276
277
278
279
   pool->state.end = 0;
   pool->back_state.next = 0;
   pool->back_state.end = 0;

280
281
282
   result = anv_block_pool_expand_range(pool, 0, initial_size);
   if (result != VK_SUCCESS)
      goto fail_mmap_cleanups;
283
284
285

   return VK_SUCCESS;

286
287
 fail_mmap_cleanups:
   u_vector_finish(&pool->mmap_cleanups);
288
289
290
291
 fail_fd:
   close(pool->fd);

   return result;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
292
293
294
295
296
297
298
}

void
anv_block_pool_finish(struct anv_block_pool *pool)
{
   struct anv_mmap_cleanup *cleanup;

299
   u_vector_foreach(cleanup, &pool->mmap_cleanups) {
Kristian Høgsberg's avatar
Kristian Høgsberg committed
300
301
302
303
304
305
      if (cleanup->map)
         munmap(cleanup->map, cleanup->size);
      if (cleanup->gem_handle)
         anv_gem_close(pool->device, cleanup->gem_handle);
   }

306
   u_vector_finish(&pool->mmap_cleanups);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
307
308
309
310

   close(pool->fd);
}

311
312
#define PAGE_SIZE 4096

313
314
315
316
317
318
319
320
321
322
323
324
static VkResult
anv_block_pool_expand_range(struct anv_block_pool *pool,
                            uint32_t center_bo_offset, uint32_t size)
{
   void *map;
   uint32_t gem_handle;
   struct anv_mmap_cleanup *cleanup;

   /* Assert that we only ever grow the pool */
   assert(center_bo_offset >= pool->back_state.end);
   assert(size - center_bo_offset >= pool->state.end);

325
326
327
328
329
   /* Assert that we don't go outside the bounds of the memfd */
   assert(center_bo_offset <= BLOCK_POOL_MEMFD_CENTER);
   assert(size - center_bo_offset <=
          BLOCK_POOL_MEMFD_SIZE - BLOCK_POOL_MEMFD_CENTER);

330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
   cleanup = u_vector_add(&pool->mmap_cleanups);
   if (!cleanup)
      return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);

   *cleanup = ANV_MMAP_CLEANUP_INIT;

   /* Just leak the old map until we destroy the pool.  We can't munmap it
    * without races or imposing locking on the block allocate fast path. On
    * the whole the leaked maps adds up to less than the size of the
    * current map.  MAP_POPULATE seems like the right thing to do, but we
    * should try to get some numbers.
    */
   map = mmap(NULL, size, PROT_READ | PROT_WRITE,
              MAP_SHARED | MAP_POPULATE, pool->fd,
              BLOCK_POOL_MEMFD_CENTER - center_bo_offset);
   if (map == MAP_FAILED)
346
347
      return vk_errorf(pool->device->instance, pool->device,
                       VK_ERROR_MEMORY_MAP_FAILED, "mmap failed: %m");
348
349
350
351

   gem_handle = anv_gem_userptr(pool->device, map, size);
   if (gem_handle == 0) {
      munmap(map, size);
352
353
      return vk_errorf(pool->device->instance, pool->device,
                       VK_ERROR_TOO_MANY_OBJECTS, "userptr failed: %m");
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
   }

   cleanup->map = map;
   cleanup->size = size;
   cleanup->gem_handle = gem_handle;

#if 0
   /* Regular objects are created I915_CACHING_CACHED on LLC platforms and
    * I915_CACHING_NONE on non-LLC platforms. However, userptr objects are
    * always created as I915_CACHING_CACHED, which on non-LLC means
    * snooped. That can be useful but comes with a bit of overheard.  Since
    * we're eplicitly clflushing and don't want the overhead we need to turn
    * it off. */
   if (!pool->device->info.has_llc) {
      anv_gem_set_caching(pool->device, gem_handle, I915_CACHING_NONE);
      anv_gem_set_domain(pool->device, gem_handle,
                         I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
   }
#endif

   /* Now that we successfull allocated everything, we can write the new
    * values back into pool. */
   pool->map = map + center_bo_offset;
   pool->center_bo_offset = center_bo_offset;

   /* For block pool BOs we have to be a bit careful about where we place them
    * in the GTT.  There are two documented workarounds for state base address
    * placement : Wa32bitGeneralStateOffset and Wa32bitInstructionBaseOffset
    * which state that those two base addresses do not support 48-bit
    * addresses and need to be placed in the bottom 32-bit range.
    * Unfortunately, this is not quite accurate.
    *
    * The real problem is that we always set the size of our state pools in
    * STATE_BASE_ADDRESS to 0xfffff (the maximum) even though the BO is most
    * likely significantly smaller.  We do this because we do not no at the
    * time we emit STATE_BASE_ADDRESS whether or not we will need to expand
    * the pool during command buffer building so we don't actually have a
    * valid final size.  If the address + size, as seen by STATE_BASE_ADDRESS
    * overflows 48 bits, the GPU appears to treat all accesses to the buffer
    * as being out of bounds and returns zero.  For dynamic state, this
    * usually just leads to rendering corruptions, but shaders that are all
    * zero hang the GPU immediately.
    *
    * The easiest solution to do is exactly what the bogus workarounds say to
    * do: restrict these buffers to 32-bit addresses.  We could also pin the
    * BO to some particular location of our choosing, but that's significantly
    * more work than just not setting a flag.  So, we explicitly DO NOT set
    * the EXEC_OBJECT_SUPPORTS_48B_ADDRESS flag and the kernel does all of the
    * hard work for us.
    */
   anv_bo_init(&pool->bo, gem_handle, size);
405
   pool->bo.flags = pool->bo_flags;
406
407
408
409
410
   pool->bo.map = map;

   return VK_SUCCESS;
}

411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
/** Grows and re-centers the block pool.
 *
 * We grow the block pool in one or both directions in such a way that the
 * following conditions are met:
 *
 *  1) The size of the entire pool is always a power of two.
 *
 *  2) The pool only grows on both ends.  Neither end can get
 *     shortened.
 *
 *  3) At the end of the allocation, we have about twice as much space
 *     allocated for each end as we have used.  This way the pool doesn't
 *     grow too far in one direction or the other.
 *
 *  4) If the _alloc_back() has never been called, then the back portion of
 *     the pool retains a size of zero.  (This makes it easier for users of
 *     the block pool that only want a one-sided pool.)
 *
 *  5) We have enough space allocated for at least one more block in
 *     whichever side `state` points to.
 *
 *  6) The center of the pool is always aligned to both the block_size of
 *     the pool and a 4K CPU page.
 */
435
static uint32_t
436
anv_block_pool_grow(struct anv_block_pool *pool, struct anv_block_state *state)
Kristian Høgsberg's avatar
Kristian Høgsberg committed
437
{
438
   VkResult result = VK_SUCCESS;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
439

440
441
   pthread_mutex_lock(&pool->device->mutex);

442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
   assert(state == &pool->state || state == &pool->back_state);

   /* Gather a little usage information on the pool.  Since we may have
    * threadsd waiting in queue to get some storage while we resize, it's
    * actually possible that total_used will be larger than old_size.  In
    * particular, block_pool_alloc() increments state->next prior to
    * calling block_pool_grow, so this ensures that we get enough space for
    * which ever side tries to grow the pool.
    *
    * We align to a page size because it makes it easier to do our
    * calculations later in such a way that we state page-aigned.
    */
   uint32_t back_used = align_u32(pool->back_state.next, PAGE_SIZE);
   uint32_t front_used = align_u32(pool->state.next, PAGE_SIZE);
   uint32_t total_used = front_used + back_used;

   assert(state == &pool->state || back_used > 0);

460
   uint32_t old_size = pool->bo.size;
461

462
463
464
465
466
467
468
469
470
471
472
473
474
   /* The block pool is always initialized to a nonzero size and this function
    * is always called after initialization.
    */
   assert(old_size > 0);

   /* The back_used and front_used may actually be smaller than the actual
    * requirement because they are based on the next pointers which are
    * updated prior to calling this function.
    */
   uint32_t back_required = MAX2(back_used, pool->center_bo_offset);
   uint32_t front_required = MAX2(front_used, old_size - pool->center_bo_offset);

   if (back_used * 2 <= back_required && front_used * 2 <= front_required) {
475
476
477
478
479
480
481
      /* If we're in this case then this isn't the firsta allocation and we
       * already have enough space on both sides to hold double what we
       * have allocated.  There's nothing for us to do.
       */
      goto done;
   }

482
483
484
485
486
   uint32_t size = old_size * 2;
   while (size < back_required + front_required)
      size *= 2;

   assert(size > pool->bo.size);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
487

488
489
490
491
492
493
494
495
496
497
498
499
   /* We compute a new center_bo_offset such that, when we double the size
    * of the pool, we maintain the ratio of how much is used by each side.
    * This way things should remain more-or-less balanced.
    */
   uint32_t center_bo_offset;
   if (back_used == 0) {
      /* If we're in this case then we have never called alloc_back().  In
       * this case, we want keep the offset at 0 to make things as simple
       * as possible for users that don't care about back allocations.
       */
      center_bo_offset = 0;
   } else {
500
501
502
      /* Try to "center" the allocation based on how much is currently in
       * use on each side of the center line.
       */
503
504
      center_bo_offset = ((uint64_t)size * back_used) / total_used;

505
506
      /* Align down to a multiple of the page size */
      center_bo_offset &= ~(PAGE_SIZE - 1);
507
508

      assert(center_bo_offset >= back_used);
509
510
511
512
513
514
515
516

      /* Make sure we don't shrink the back end of the pool */
      if (center_bo_offset < pool->back_state.end)
         center_bo_offset = pool->back_state.end;

      /* Make sure that we don't shrink the front end of the pool */
      if (size - center_bo_offset < pool->state.end)
         center_bo_offset = size - pool->state.end;
517
518
519
520
   }

   assert(center_bo_offset % PAGE_SIZE == 0);

521
   result = anv_block_pool_expand_range(pool, center_bo_offset, size);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
522

523
   pool->bo.flags = pool->bo_flags;
524

525
done:
526
527
   pthread_mutex_unlock(&pool->device->mutex);

528
529
530
531
532
533
534
535
536
537
538
   if (result == VK_SUCCESS) {
      /* Return the appropriate new size.  This function never actually
       * updates state->next.  Instead, we let the caller do that because it
       * needs to do so in order to maintain its concurrency model.
       */
      if (state == &pool->state) {
         return pool->bo.size - pool->center_bo_offset;
      } else {
         assert(pool->center_bo_offset > 0);
         return pool->center_bo_offset;
      }
539
   } else {
540
      return 0;
541
   }
Kristian Høgsberg's avatar
Kristian Høgsberg committed
542
543
}

544
545
static uint32_t
anv_block_pool_alloc_new(struct anv_block_pool *pool,
546
547
                         struct anv_block_state *pool_state,
                         uint32_t block_size)
548
549
550
551
{
   struct anv_block_state state, old, new;

   while (1) {
552
      state.u64 = __sync_fetch_and_add(&pool_state->u64, block_size);
553
      if (state.next + block_size <= state.end) {
554
555
         assert(pool->map);
         return state.next;
556
      } else if (state.next <= state.end) {
557
558
559
560
561
         /* We allocated the first block outside the pool so we have to grow
          * the pool.  pool_state->next acts a mutex: threads who try to
          * allocate now will get block indexes above the current limit and
          * hit futex_wait below.
          */
562
         new.next = state.next + block_size;
563
564
565
566
         do {
            new.end = anv_block_pool_grow(pool, pool_state);
         } while (new.end < new.next);

567
568
569
570
571
         old.u64 = __sync_lock_test_and_set(&pool_state->u64, new.u64);
         if (old.next != state.next)
            futex_wake(&pool_state->end, INT_MAX);
         return state.next;
      } else {
Nicolai Hähnle's avatar
Nicolai Hähnle committed
572
         futex_wait(&pool_state->end, state.end, NULL);
573
574
575
576
577
         continue;
      }
   }
}

578
int32_t
579
580
anv_block_pool_alloc(struct anv_block_pool *pool,
                     uint32_t block_size)
Kristian Høgsberg's avatar
Kristian Høgsberg committed
581
{
582
   return anv_block_pool_alloc_new(pool, &pool->state, block_size);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
583
584
}

585
586
587
588
589
590
591
592
593
594
/* Allocates a block out of the back of the block pool.
 *
 * This will allocated a block earlier than the "start" of the block pool.
 * The offsets returned from this function will be negative but will still
 * be correct relative to the block pool's map pointer.
 *
 * If you ever use anv_block_pool_alloc_back, then you will have to do
 * gymnastics with the block pool's BO when doing relocations.
 */
int32_t
595
596
anv_block_pool_alloc_back(struct anv_block_pool *pool,
                          uint32_t block_size)
597
{
598
599
   int32_t offset = anv_block_pool_alloc_new(pool, &pool->back_state,
                                             block_size);
600
601
602
603
604
605
606

   /* The offset we get out of anv_block_pool_alloc_new() is actually the
    * number of bytes downwards from the middle to the end of the block.
    * We need to turn it into a (negative) offset from the middle to the
    * start of the block.
    */
   assert(offset >= 0);
607
   return -(offset + block_size);
608
609
}

610
VkResult
611
anv_state_pool_init(struct anv_state_pool *pool,
612
                    struct anv_device *device,
613
614
                    uint32_t block_size,
                    uint64_t bo_flags)
Kristian Høgsberg's avatar
Kristian Høgsberg committed
615
{
616
   VkResult result = anv_block_pool_init(&pool->block_pool, device,
617
618
                                         block_size * 16,
                                         bo_flags);
619
620
621
   if (result != VK_SUCCESS)
      return result;

622
623
   assert(util_is_power_of_two(block_size));
   pool->block_size = block_size;
624
   pool->back_alloc_free_list = ANV_FREE_LIST_EMPTY;
625
626
627
628
629
630
   for (unsigned i = 0; i < ANV_STATE_BUCKETS; i++) {
      pool->buckets[i].free_list = ANV_FREE_LIST_EMPTY;
      pool->buckets[i].block.next = 0;
      pool->buckets[i].block.end = 0;
   }
   VG(VALGRIND_CREATE_MEMPOOL(pool, 0, false));
631
632

   return VK_SUCCESS;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
633
634
}

635
636
void
anv_state_pool_finish(struct anv_state_pool *pool)
Kristian Høgsberg's avatar
Kristian Høgsberg committed
637
{
638
   VG(VALGRIND_DESTROY_MEMPOOL(pool));
639
   anv_block_pool_finish(&pool->block_pool);
640
}
641

642
643
644
static uint32_t
anv_fixed_size_state_pool_alloc_new(struct anv_fixed_size_state_pool *pool,
                                    struct anv_block_pool *block_pool,
645
646
                                    uint32_t state_size,
                                    uint32_t block_size)
647
{
Kristian Høgsberg's avatar
Kristian Høgsberg committed
648
   struct anv_block_state block, old, new;
649
   uint32_t offset;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
650

651
652
653
654
655
656
   /* If our state is large, we don't need any sub-allocation from a block.
    * Instead, we just grab whole (potentially large) blocks.
    */
   if (state_size >= block_size)
      return anv_block_pool_alloc(block_pool, state_size);

Kristian Høgsberg's avatar
Kristian Høgsberg committed
657
 restart:
658
   block.u64 = __sync_fetch_and_add(&pool->block.u64, state_size);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
659
660
661
662

   if (block.next < block.end) {
      return block.next;
   } else if (block.next == block.end) {
663
      offset = anv_block_pool_alloc(block_pool, block_size);
664
      new.next = offset + state_size;
665
      new.end = offset + block_size;
666
      old.u64 = __sync_lock_test_and_set(&pool->block.u64, new.u64);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
667
668
      if (old.next != block.next)
         futex_wake(&pool->block.end, INT_MAX);
669
      return offset;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
670
   } else {
Nicolai Hähnle's avatar
Nicolai Hähnle committed
671
      futex_wait(&pool->block.end, block.end, NULL);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
672
673
674
675
      goto restart;
   }
}

676
677
static uint32_t
anv_state_pool_get_bucket(uint32_t size)
Kristian Høgsberg's avatar
Kristian Høgsberg committed
678
{
679
   unsigned size_log2 = ilog2_round_up(size);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
680
681
682
   assert(size_log2 <= ANV_MAX_STATE_SIZE_LOG2);
   if (size_log2 < ANV_MIN_STATE_SIZE_LOG2)
      size_log2 = ANV_MIN_STATE_SIZE_LOG2;
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
   return size_log2 - ANV_MIN_STATE_SIZE_LOG2;
}

static uint32_t
anv_state_pool_get_bucket_size(uint32_t bucket)
{
   uint32_t size_log2 = bucket + ANV_MIN_STATE_SIZE_LOG2;
   return 1 << size_log2;
}

static struct anv_state
anv_state_pool_alloc_no_vg(struct anv_state_pool *pool,
                           uint32_t size, uint32_t align)
{
   uint32_t bucket = anv_state_pool_get_bucket(MAX2(size, align));
Kristian Høgsberg's avatar
Kristian Høgsberg committed
698
699

   struct anv_state state;
700
   state.alloc_size = anv_state_pool_get_bucket_size(bucket);
701
702
703

   /* Try free list first. */
   if (anv_free_list_pop(&pool->buckets[bucket].free_list,
704
                         &pool->block_pool.map, &state.offset)) {
705
706
707
708
      assert(state.offset >= 0);
      goto done;
   }

709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
   /* Try to grab a chunk from some larger bucket and split it up */
   for (unsigned b = bucket + 1; b < ANV_STATE_BUCKETS; b++) {
      int32_t chunk_offset;
      if (anv_free_list_pop(&pool->buckets[b].free_list,
                            &pool->block_pool.map, &chunk_offset)) {
         unsigned chunk_size = anv_state_pool_get_bucket_size(b);

         /* We've found a chunk that's larger than the requested state size.
          * There are a couple of options as to what we do with it:
          *
          *    1) We could fully split the chunk into state.alloc_size sized
          *       pieces.  However, this would mean that allocating a 16B
          *       state could potentially split a 2MB chunk into 512K smaller
          *       chunks.  This would lead to unnecessary fragmentation.
          *
          *    2) The classic "buddy allocator" method would have us split the
          *       chunk in half and return one half.  Then we would split the
          *       remaining half in half and return one half, and repeat as
          *       needed until we get down to the size we want.  However, if
          *       you are allocating a bunch of the same size state (which is
          *       the common case), this means that every other allocation has
          *       to go up a level and every fourth goes up two levels, etc.
          *       This is not nearly as efficient as it could be if we did a
          *       little more work up-front.
          *
          *    3) Split the difference between (1) and (2) by doing a
          *       two-level split.  If it's bigger than some fixed block_size,
          *       we split it into block_size sized chunks and return all but
          *       one of them.  Then we split what remains into
          *       state.alloc_size sized chunks and return all but one.
          *
          * We choose option (3).
          */
         if (chunk_size > pool->block_size &&
             state.alloc_size < pool->block_size) {
            assert(chunk_size % pool->block_size == 0);
            /* We don't want to split giant chunks into tiny chunks.  Instead,
             * break anything bigger than a block into block-sized chunks and
             * then break it down into bucket-sized chunks from there.  Return
             * all but the first block of the chunk to the block bucket.
             */
            const uint32_t block_bucket =
               anv_state_pool_get_bucket(pool->block_size);
            anv_free_list_push(&pool->buckets[block_bucket].free_list,
                               pool->block_pool.map,
                               chunk_offset + pool->block_size,
                               pool->block_size,
                               (chunk_size / pool->block_size) - 1);
            chunk_size = pool->block_size;
         }

         assert(chunk_size % state.alloc_size == 0);
         anv_free_list_push(&pool->buckets[bucket].free_list,
                            pool->block_pool.map,
                            chunk_offset + state.alloc_size,
                            state.alloc_size,
                            (chunk_size / state.alloc_size) - 1);

         state.offset = chunk_offset;
         goto done;
      }
   }

772
   state.offset = anv_fixed_size_state_pool_alloc_new(&pool->buckets[bucket],
773
                                                      &pool->block_pool,
774
775
                                                      state.alloc_size,
                                                      pool->block_size);
776
777

done:
778
   state.map = pool->block_pool.map + state.offset;
779
780
781
782
   return state;
}

struct anv_state
783
anv_state_pool_alloc(struct anv_state_pool *pool, uint32_t size, uint32_t align)
784
{
785
786
787
   if (size == 0)
      return ANV_STATE_NULL;

788
   struct anv_state state = anv_state_pool_alloc_no_vg(pool, size, align);
789
   VG(VALGRIND_MEMPOOL_ALLOC(pool, state.map, size));
Kristian Høgsberg's avatar
Kristian Høgsberg committed
790
791
792
   return state;
}

793
794
795
796
797
798
799
struct anv_state
anv_state_pool_alloc_back(struct anv_state_pool *pool)
{
   struct anv_state state;
   state.alloc_size = pool->block_size;

   if (anv_free_list_pop(&pool->back_alloc_free_list,
800
                         &pool->block_pool.map, &state.offset)) {
801
802
803
804
      assert(state.offset < 0);
      goto done;
   }

805
806
   state.offset = anv_block_pool_alloc_back(&pool->block_pool,
                                            pool->block_size);
807
808

done:
809
   state.map = pool->block_pool.map + state.offset;
810
811
812
813
   VG(VALGRIND_MEMPOOL_ALLOC(pool, state.map, state.alloc_size));
   return state;
}

814
815
static void
anv_state_pool_free_no_vg(struct anv_state_pool *pool, struct anv_state state)
Kristian Høgsberg's avatar
Kristian Høgsberg committed
816
{
817
   assert(util_is_power_of_two(state.alloc_size));
818
   unsigned bucket = anv_state_pool_get_bucket(state.alloc_size);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
819

820
821
822
   if (state.offset < 0) {
      assert(state.alloc_size == pool->block_size);
      anv_free_list_push(&pool->back_alloc_free_list,
823
824
                         pool->block_pool.map, state.offset,
                         state.alloc_size, 1);
825
826
   } else {
      anv_free_list_push(&pool->buckets[bucket].free_list,
827
828
                         pool->block_pool.map, state.offset,
                         state.alloc_size, 1);
829
   }
Kristian Høgsberg's avatar
Kristian Høgsberg committed
830
831
}

832
833
834
void
anv_state_pool_free(struct anv_state_pool *pool, struct anv_state state)
{
835
836
837
   if (state.alloc_size == 0)
      return;

838
839
840
841
   VG(VALGRIND_MEMPOOL_FREE(pool, state.map));
   anv_state_pool_free_no_vg(pool, state);
}

842
struct anv_state_stream_block {
843
844
   struct anv_state block;

845
846
   /* The next block */
   struct anv_state_stream_block *next;
847
848

#ifdef HAVE_VALGRIND
849
850
   /* A pointer to the first user-allocated thing in this block.  This is
    * what valgrind sees as the start of the block.
851
    */
852
853
   void *_vg_ptr;
#endif
Kristian Høgsberg's avatar
Kristian Høgsberg committed
854
855
856
857
858
859
860
};

/* The state stream allocator is a one-shot, single threaded allocator for
 * variable sized blocks.  We use it for allocating dynamic state.
 */
void
anv_state_stream_init(struct anv_state_stream *stream,
861
862
                      struct anv_state_pool *state_pool,
                      uint32_t block_size)
Kristian Høgsberg's avatar
Kristian Høgsberg committed
863
{
864
865
866
867
868
869
   stream->state_pool = state_pool;
   stream->block_size = block_size;

   stream->block = ANV_STATE_NULL;

   stream->block_list = NULL;
870

871
   /* Ensure that next + whatever > block_size.  This way the first call to
872
873
    * state_stream_alloc fetches a new block.
    */
874
   stream->next = block_size;
875
876

   VG(VALGRIND_CREATE_MEMPOOL(stream, 0, false));
Kristian Høgsberg's avatar
Kristian Høgsberg committed
877
878
879
880
881
}

void
anv_state_stream_finish(struct anv_state_stream *stream)
{
882
   struct anv_state_stream_block *next = stream->block_list;
883
884
885
   while (next != NULL) {
      struct anv_state_stream_block sb = VG_NOACCESS_READ(next);
      VG(VALGRIND_MEMPOOL_FREE(stream, sb._vg_ptr));
886
887
      VG(VALGRIND_MAKE_MEM_UNDEFINED(next, stream->block_size));
      anv_state_pool_free_no_vg(stream->state_pool, sb.block);
888
      next = sb.next;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
889
   }
890
891

   VG(VALGRIND_DESTROY_MEMPOOL(stream));
Kristian Høgsberg's avatar
Kristian Høgsberg committed
892
893
894
895
896
897
}

struct anv_state
anv_state_stream_alloc(struct anv_state_stream *stream,
                       uint32_t size, uint32_t alignment)
{
898
899
900
   if (size == 0)
      return ANV_STATE_NULL;

901
   assert(alignment <= PAGE_SIZE);
902

903
   uint32_t offset = align_u32(stream->next, alignment);
904
905
906
907
908
   if (offset + size > stream->block.alloc_size) {
      uint32_t block_size = stream->block_size;
      if (block_size < size)
         block_size = round_to_power_of_two(size);

909
      stream->block = anv_state_pool_alloc_no_vg(stream->state_pool,
910
                                                 block_size, PAGE_SIZE);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
911

912
913
914
915
      struct anv_state_stream_block *sb = stream->block.map;
      VG_NOACCESS_WRITE(&sb->block, stream->block);
      VG_NOACCESS_WRITE(&sb->next, stream->block_list);
      stream->block_list = sb;
916
      VG(VG_NOACCESS_WRITE(&sb->_vg_ptr, NULL));
917

918
      VG(VALGRIND_MAKE_MEM_NOACCESS(stream->block.map, stream->block_size));
919

920
921
      /* Reset back to the start plus space for the header */
      stream->next = sizeof(*sb);
922

923
      offset = align_u32(stream->next, alignment);
924
      assert(offset + size <= stream->block.alloc_size);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
925
926
   }

927
928
   struct anv_state state = stream->block;
   state.offset += offset;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
929
   state.alloc_size = size;
930
931
932
   state.map += offset;

   stream->next = offset + size;
933
934

#ifdef HAVE_VALGRIND
935
   struct anv_state_stream_block *sb = stream->block_list;
936
937
938
939
   void *vg_ptr = VG_NOACCESS_READ(&sb->_vg_ptr);
   if (vg_ptr == NULL) {
      vg_ptr = state.map;
      VG_NOACCESS_WRITE(&sb->_vg_ptr, vg_ptr);
940
      VALGRIND_MEMPOOL_ALLOC(stream, vg_ptr, size);
941
   } else {
942
      void *state_end = state.map + state.alloc_size;
943
944
      /* This only updates the mempool.  The newly allocated chunk is still
       * marked as NOACCESS. */
945
      VALGRIND_MEMPOOL_CHANGE(stream, vg_ptr, vg_ptr, state_end - vg_ptr);
946
947
      /* Mark the newly allocated chunk as undefined */
      VALGRIND_MAKE_MEM_UNDEFINED(state.map, state.alloc_size);
948
949
950
   }
#endif

Kristian Høgsberg's avatar
Kristian Høgsberg committed
951
952
   return state;
}
Jason Ekstrand's avatar
Jason Ekstrand committed
953
954
955
956
957
958
959

struct bo_pool_bo_link {
   struct bo_pool_bo_link *next;
   struct anv_bo bo;
};

void
960
961
anv_bo_pool_init(struct anv_bo_pool *pool, struct anv_device *device,
                 uint64_t bo_flags)
Jason Ekstrand's avatar
Jason Ekstrand committed
962
963
{
   pool->device = device;
964
   pool->bo_flags = bo_flags;
965
   memset(pool->free_list, 0, sizeof(pool->free_list));
966
967

   VG(VALGRIND_CREATE_MEMPOOL(pool, 0, false));
Jason Ekstrand's avatar
Jason Ekstrand committed
968
969
970
971
972
}

void
anv_bo_pool_finish(struct anv_bo_pool *pool)
{
973
974
975
976
977
978
979
980
981
   for (unsigned i = 0; i < ARRAY_SIZE(pool->free_list); i++) {
      struct bo_pool_bo_link *link = PFL_PTR(pool->free_list[i]);
      while (link != NULL) {
         struct bo_pool_bo_link link_copy = VG_NOACCESS_READ(link);

         anv_gem_munmap(link_copy.bo.map, link_copy.bo.size);
         anv_gem_close(pool->device, link_copy.bo.gem_handle);
         link = link_copy.next;
      }
Jason Ekstrand's avatar
Jason Ekstrand committed
982
   }
983
984

   VG(VALGRIND_DESTROY_MEMPOOL(pool));
Jason Ekstrand's avatar
Jason Ekstrand committed
985
986
987
}

VkResult
988
anv_bo_pool_alloc(struct anv_bo_pool *pool, struct anv_bo *bo, uint32_t size)
Jason Ekstrand's avatar
Jason Ekstrand committed
989
990
991
{
   VkResult result;

992
993
994
995
   const unsigned size_log2 = size < 4096 ? 12 : ilog2_round_up(size);
   const unsigned pow2_size = 1 << size_log2;
   const unsigned bucket = size_log2 - 12;
   assert(bucket < ARRAY_SIZE(pool->free_list));
996

Jason Ekstrand's avatar
Jason Ekstrand committed
997
   void *next_free_void;
998
   if (anv_ptr_free_list_pop(&pool->free_list[bucket], &next_free_void)) {
Jason Ekstrand's avatar
Jason Ekstrand committed
999
1000
      struct bo_pool_bo_link *next_free = next_free_void;
      *bo = VG_NOACCESS_READ(&next_free->bo);
1001
      assert(bo->gem_handle);
Jason Ekstrand's avatar
Jason Ekstrand committed
1002
      assert(bo->map == next_free);
1003
      assert(size <= bo->size);
Jason Ekstrand's avatar
Jason Ekstrand committed
1004

1005
      VG(VALGRIND_MEMPOOL_ALLOC(pool, bo->map, size));
Jason Ekstrand's avatar
Jason Ekstrand committed
1006
1007
1008
1009
1010
1011

      return VK_SUCCESS;
   }

   struct anv_bo new_bo;

1012
   result = anv_bo_init_new(&new_bo, pool->device, pow2_size);
Jason Ekstrand's avatar
Jason Ekstrand committed
1013
1014
1015
   if (result != VK_SUCCESS)
      return result;

1016
   new_bo.flags = pool->bo_flags;
1017

1018
   assert(new_bo.size == pow2_size);
Jason Ekstrand's avatar
Jason Ekstrand committed
1019

1020
   new_bo.map = anv_gem_mmap(pool->device, new_bo.gem_handle, 0, pow2_size, 0);
1021
   if (new_bo.map == MAP_FAILED) {
Jason Ekstrand's avatar
Jason Ekstrand committed
1022
1023
1024
1025
1026
      anv_gem_close(pool->device, new_bo.gem_handle);
      return vk_error(VK_ERROR_MEMORY_MAP_FAILED);
   }

   *bo = new_bo;
1027

1028
   VG(VALGRIND_MEMPOOL_ALLOC(pool, bo->map, size));
1029

Jason Ekstrand's avatar
Jason Ekstrand committed
1030
1031
1032
1033
   return VK_SUCCESS;
}

void
1034
anv_bo_pool_free(struct anv_bo_pool *pool, const struct anv_bo *bo_in)
Jason Ekstrand's avatar
Jason Ekstrand committed
1035
{
1036
1037
   /* Make a copy in case the anv_bo happens to be storred in the BO */
   struct anv_bo bo = *bo_in;
1038
1039
1040

   VG(VALGRIND_MEMPOOL_FREE(pool, bo.map));

1041
   struct bo_pool_bo_link *link = bo.map;
1042
   VG_NOACCESS_WRITE(&link->bo, bo);
Jason Ekstrand's avatar
Jason Ekstrand committed
1043

1044
1045
1046
1047
1048
1049
   assert(util_is_power_of_two(bo.size));
   const unsigned size_log2 = ilog2_round_up(bo.size);
   const unsigned bucket = size_log2 - 12;
   assert(bucket < ARRAY_SIZE(pool->free_list));

   anv_ptr_free_list_push(&pool->free_list[bucket], link);
Jason Ekstrand's avatar
Jason Ekstrand committed
1050
}
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064

// Scratch pool

void
anv_scratch_pool_init(struct anv_device *device, struct anv_scratch_pool *pool)
{
   memset(pool, 0, sizeof(*pool));
}

void
anv_scratch_pool_finish(struct anv_device *device, struct anv_scratch_pool *pool)
{
   for (unsigned s = 0; s < MESA_SHADER_STAGES; s++) {
      for (unsigned i = 0; i < 16; i++) {
1065
1066
1067
         struct anv_scratch_bo *bo = &pool->bos[i][s];
         if (bo->exists > 0)
            anv_gem_close(device, bo->bo.gem_handle);
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
      }
   }
}

struct anv_bo *
anv_scratch_pool_alloc(struct anv_device *device, struct anv_scratch_pool *pool,
                       gl_shader_stage stage, unsigned per_thread_scratch)
{
   if (per_thread_scratch == 0)
      return NULL;

   unsigned scratch_size_log2 = ffs(per_thread_scratch / 2048);
   assert(scratch_size_log2 < 16);

1082
   struct anv_scratch_bo *bo = &pool->bos[scratch_size_log2][stage];
1083

1084
1085
1086
   /* We can use "exists" to shortcut and ignore the critical section */
   if (bo->exists)
      return &bo->bo;
1087

1088
1089
1090
   pthread_mutex_lock(&device->mutex);

   __sync_synchronize();
1091
1092
   if (bo->exists) {
      pthread_mutex_unlock(&device->mutex);
1093
      return &bo->bo;
1094
   }
1095

1096
1097
1098
1099
1100
   const struct anv_physical_device *physical_device =
      &device->instance->physicalDevice;
   const struct gen_device_info *devinfo = &physical_device->info;

   const unsigned subslices = MAX2(physical_device->subslice_total, 1);
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128

   unsigned scratch_ids_per_subslice;
   if (devinfo->is_haswell) {
      /* WaCSScratchSize:hsw
       *
       * Haswell's scratch space address calculation appears to be sparse
       * rather than tightly packed. The Thread ID has bits indicating
       * which subslice, EU within a subslice, and thread within an EU it
       * is. There's a maximum of two slices and two subslices, so these
       * can be stored with a single bit. Even though there are only 10 EUs
       * per subslice, this is stored in 4 bits, so there's an effective
       * maximum value of 16 EUs. Similarly, although there are only 7
       * threads per EU, this is stored in a 3 bit number, giving an
       * effective maximum value of 8 threads per EU.
       *
       * This means that we need to use 16 * 8 instead of 10 * 7 for the
       * number of threads per subslice.
       */
      scratch_ids_per_subslice = 16 * 8;
   } else if (devinfo->is_cherryview) {
      /* Cherryview devices have either 6 or 8 EUs per subslice, and each EU
       * has 7 threads. The 6 EU devices appear to calculate thread IDs as if
       * it had 8 EUs.
       */
      scratch_ids_per_subslice = 8 * 7;
   } else {
      scratch_ids_per_subslice = devinfo->max_cs_threads;
   }
1129

1130
1131
1132
1133
1134
1135
1136
1137
   uint32_t max_threads[] = {
      [MESA_SHADER_VERTEX]           = devinfo->max_vs_threads,
      [MESA_SHADER_TESS_CTRL]        = devinfo->max_tcs_threads,
      [MESA_SHADER_TESS_EVAL]        = devinfo->max_tes_threads,
      [MESA_SHADER_GEOMETRY]         = devinfo->max_gs_threads,
      [MESA_SHADER_FRAGMENT]         = devinfo->max_wm_threads,
      [MESA_SHADER_COMPUTE]          = scratch_ids_per_subslice * subslices,
   };
1138

1139
   uint32_t size = per_thread_scratch * max_threads[stage];
1140

1141
   anv_bo_init_new(&bo->bo, device, size);
1142

1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
   /* Even though the Scratch base pointers in 3DSTATE_*S are 64 bits, they
    * are still relative to the general state base address.  When we emit
    * STATE_BASE_ADDRESS, we set general state base address to 0 and the size
    * to the maximum (1 page under 4GB).  This allows us to just place the
    * scratch buffers anywhere we wish in the bottom 32 bits of address space
    * and just set the scratch base pointer in 3DSTATE_*S using a relocation.
    * However, in order to do so, we need to ensure that the kernel does not
    * place the scratch BO above the 32-bit boundary.
    *
    * NOTE: Technically, it can't go "anywhere" because the top page is off
    * limits.  However, when EXEC_OBJECT_SUPPORTS_48B_ADDRESS is set, the
    * kernel allocates space using
    *
    *    end = min_t(u64, end, (1ULL << 32) - I915_GTT_PAGE_SIZE);
    *
    * so nothing will ever touch the top page.
    */
1160
1161
1162
1163
   assert(!(bo->bo.flags & EXEC_OBJECT_SUPPORTS_48B_ADDRESS));

   if (device->instance->physicalDevice.has_exec_async)
      bo->bo.flags |= EXEC_OBJECT_ASYNC;
1164

1165
1166
1167
   /* Set the exists last because it may be read by other threads */
   __sync_synchronize();
   bo->exists = true;
1168

1169
   pthread_mutex_unlock(&device->mutex);
1170

1171
   return &bo->bo;
1172
}
Jason Ekstrand's avatar
Jason Ekstrand committed
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189

struct anv_cached_bo {
   struct anv_bo bo;

   uint32_t refcount;
};

VkResult
anv_bo_cache_init(struct anv_bo_cache *cache)
{
   cache->bo_map = _mesa_hash_table_create(NULL, _mesa_hash_pointer,
                                           _mesa_key_pointer_equal);
   if (!cache->bo_map)
      return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);

   if (pthread_mutex_init(&cache->mutex, NULL)) {
      _mesa_hash_table_destroy(cache->bo_map, NULL);
1190
      return vk_errorf(NULL, NULL, VK_ERROR_OUT_OF_HOST_MEMORY,
Jason Ekstrand's avatar
Jason Ekstrand committed
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
                       "pthread_mutex_init failed: %m");
   }

   return VK_SUCCESS;
}

void
anv_bo_cache_finish(struct anv_bo_cache *cache)
{
   _mesa_hash_table_destroy(cache->bo_map, NULL);
   pthread_mutex_destroy(&cache->mutex);
}

static struct anv_cached_bo *
anv_bo_cache_lookup_locked(struct anv_bo_cache *cache, uint32_t gem_handle)
{
   struct hash_entry *entry =
      _mesa_hash_table_search(cache->bo_map,
                              (const void *)(uintptr_t)gem_handle);
   if (!entry)
      return NULL;

   struct anv_cached_bo *bo = (struct anv_cached_bo *)entry->data;
   assert(bo->bo.gem_handle == gem_handle);

   return bo;
}

1219
UNUSED static struct anv_bo *
Jason Ekstrand's avatar
Jason Ekstrand committed
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
anv_bo_cache_lookup(struct anv_bo_cache *cache, uint32_t gem_handle)
{
   pthread_mutex_lock(&cache->mutex);

   struct anv_cached_bo *bo = anv_bo_cache_lookup_locked(cache, gem_handle);

   pthread_mutex_unlock(&cache->mutex);

   return bo ? &bo->bo : NULL;
}

VkResult
anv_bo_cache_alloc(struct anv_device *device,
                   struct anv_bo_cache *cache,
                   uint64_t size, struct anv_bo **bo_out)
{
   struct anv_cached_bo *bo =
      vk_alloc(&device->alloc, sizeof(struct anv_cached_bo), 8,
               VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
   if (!bo)
      return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);

   bo->refcount = 1;

   /* The kernel is going to give us whole pages anyway */
   size = align_u64(size, 4096);

   VkResult result = anv_bo_init_new(&bo->bo, device, size);
   if (result != VK_SUCCESS) {
      vk_free(&device->alloc, bo);
      return result;
   }

   assert(bo->bo.gem_handle);

   pthread_mutex_lock(&cache->mutex);

   _mesa_hash_table_insert(cache->bo_map,
                           (void *)(uintptr_t)bo->bo.gem_handle, bo);

   pthread_mutex_unlock(&cache->mutex);

   *bo_out = &bo->bo;

   return VK_SUCCESS;
}

VkResult
anv_bo_cache_import(struct anv_device *device,
                    struct anv_bo_cache *cache,
1270
                    int fd, struct anv_bo **bo_out)
Jason Ekstrand's avatar
Jason Ekstrand committed
1271
1272
1273
1274
1275
1276
{
   pthread_mutex_lock(&cache->mutex);

   uint32_t gem_handle = anv_gem_fd_to_handle(device, fd);
   if (!gem_handle) {
      pthread_mutex_unlock(&cache->mutex);
1277
      return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR);
Jason Ekstrand's avatar
Jason Ekstrand committed
1278
1279
1280
1281
1282
1283
   }

   struct anv_cached_bo *bo = anv_bo_cache_lookup_locked(cache, gem_handle);
   if (bo) {
      __sync_fetch_and_add(&bo->refcount, 1);
   } else {
1284
1285
      off_t size = lseek(fd, 0, SEEK_END);
      if (size == (off_t)-1) {
Jason Ekstrand's avatar
Jason Ekstrand committed
1286
1287
         anv_gem_close(device, gem_handle);
         pthread_mutex_unlock(&cache->mutex);
1288
         return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR);
Jason Ekstrand's avatar
Jason Ekstrand committed
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360