• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 Google LLC
3  * SPDX-License-Identifier: MIT
4  *
5  * based in part on anv and radv which are:
6  * Copyright © 2015 Intel Corporation
7  * Copyright © 2016 Red Hat.
8  * Copyright © 2016 Bas Nieuwenhuizen
9  */
10 
11 #include "vn_buffer.h"
12 
13 #include "venus-protocol/vn_protocol_driver_buffer.h"
14 #include "venus-protocol/vn_protocol_driver_buffer_view.h"
15 
16 #include "vn_android.h"
17 #include "vn_device.h"
18 #include "vn_device_memory.h"
19 #include "vn_physical_device.h"
20 
21 /* buffer commands */
22 
23 static inline uint64_t
vn_buffer_get_cache_index(const VkBufferCreateInfo * create_info,struct vn_buffer_reqs_cache * cache)24 vn_buffer_get_cache_index(const VkBufferCreateInfo *create_info,
25                           struct vn_buffer_reqs_cache *cache)
26 {
27    /* For simplicity, cache only when below conditions are met:
28     * - pNext is NULL
29     * - VK_SHARING_MODE_EXCLUSIVE or VK_SHARING_MODE_CONCURRENT across all
30     *
31     * Combine sharing mode, flags and usage bits to form a unique index.
32     *
33     * Btw, we assume VkBufferCreateFlagBits won't exhaust all 32bits, at least
34     * no earlier than VkBufferUsageFlagBits.
35     *
36     * TODO: extend cache to cover VkBufferUsageFlags2CreateInfo (introduced in
37     * VK_KHR_maintenance5 and promoted to 1.4).
38     */
39    assert(!(create_info->flags & 0x80000000));
40 
41    const bool is_exclusive =
42       create_info->sharingMode == VK_SHARING_MODE_EXCLUSIVE;
43    const bool is_concurrent =
44       create_info->sharingMode == VK_SHARING_MODE_CONCURRENT &&
45       create_info->queueFamilyIndexCount == cache->queue_family_count;
46    if (create_info->size <= cache->max_buffer_size &&
47        create_info->pNext == NULL && (is_exclusive || is_concurrent)) {
48       return (uint64_t)is_concurrent << 63 |
49              (uint64_t)create_info->flags << 32 | create_info->usage;
50    }
51 
52    /* index being zero suggests uncachable since usage must not be zero */
53    return 0;
54 }
55 
56 static inline uint64_t
vn_buffer_get_max_buffer_size(struct vn_physical_device * physical_dev)57 vn_buffer_get_max_buffer_size(struct vn_physical_device *physical_dev)
58 {
59    /* Without maintenance4, hardcode the min of supported drivers:
60     * - anv:  1ull << 30
61     * - radv: UINT32_MAX - 4
62     * - tu:   UINT32_MAX + 1
63     * - lvp:  UINT32_MAX
64     * - mali: UINT32_MAX
65     */
66    static const uint64_t safe_max_buffer_size = 1ULL << 30;
67    return physical_dev->base.base.supported_features.maintenance4
68              ? physical_dev->base.base.properties.maxBufferSize
69              : safe_max_buffer_size;
70 }
71 
72 void
vn_buffer_reqs_cache_init(struct vn_device * dev)73 vn_buffer_reqs_cache_init(struct vn_device *dev)
74 {
75    assert(dev->physical_device->queue_family_count);
76 
77    dev->buffer_reqs_cache.max_buffer_size =
78       vn_buffer_get_max_buffer_size(dev->physical_device);
79    dev->buffer_reqs_cache.queue_family_count =
80       dev->physical_device->queue_family_count;
81 
82    simple_mtx_init(&dev->buffer_reqs_cache.mutex, mtx_plain);
83    util_sparse_array_init(&dev->buffer_reqs_cache.entries,
84                           sizeof(struct vn_buffer_reqs_cache_entry), 64);
85 }
86 
87 static void
vn_buffer_reqs_cache_debug_dump(struct vn_buffer_reqs_cache * cache)88 vn_buffer_reqs_cache_debug_dump(struct vn_buffer_reqs_cache *cache)
89 {
90    vn_log(NULL, "dumping buffer cache statistics");
91    vn_log(NULL, "  cache hit: %d", cache->debug.cache_hit_count);
92    vn_log(NULL, "  cache miss: %d", cache->debug.cache_miss_count);
93    vn_log(NULL, "  cache skip: %d", cache->debug.cache_skip_count);
94 }
95 
96 void
vn_buffer_reqs_cache_fini(struct vn_device * dev)97 vn_buffer_reqs_cache_fini(struct vn_device *dev)
98 {
99    util_sparse_array_finish(&dev->buffer_reqs_cache.entries);
100    simple_mtx_destroy(&dev->buffer_reqs_cache.mutex);
101 
102    if (VN_DEBUG(CACHE))
103       vn_buffer_reqs_cache_debug_dump(&dev->buffer_reqs_cache);
104 }
105 
106 static inline uint32_t
vn_buffer_get_ahb_memory_type_bits(struct vn_device * dev)107 vn_buffer_get_ahb_memory_type_bits(struct vn_device *dev)
108 {
109    struct vn_buffer_reqs_cache *cache = &dev->buffer_reqs_cache;
110    if (unlikely(!cache->ahb_mem_type_bits_valid)) {
111       simple_mtx_lock(&cache->mutex);
112       if (!cache->ahb_mem_type_bits_valid) {
113          cache->ahb_mem_type_bits =
114             vn_android_get_ahb_buffer_memory_type_bits(dev);
115          cache->ahb_mem_type_bits_valid = true;
116       }
117       simple_mtx_unlock(&cache->mutex);
118    }
119 
120    return cache->ahb_mem_type_bits;
121 }
122 
123 static inline VkDeviceSize
vn_buffer_get_aligned_memory_requirement_size(VkDeviceSize size,const VkMemoryRequirements * req)124 vn_buffer_get_aligned_memory_requirement_size(VkDeviceSize size,
125                                               const VkMemoryRequirements *req)
126 {
127    /* TODO remove comment after mandating VK_KHR_maintenance4
128     *
129     * This is based on below implementation defined behavior:
130     *    req.size <= align64(info.size, req.alignment)
131     */
132    return align64(size, req->alignment);
133 }
134 
135 static struct vn_buffer_reqs_cache_entry *
vn_buffer_get_cached_memory_requirements(struct vn_buffer_reqs_cache * cache,const VkBufferCreateInfo * create_info,struct vn_buffer_memory_requirements * out)136 vn_buffer_get_cached_memory_requirements(
137    struct vn_buffer_reqs_cache *cache,
138    const VkBufferCreateInfo *create_info,
139    struct vn_buffer_memory_requirements *out)
140 {
141    if (VN_PERF(NO_ASYNC_BUFFER_CREATE))
142       return NULL;
143 
144    /* 12.7. Resource Memory Association
145     *
146     * The memoryTypeBits member is identical for all VkBuffer objects created
147     * with the same value for the flags and usage members in the
148     * VkBufferCreateInfo structure and the handleTypes member of the
149     * VkExternalMemoryBufferCreateInfo structure passed to vkCreateBuffer.
150     */
151    const uint64_t idx = vn_buffer_get_cache_index(create_info, cache);
152    if (idx) {
153       struct vn_buffer_reqs_cache_entry *entry =
154          util_sparse_array_get(&cache->entries, idx);
155 
156       if (entry->valid) {
157          *out = entry->requirements;
158 
159          out->memory.memoryRequirements.size =
160             vn_buffer_get_aligned_memory_requirement_size(
161                create_info->size, &out->memory.memoryRequirements);
162 
163          p_atomic_inc(&cache->debug.cache_hit_count);
164       } else {
165          p_atomic_inc(&cache->debug.cache_miss_count);
166       }
167 
168       return entry;
169    }
170 
171    p_atomic_inc(&cache->debug.cache_skip_count);
172 
173    return NULL;
174 }
175 
176 static void
vn_buffer_reqs_cache_entry_init(struct vn_buffer_reqs_cache * cache,struct vn_buffer_reqs_cache_entry * entry,VkMemoryRequirements2 * req)177 vn_buffer_reqs_cache_entry_init(struct vn_buffer_reqs_cache *cache,
178                                 struct vn_buffer_reqs_cache_entry *entry,
179                                 VkMemoryRequirements2 *req)
180 {
181    simple_mtx_lock(&cache->mutex);
182 
183    /* Entry might have already been initialized by another thread
184     * before the lock
185     */
186    if (entry->valid)
187       goto unlock;
188 
189    entry->requirements.memory = *req;
190 
191    const VkMemoryDedicatedRequirements *dedicated_req =
192       vk_find_struct_const(req->pNext, MEMORY_DEDICATED_REQUIREMENTS);
193    if (dedicated_req)
194       entry->requirements.dedicated = *dedicated_req;
195 
196    entry->valid = true;
197 
198 unlock:
199    simple_mtx_unlock(&cache->mutex);
200 
201    /* ensure invariance of the memory requirement size */
202    req->memoryRequirements.size =
203       vn_buffer_get_aligned_memory_requirement_size(
204          req->memoryRequirements.size,
205          &entry->requirements.memory.memoryRequirements);
206 }
207 
208 static void
vn_copy_cached_memory_requirements(const struct vn_buffer_memory_requirements * cached,VkMemoryRequirements2 * out_mem_req)209 vn_copy_cached_memory_requirements(
210    const struct vn_buffer_memory_requirements *cached,
211    VkMemoryRequirements2 *out_mem_req)
212 {
213    union {
214       VkBaseOutStructure *pnext;
215       VkMemoryRequirements2 *two;
216       VkMemoryDedicatedRequirements *dedicated;
217    } u = { .two = out_mem_req };
218 
219    while (u.pnext) {
220       switch (u.pnext->sType) {
221       case VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2:
222          u.two->memoryRequirements = cached->memory.memoryRequirements;
223          break;
224       case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS:
225          u.dedicated->prefersDedicatedAllocation =
226             cached->dedicated.prefersDedicatedAllocation;
227          u.dedicated->requiresDedicatedAllocation =
228             cached->dedicated.requiresDedicatedAllocation;
229          break;
230       default:
231          break;
232       }
233       u.pnext = u.pnext->pNext;
234    }
235 }
236 
237 static VkResult
vn_buffer_init(struct vn_device * dev,const VkBufferCreateInfo * create_info,struct vn_buffer * buf)238 vn_buffer_init(struct vn_device *dev,
239                const VkBufferCreateInfo *create_info,
240                struct vn_buffer *buf)
241 {
242    VkDevice dev_handle = vn_device_to_handle(dev);
243    VkBuffer buf_handle = vn_buffer_to_handle(buf);
244    struct vn_buffer_reqs_cache *cache = &dev->buffer_reqs_cache;
245    VkResult result;
246 
247    /* If cacheable and mem requirements found in cache, make async call */
248    struct vn_buffer_reqs_cache_entry *entry =
249       vn_buffer_get_cached_memory_requirements(cache, create_info,
250                                                &buf->requirements);
251 
252    /* Check size instead of entry->valid to be lock free */
253    if (buf->requirements.memory.memoryRequirements.size) {
254       vn_async_vkCreateBuffer(dev->primary_ring, dev_handle, create_info,
255                               NULL, &buf_handle);
256       return VK_SUCCESS;
257    }
258 
259    /* If cache miss or not cacheable, make synchronous call */
260    result = vn_call_vkCreateBuffer(dev->primary_ring, dev_handle, create_info,
261                                    NULL, &buf_handle);
262    if (result != VK_SUCCESS)
263       return result;
264 
265    buf->requirements.memory.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
266    buf->requirements.memory.pNext = &buf->requirements.dedicated;
267    buf->requirements.dedicated.sType =
268       VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS;
269    buf->requirements.dedicated.pNext = NULL;
270 
271    vn_call_vkGetBufferMemoryRequirements2(
272       dev->primary_ring, dev_handle,
273       &(VkBufferMemoryRequirementsInfo2){
274          .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2,
275          .buffer = buf_handle,
276       },
277       &buf->requirements.memory);
278 
279    /* If cacheable, store mem requirements from the synchronous call */
280    if (entry) {
281       vn_buffer_reqs_cache_entry_init(cache, entry,
282                                       &buf->requirements.memory);
283    }
284 
285    return VK_SUCCESS;
286 }
287 
288 VkResult
vn_buffer_create(struct vn_device * dev,const VkBufferCreateInfo * create_info,const VkAllocationCallbacks * alloc,struct vn_buffer ** out_buf)289 vn_buffer_create(struct vn_device *dev,
290                  const VkBufferCreateInfo *create_info,
291                  const VkAllocationCallbacks *alloc,
292                  struct vn_buffer **out_buf)
293 {
294    struct vn_buffer *buf = NULL;
295    VkResult result;
296 
297    buf = vk_zalloc(alloc, sizeof(*buf), VN_DEFAULT_ALIGN,
298                    VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
299    if (!buf)
300       return VK_ERROR_OUT_OF_HOST_MEMORY;
301 
302    vn_object_base_init(&buf->base, VK_OBJECT_TYPE_BUFFER, &dev->base);
303 
304    result = vn_buffer_init(dev, create_info, buf);
305    if (result != VK_SUCCESS) {
306       vn_object_base_fini(&buf->base);
307       vk_free(alloc, buf);
308       return result;
309    }
310 
311    *out_buf = buf;
312 
313    return VK_SUCCESS;
314 }
315 
316 struct vn_buffer_create_info {
317    VkBufferCreateInfo create;
318    VkExternalMemoryBufferCreateInfo external;
319    VkBufferOpaqueCaptureAddressCreateInfo capture;
320 };
321 
322 static const VkBufferCreateInfo *
vn_buffer_fix_create_info(const VkBufferCreateInfo * create_info,const VkExternalMemoryHandleTypeFlagBits renderer_handle_type,struct vn_buffer_create_info * local_info)323 vn_buffer_fix_create_info(
324    const VkBufferCreateInfo *create_info,
325    const VkExternalMemoryHandleTypeFlagBits renderer_handle_type,
326    struct vn_buffer_create_info *local_info)
327 {
328    local_info->create = *create_info;
329    VkBaseOutStructure *cur = (void *)&local_info->create;
330 
331    vk_foreach_struct_const(src, create_info->pNext) {
332       void *next = NULL;
333       switch (src->sType) {
334       case VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO:
335          memcpy(&local_info->external, src, sizeof(local_info->external));
336          local_info->external.handleTypes = renderer_handle_type;
337          next = &local_info->external;
338          break;
339       case VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO:
340          memcpy(&local_info->capture, src, sizeof(local_info->capture));
341          next = &local_info->capture;
342          break;
343       default:
344          break;
345       }
346 
347       if (next) {
348          cur->pNext = next;
349          cur = next;
350       }
351    }
352 
353    cur->pNext = NULL;
354 
355    return &local_info->create;
356 }
357 
358 VkResult
vn_CreateBuffer(VkDevice device,const VkBufferCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkBuffer * pBuffer)359 vn_CreateBuffer(VkDevice device,
360                 const VkBufferCreateInfo *pCreateInfo,
361                 const VkAllocationCallbacks *pAllocator,
362                 VkBuffer *pBuffer)
363 {
364    struct vn_device *dev = vn_device_from_handle(device);
365    const VkAllocationCallbacks *alloc =
366       pAllocator ? pAllocator : &dev->base.base.alloc;
367    const VkExternalMemoryHandleTypeFlagBits renderer_handle_type =
368       dev->physical_device->external_memory.renderer_handle_type;
369 
370    struct vn_buffer_create_info local_info;
371    const VkExternalMemoryBufferCreateInfo *external_info =
372       vk_find_struct_const(pCreateInfo->pNext,
373                            EXTERNAL_MEMORY_BUFFER_CREATE_INFO);
374    if (external_info && external_info->handleTypes &&
375        external_info->handleTypes != renderer_handle_type) {
376       pCreateInfo = vn_buffer_fix_create_info(
377          pCreateInfo, renderer_handle_type, &local_info);
378    }
379 
380    struct vn_buffer *buf;
381    VkResult result = vn_buffer_create(dev, pCreateInfo, alloc, &buf);
382    if (result != VK_SUCCESS)
383       return vn_error(dev->instance, result);
384 
385    if (external_info &&
386        external_info->handleTypes ==
387           VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID) {
388       /* AHB backed buffer layers on top of renderer external memory, so here
389        * we combine the queried type bits from both buffer memory requirement
390        * and renderer external memory properties.
391        */
392       buf->requirements.memory.memoryRequirements.memoryTypeBits &=
393          vn_buffer_get_ahb_memory_type_bits(dev);
394 
395       assert(buf->requirements.memory.memoryRequirements.memoryTypeBits);
396    }
397 
398    *pBuffer = vn_buffer_to_handle(buf);
399 
400    return VK_SUCCESS;
401 }
402 
403 void
vn_DestroyBuffer(VkDevice device,VkBuffer buffer,const VkAllocationCallbacks * pAllocator)404 vn_DestroyBuffer(VkDevice device,
405                  VkBuffer buffer,
406                  const VkAllocationCallbacks *pAllocator)
407 {
408    struct vn_device *dev = vn_device_from_handle(device);
409    struct vn_buffer *buf = vn_buffer_from_handle(buffer);
410    const VkAllocationCallbacks *alloc =
411       pAllocator ? pAllocator : &dev->base.base.alloc;
412 
413    if (!buf)
414       return;
415 
416    vn_async_vkDestroyBuffer(dev->primary_ring, device, buffer, NULL);
417 
418    vn_object_base_fini(&buf->base);
419    vk_free(alloc, buf);
420 }
421 
422 VkDeviceAddress
vn_GetBufferDeviceAddress(VkDevice device,const VkBufferDeviceAddressInfo * pInfo)423 vn_GetBufferDeviceAddress(VkDevice device,
424                           const VkBufferDeviceAddressInfo *pInfo)
425 {
426    struct vn_device *dev = vn_device_from_handle(device);
427 
428    return vn_call_vkGetBufferDeviceAddress(dev->primary_ring, device, pInfo);
429 }
430 
431 uint64_t
vn_GetBufferOpaqueCaptureAddress(VkDevice device,const VkBufferDeviceAddressInfo * pInfo)432 vn_GetBufferOpaqueCaptureAddress(VkDevice device,
433                                  const VkBufferDeviceAddressInfo *pInfo)
434 {
435    struct vn_device *dev = vn_device_from_handle(device);
436 
437    return vn_call_vkGetBufferOpaqueCaptureAddress(dev->primary_ring, device,
438                                                   pInfo);
439 }
440 
441 void
vn_GetBufferMemoryRequirements2(VkDevice device,const VkBufferMemoryRequirementsInfo2 * pInfo,VkMemoryRequirements2 * pMemoryRequirements)442 vn_GetBufferMemoryRequirements2(VkDevice device,
443                                 const VkBufferMemoryRequirementsInfo2 *pInfo,
444                                 VkMemoryRequirements2 *pMemoryRequirements)
445 {
446    const struct vn_buffer *buf = vn_buffer_from_handle(pInfo->buffer);
447 
448    vn_copy_cached_memory_requirements(&buf->requirements,
449                                       pMemoryRequirements);
450 }
451 
452 VkResult
vn_BindBufferMemory2(VkDevice device,uint32_t bindInfoCount,const VkBindBufferMemoryInfo * pBindInfos)453 vn_BindBufferMemory2(VkDevice device,
454                      uint32_t bindInfoCount,
455                      const VkBindBufferMemoryInfo *pBindInfos)
456 {
457    struct vn_device *dev = vn_device_from_handle(device);
458    vn_async_vkBindBufferMemory2(dev->primary_ring, device, bindInfoCount,
459                                 pBindInfos);
460 
461    return VK_SUCCESS;
462 }
463 
464 /* buffer view commands */
465 
466 VkResult
vn_CreateBufferView(VkDevice device,const VkBufferViewCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkBufferView * pView)467 vn_CreateBufferView(VkDevice device,
468                     const VkBufferViewCreateInfo *pCreateInfo,
469                     const VkAllocationCallbacks *pAllocator,
470                     VkBufferView *pView)
471 {
472    struct vn_device *dev = vn_device_from_handle(device);
473    const VkAllocationCallbacks *alloc =
474       pAllocator ? pAllocator : &dev->base.base.alloc;
475 
476    struct vn_buffer_view *view =
477       vk_zalloc(alloc, sizeof(*view), VN_DEFAULT_ALIGN,
478                 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
479    if (!view)
480       return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
481 
482    vn_object_base_init(&view->base, VK_OBJECT_TYPE_BUFFER_VIEW, &dev->base);
483 
484    VkBufferView view_handle = vn_buffer_view_to_handle(view);
485    vn_async_vkCreateBufferView(dev->primary_ring, device, pCreateInfo, NULL,
486                                &view_handle);
487 
488    *pView = view_handle;
489 
490    return VK_SUCCESS;
491 }
492 
493 void
vn_DestroyBufferView(VkDevice device,VkBufferView bufferView,const VkAllocationCallbacks * pAllocator)494 vn_DestroyBufferView(VkDevice device,
495                      VkBufferView bufferView,
496                      const VkAllocationCallbacks *pAllocator)
497 {
498    struct vn_device *dev = vn_device_from_handle(device);
499    struct vn_buffer_view *view = vn_buffer_view_from_handle(bufferView);
500    const VkAllocationCallbacks *alloc =
501       pAllocator ? pAllocator : &dev->base.base.alloc;
502 
503    if (!view)
504       return;
505 
506    vn_async_vkDestroyBufferView(dev->primary_ring, device, bufferView, NULL);
507 
508    vn_object_base_fini(&view->base);
509    vk_free(alloc, view);
510 }
511 
512 void
vn_GetDeviceBufferMemoryRequirements(VkDevice device,const VkDeviceBufferMemoryRequirements * pInfo,VkMemoryRequirements2 * pMemoryRequirements)513 vn_GetDeviceBufferMemoryRequirements(
514    VkDevice device,
515    const VkDeviceBufferMemoryRequirements *pInfo,
516    VkMemoryRequirements2 *pMemoryRequirements)
517 {
518    struct vn_device *dev = vn_device_from_handle(device);
519    struct vn_buffer_reqs_cache *cache = &dev->buffer_reqs_cache;
520    struct vn_buffer_memory_requirements reqs = { 0 };
521 
522    /* If cacheable and mem requirements found in cache, skip host call */
523    struct vn_buffer_reqs_cache_entry *entry =
524       vn_buffer_get_cached_memory_requirements(cache, pInfo->pCreateInfo,
525                                                &reqs);
526 
527    /* Check size instead of entry->valid to be lock free */
528    if (reqs.memory.memoryRequirements.size) {
529       vn_copy_cached_memory_requirements(&reqs, pMemoryRequirements);
530       return;
531    }
532 
533    /* Make the host call if not found in cache or not cacheable */
534    vn_call_vkGetDeviceBufferMemoryRequirements(dev->primary_ring, device,
535                                                pInfo, pMemoryRequirements);
536 
537    /* If cacheable, store mem requirements from the host call */
538    if (entry)
539       vn_buffer_reqs_cache_entry_init(cache, entry, pMemoryRequirements);
540 }
541