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