1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright 2022 Google LLC 3bf215546Sopenharmony_ci * SPDX-License-Identifier: MIT 4bf215546Sopenharmony_ci */ 5bf215546Sopenharmony_ci 6bf215546Sopenharmony_ci#include "vn_feedback.h" 7bf215546Sopenharmony_ci 8bf215546Sopenharmony_ci#include "vn_device.h" 9bf215546Sopenharmony_ci#include "vn_physical_device.h" 10bf215546Sopenharmony_ci#include "vn_queue.h" 11bf215546Sopenharmony_ci 12bf215546Sopenharmony_ci/* coherent buffer with bound and mapped memory */ 13bf215546Sopenharmony_cistruct vn_feedback_buffer { 14bf215546Sopenharmony_ci VkBuffer buffer; 15bf215546Sopenharmony_ci VkDeviceMemory memory; 16bf215546Sopenharmony_ci void *data; 17bf215546Sopenharmony_ci 18bf215546Sopenharmony_ci struct list_head head; 19bf215546Sopenharmony_ci}; 20bf215546Sopenharmony_ci 21bf215546Sopenharmony_cistatic uint32_t 22bf215546Sopenharmony_civn_get_memory_type_index(const VkPhysicalDeviceMemoryProperties *mem_props, 23bf215546Sopenharmony_ci uint32_t mem_type_bits, 24bf215546Sopenharmony_ci VkMemoryPropertyFlags required_mem_flags) 25bf215546Sopenharmony_ci{ 26bf215546Sopenharmony_ci u_foreach_bit(mem_type_index, mem_type_bits) 27bf215546Sopenharmony_ci { 28bf215546Sopenharmony_ci assert(mem_type_index < mem_props->memoryTypeCount); 29bf215546Sopenharmony_ci if ((mem_props->memoryTypes[mem_type_index].propertyFlags & 30bf215546Sopenharmony_ci required_mem_flags) == required_mem_flags) 31bf215546Sopenharmony_ci return mem_type_index; 32bf215546Sopenharmony_ci } 33bf215546Sopenharmony_ci 34bf215546Sopenharmony_ci return UINT32_MAX; 35bf215546Sopenharmony_ci} 36bf215546Sopenharmony_ci 37bf215546Sopenharmony_cistatic VkResult 38bf215546Sopenharmony_civn_feedback_buffer_create(struct vn_device *dev, 39bf215546Sopenharmony_ci uint32_t size, 40bf215546Sopenharmony_ci const VkAllocationCallbacks *alloc, 41bf215546Sopenharmony_ci struct vn_feedback_buffer **out_feedback_buf) 42bf215546Sopenharmony_ci{ 43bf215546Sopenharmony_ci const bool exclusive = dev->queue_family_count == 1; 44bf215546Sopenharmony_ci const VkPhysicalDeviceMemoryProperties *mem_props = 45bf215546Sopenharmony_ci &dev->physical_device->memory_properties.memoryProperties; 46bf215546Sopenharmony_ci VkDevice dev_handle = vn_device_to_handle(dev); 47bf215546Sopenharmony_ci struct vn_feedback_buffer *feedback_buf; 48bf215546Sopenharmony_ci VkResult result; 49bf215546Sopenharmony_ci 50bf215546Sopenharmony_ci feedback_buf = vk_zalloc(alloc, sizeof(*feedback_buf), VN_DEFAULT_ALIGN, 51bf215546Sopenharmony_ci VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 52bf215546Sopenharmony_ci if (!feedback_buf) 53bf215546Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 54bf215546Sopenharmony_ci 55bf215546Sopenharmony_ci /* use concurrent to avoid explicit queue family ownership transfer for 56bf215546Sopenharmony_ci * device created with queues from multiple queue families 57bf215546Sopenharmony_ci */ 58bf215546Sopenharmony_ci const VkBufferCreateInfo buf_create_info = { 59bf215546Sopenharmony_ci .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 60bf215546Sopenharmony_ci .size = size, 61bf215546Sopenharmony_ci .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT, 62bf215546Sopenharmony_ci .sharingMode = 63bf215546Sopenharmony_ci exclusive ? VK_SHARING_MODE_EXCLUSIVE : VK_SHARING_MODE_CONCURRENT, 64bf215546Sopenharmony_ci /* below favors the current venus protocol */ 65bf215546Sopenharmony_ci .queueFamilyIndexCount = exclusive ? 0 : dev->queue_family_count, 66bf215546Sopenharmony_ci .pQueueFamilyIndices = exclusive ? NULL : dev->queue_families, 67bf215546Sopenharmony_ci }; 68bf215546Sopenharmony_ci result = vn_CreateBuffer(dev_handle, &buf_create_info, alloc, 69bf215546Sopenharmony_ci &feedback_buf->buffer); 70bf215546Sopenharmony_ci if (result != VK_SUCCESS) 71bf215546Sopenharmony_ci goto out_free_feedback_buf; 72bf215546Sopenharmony_ci 73bf215546Sopenharmony_ci struct vn_buffer *buf = vn_buffer_from_handle(feedback_buf->buffer); 74bf215546Sopenharmony_ci const VkMemoryRequirements *mem_req = 75bf215546Sopenharmony_ci &buf->requirements.memory.memoryRequirements; 76bf215546Sopenharmony_ci const uint32_t mem_type_index = 77bf215546Sopenharmony_ci vn_get_memory_type_index(mem_props, mem_req->memoryTypeBits, 78bf215546Sopenharmony_ci VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); 79bf215546Sopenharmony_ci if (mem_type_index >= mem_props->memoryTypeCount) { 80bf215546Sopenharmony_ci result = VK_ERROR_INITIALIZATION_FAILED; 81bf215546Sopenharmony_ci goto out_destroy_buffer; 82bf215546Sopenharmony_ci } 83bf215546Sopenharmony_ci 84bf215546Sopenharmony_ci const VkMemoryAllocateInfo mem_alloc_info = { 85bf215546Sopenharmony_ci .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, 86bf215546Sopenharmony_ci .allocationSize = mem_req->size, 87bf215546Sopenharmony_ci .memoryTypeIndex = mem_type_index, 88bf215546Sopenharmony_ci }; 89bf215546Sopenharmony_ci result = vn_AllocateMemory(dev_handle, &mem_alloc_info, alloc, 90bf215546Sopenharmony_ci &feedback_buf->memory); 91bf215546Sopenharmony_ci if (result != VK_SUCCESS) 92bf215546Sopenharmony_ci goto out_destroy_buffer; 93bf215546Sopenharmony_ci 94bf215546Sopenharmony_ci const VkBindBufferMemoryInfo bind_info = { 95bf215546Sopenharmony_ci .sType = VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO, 96bf215546Sopenharmony_ci .buffer = feedback_buf->buffer, 97bf215546Sopenharmony_ci .memory = feedback_buf->memory, 98bf215546Sopenharmony_ci .memoryOffset = 0, 99bf215546Sopenharmony_ci }; 100bf215546Sopenharmony_ci result = vn_BindBufferMemory2(dev_handle, 1, &bind_info); 101bf215546Sopenharmony_ci if (result != VK_SUCCESS) 102bf215546Sopenharmony_ci goto out_free_memory; 103bf215546Sopenharmony_ci 104bf215546Sopenharmony_ci result = vn_MapMemory(dev_handle, feedback_buf->memory, 0, VK_WHOLE_SIZE, 105bf215546Sopenharmony_ci 0, &feedback_buf->data); 106bf215546Sopenharmony_ci if (result != VK_SUCCESS) 107bf215546Sopenharmony_ci goto out_free_memory; 108bf215546Sopenharmony_ci 109bf215546Sopenharmony_ci *out_feedback_buf = feedback_buf; 110bf215546Sopenharmony_ci 111bf215546Sopenharmony_ci return VK_SUCCESS; 112bf215546Sopenharmony_ci 113bf215546Sopenharmony_ciout_free_memory: 114bf215546Sopenharmony_ci vn_FreeMemory(dev_handle, feedback_buf->memory, alloc); 115bf215546Sopenharmony_ci 116bf215546Sopenharmony_ciout_destroy_buffer: 117bf215546Sopenharmony_ci vn_DestroyBuffer(dev_handle, feedback_buf->buffer, alloc); 118bf215546Sopenharmony_ci 119bf215546Sopenharmony_ciout_free_feedback_buf: 120bf215546Sopenharmony_ci vk_free(alloc, feedback_buf); 121bf215546Sopenharmony_ci 122bf215546Sopenharmony_ci return result; 123bf215546Sopenharmony_ci} 124bf215546Sopenharmony_ci 125bf215546Sopenharmony_cistatic void 126bf215546Sopenharmony_civn_feedback_buffer_destroy(struct vn_device *dev, 127bf215546Sopenharmony_ci struct vn_feedback_buffer *feedback_buf, 128bf215546Sopenharmony_ci const VkAllocationCallbacks *alloc) 129bf215546Sopenharmony_ci{ 130bf215546Sopenharmony_ci VkDevice dev_handle = vn_device_to_handle(dev); 131bf215546Sopenharmony_ci 132bf215546Sopenharmony_ci vn_UnmapMemory(dev_handle, feedback_buf->memory); 133bf215546Sopenharmony_ci vn_FreeMemory(dev_handle, feedback_buf->memory, alloc); 134bf215546Sopenharmony_ci vn_DestroyBuffer(dev_handle, feedback_buf->buffer, alloc); 135bf215546Sopenharmony_ci vk_free(alloc, feedback_buf); 136bf215546Sopenharmony_ci} 137bf215546Sopenharmony_ci 138bf215546Sopenharmony_cistatic VkResult 139bf215546Sopenharmony_civn_feedback_pool_grow_locked(struct vn_feedback_pool *pool) 140bf215546Sopenharmony_ci{ 141bf215546Sopenharmony_ci VN_TRACE_FUNC(); 142bf215546Sopenharmony_ci struct vn_feedback_buffer *feedback_buf = NULL; 143bf215546Sopenharmony_ci VkResult result; 144bf215546Sopenharmony_ci 145bf215546Sopenharmony_ci result = vn_feedback_buffer_create(pool->device, pool->size, pool->alloc, 146bf215546Sopenharmony_ci &feedback_buf); 147bf215546Sopenharmony_ci if (result != VK_SUCCESS) 148bf215546Sopenharmony_ci return result; 149bf215546Sopenharmony_ci 150bf215546Sopenharmony_ci pool->used = 0; 151bf215546Sopenharmony_ci 152bf215546Sopenharmony_ci list_add(&feedback_buf->head, &pool->feedback_buffers); 153bf215546Sopenharmony_ci 154bf215546Sopenharmony_ci return VK_SUCCESS; 155bf215546Sopenharmony_ci} 156bf215546Sopenharmony_ci 157bf215546Sopenharmony_ciVkResult 158bf215546Sopenharmony_civn_feedback_pool_init(struct vn_device *dev, 159bf215546Sopenharmony_ci struct vn_feedback_pool *pool, 160bf215546Sopenharmony_ci uint32_t size, 161bf215546Sopenharmony_ci const VkAllocationCallbacks *alloc) 162bf215546Sopenharmony_ci{ 163bf215546Sopenharmony_ci simple_mtx_init(&pool->mutex, mtx_plain); 164bf215546Sopenharmony_ci 165bf215546Sopenharmony_ci pool->device = dev; 166bf215546Sopenharmony_ci pool->alloc = alloc; 167bf215546Sopenharmony_ci pool->size = size; 168bf215546Sopenharmony_ci pool->used = size; 169bf215546Sopenharmony_ci list_inithead(&pool->feedback_buffers); 170bf215546Sopenharmony_ci list_inithead(&pool->free_slots); 171bf215546Sopenharmony_ci 172bf215546Sopenharmony_ci /* no lock needed upon init */ 173bf215546Sopenharmony_ci return vn_feedback_pool_grow_locked(pool); 174bf215546Sopenharmony_ci} 175bf215546Sopenharmony_ci 176bf215546Sopenharmony_civoid 177bf215546Sopenharmony_civn_feedback_pool_fini(struct vn_feedback_pool *pool) 178bf215546Sopenharmony_ci{ 179bf215546Sopenharmony_ci list_for_each_entry_safe(struct vn_feedback_slot, slot, &pool->free_slots, 180bf215546Sopenharmony_ci head) 181bf215546Sopenharmony_ci vk_free(pool->alloc, slot); 182bf215546Sopenharmony_ci 183bf215546Sopenharmony_ci list_for_each_entry_safe(struct vn_feedback_buffer, feedback_buf, 184bf215546Sopenharmony_ci &pool->feedback_buffers, head) 185bf215546Sopenharmony_ci vn_feedback_buffer_destroy(pool->device, feedback_buf, pool->alloc); 186bf215546Sopenharmony_ci 187bf215546Sopenharmony_ci simple_mtx_destroy(&pool->mutex); 188bf215546Sopenharmony_ci} 189bf215546Sopenharmony_ci 190bf215546Sopenharmony_cistatic struct vn_feedback_buffer * 191bf215546Sopenharmony_civn_feedback_pool_alloc_locked(struct vn_feedback_pool *pool, 192bf215546Sopenharmony_ci uint32_t size, 193bf215546Sopenharmony_ci uint32_t *out_offset) 194bf215546Sopenharmony_ci{ 195bf215546Sopenharmony_ci VN_TRACE_FUNC(); 196bf215546Sopenharmony_ci const uint32_t aligned_size = align(size, 4); 197bf215546Sopenharmony_ci 198bf215546Sopenharmony_ci if (unlikely(aligned_size > pool->size - pool->used)) { 199bf215546Sopenharmony_ci VkResult result = vn_feedback_pool_grow_locked(pool); 200bf215546Sopenharmony_ci if (result != VK_SUCCESS) 201bf215546Sopenharmony_ci return NULL; 202bf215546Sopenharmony_ci 203bf215546Sopenharmony_ci assert(aligned_size <= pool->size - pool->used); 204bf215546Sopenharmony_ci } 205bf215546Sopenharmony_ci 206bf215546Sopenharmony_ci *out_offset = pool->used; 207bf215546Sopenharmony_ci pool->used += aligned_size; 208bf215546Sopenharmony_ci 209bf215546Sopenharmony_ci return list_first_entry(&pool->feedback_buffers, struct vn_feedback_buffer, 210bf215546Sopenharmony_ci head); 211bf215546Sopenharmony_ci} 212bf215546Sopenharmony_ci 213bf215546Sopenharmony_cistruct vn_feedback_slot * 214bf215546Sopenharmony_civn_feedback_pool_alloc(struct vn_feedback_pool *pool, 215bf215546Sopenharmony_ci enum vn_feedback_type type) 216bf215546Sopenharmony_ci{ 217bf215546Sopenharmony_ci /* TODO Make slot size variable for VkQueryPool feedback. Currently it's 218bf215546Sopenharmony_ci * MAX2(sizeof(VkResult), sizeof(uint64_t)). 219bf215546Sopenharmony_ci */ 220bf215546Sopenharmony_ci static const uint32_t slot_size = 8; 221bf215546Sopenharmony_ci struct vn_feedback_buffer *feedback_buf; 222bf215546Sopenharmony_ci uint32_t offset; 223bf215546Sopenharmony_ci struct vn_feedback_slot *slot; 224bf215546Sopenharmony_ci 225bf215546Sopenharmony_ci simple_mtx_lock(&pool->mutex); 226bf215546Sopenharmony_ci if (!list_is_empty(&pool->free_slots)) { 227bf215546Sopenharmony_ci slot = 228bf215546Sopenharmony_ci list_first_entry(&pool->free_slots, struct vn_feedback_slot, head); 229bf215546Sopenharmony_ci list_del(&slot->head); 230bf215546Sopenharmony_ci simple_mtx_unlock(&pool->mutex); 231bf215546Sopenharmony_ci 232bf215546Sopenharmony_ci slot->type = type; 233bf215546Sopenharmony_ci return slot; 234bf215546Sopenharmony_ci } 235bf215546Sopenharmony_ci 236bf215546Sopenharmony_ci slot = vk_alloc(pool->alloc, sizeof(*slot), VN_DEFAULT_ALIGN, 237bf215546Sopenharmony_ci VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 238bf215546Sopenharmony_ci if (!slot) { 239bf215546Sopenharmony_ci simple_mtx_unlock(&pool->mutex); 240bf215546Sopenharmony_ci return NULL; 241bf215546Sopenharmony_ci } 242bf215546Sopenharmony_ci 243bf215546Sopenharmony_ci feedback_buf = vn_feedback_pool_alloc_locked(pool, slot_size, &offset); 244bf215546Sopenharmony_ci simple_mtx_unlock(&pool->mutex); 245bf215546Sopenharmony_ci 246bf215546Sopenharmony_ci if (!feedback_buf) { 247bf215546Sopenharmony_ci vk_free(pool->alloc, slot); 248bf215546Sopenharmony_ci return NULL; 249bf215546Sopenharmony_ci } 250bf215546Sopenharmony_ci 251bf215546Sopenharmony_ci slot->type = type; 252bf215546Sopenharmony_ci slot->offset = offset; 253bf215546Sopenharmony_ci slot->buffer = feedback_buf->buffer; 254bf215546Sopenharmony_ci slot->data = feedback_buf->data + offset; 255bf215546Sopenharmony_ci 256bf215546Sopenharmony_ci return slot; 257bf215546Sopenharmony_ci} 258bf215546Sopenharmony_ci 259bf215546Sopenharmony_civoid 260bf215546Sopenharmony_civn_feedback_pool_free(struct vn_feedback_pool *pool, 261bf215546Sopenharmony_ci struct vn_feedback_slot *slot) 262bf215546Sopenharmony_ci{ 263bf215546Sopenharmony_ci simple_mtx_lock(&pool->mutex); 264bf215546Sopenharmony_ci list_add(&slot->head, &pool->free_slots); 265bf215546Sopenharmony_ci simple_mtx_unlock(&pool->mutex); 266bf215546Sopenharmony_ci} 267bf215546Sopenharmony_ci 268bf215546Sopenharmony_civoid 269bf215546Sopenharmony_civn_feedback_event_cmd_record(VkCommandBuffer cmd_handle, 270bf215546Sopenharmony_ci VkEvent ev_handle, 271bf215546Sopenharmony_ci VkPipelineStageFlags stage_mask, 272bf215546Sopenharmony_ci VkResult status) 273bf215546Sopenharmony_ci{ 274bf215546Sopenharmony_ci /* For vkCmdSetEvent and vkCmdResetEvent feedback interception. 275bf215546Sopenharmony_ci * 276bf215546Sopenharmony_ci * The injection point is after the event call to avoid introducing 277bf215546Sopenharmony_ci * unexpected src stage waiting for VK_PIPELINE_STAGE_HOST_BIT and 278bf215546Sopenharmony_ci * VK_PIPELINE_STAGE_TRANSFER_BIT if they are not already being waited by 279bf215546Sopenharmony_ci * vkCmdSetEvent or vkCmdResetEvent. On the other hand, the delay in the 280bf215546Sopenharmony_ci * feedback signal is acceptable for the nature of VkEvent, and the event 281bf215546Sopenharmony_ci * feedback cmds lifecycle is guarded by the intercepted command buffer. 282bf215546Sopenharmony_ci */ 283bf215546Sopenharmony_ci struct vn_event *ev = vn_event_from_handle(ev_handle); 284bf215546Sopenharmony_ci struct vn_feedback_slot *slot = ev->feedback_slot; 285bf215546Sopenharmony_ci 286bf215546Sopenharmony_ci if (!slot) 287bf215546Sopenharmony_ci return; 288bf215546Sopenharmony_ci 289bf215546Sopenharmony_ci STATIC_ASSERT(sizeof(*slot->status) == 4); 290bf215546Sopenharmony_ci 291bf215546Sopenharmony_ci const VkBufferMemoryBarrier buf_barrier_before = { 292bf215546Sopenharmony_ci .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 293bf215546Sopenharmony_ci .pNext = NULL, 294bf215546Sopenharmony_ci .srcAccessMask = 295bf215546Sopenharmony_ci VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT, 296bf215546Sopenharmony_ci .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, 297bf215546Sopenharmony_ci .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 298bf215546Sopenharmony_ci .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 299bf215546Sopenharmony_ci .buffer = slot->buffer, 300bf215546Sopenharmony_ci .offset = slot->offset, 301bf215546Sopenharmony_ci .size = 4, 302bf215546Sopenharmony_ci }; 303bf215546Sopenharmony_ci vn_CmdPipelineBarrier(cmd_handle, 304bf215546Sopenharmony_ci stage_mask | VK_PIPELINE_STAGE_HOST_BIT | 305bf215546Sopenharmony_ci VK_PIPELINE_STAGE_TRANSFER_BIT, 306bf215546Sopenharmony_ci VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 1, 307bf215546Sopenharmony_ci &buf_barrier_before, 0, NULL); 308bf215546Sopenharmony_ci vn_CmdFillBuffer(cmd_handle, slot->buffer, slot->offset, 4, status); 309bf215546Sopenharmony_ci 310bf215546Sopenharmony_ci const VkBufferMemoryBarrier buf_barrier_after = { 311bf215546Sopenharmony_ci .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 312bf215546Sopenharmony_ci .pNext = NULL, 313bf215546Sopenharmony_ci .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, 314bf215546Sopenharmony_ci .dstAccessMask = VK_ACCESS_HOST_READ_BIT | VK_ACCESS_HOST_WRITE_BIT, 315bf215546Sopenharmony_ci .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 316bf215546Sopenharmony_ci .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 317bf215546Sopenharmony_ci .buffer = slot->buffer, 318bf215546Sopenharmony_ci .offset = slot->offset, 319bf215546Sopenharmony_ci .size = 4, 320bf215546Sopenharmony_ci }; 321bf215546Sopenharmony_ci vn_CmdPipelineBarrier(cmd_handle, VK_PIPELINE_STAGE_TRANSFER_BIT, 322bf215546Sopenharmony_ci VK_PIPELINE_STAGE_HOST_BIT, 0, 0, NULL, 1, 323bf215546Sopenharmony_ci &buf_barrier_after, 0, NULL); 324bf215546Sopenharmony_ci} 325bf215546Sopenharmony_ci 326bf215546Sopenharmony_cistatic VkResult 327bf215546Sopenharmony_civn_feedback_fence_cmd_record(VkCommandBuffer cmd_handle, 328bf215546Sopenharmony_ci struct vn_feedback_slot *slot) 329bf215546Sopenharmony_ci 330bf215546Sopenharmony_ci{ 331bf215546Sopenharmony_ci STATIC_ASSERT(sizeof(*slot->status) == 4); 332bf215546Sopenharmony_ci 333bf215546Sopenharmony_ci static const VkCommandBufferBeginInfo begin_info = { 334bf215546Sopenharmony_ci .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 335bf215546Sopenharmony_ci .pNext = NULL, 336bf215546Sopenharmony_ci .flags = 0, 337bf215546Sopenharmony_ci .pInheritanceInfo = NULL, 338bf215546Sopenharmony_ci }; 339bf215546Sopenharmony_ci VkResult result = vn_BeginCommandBuffer(cmd_handle, &begin_info); 340bf215546Sopenharmony_ci if (result != VK_SUCCESS) 341bf215546Sopenharmony_ci return result; 342bf215546Sopenharmony_ci 343bf215546Sopenharmony_ci static const VkMemoryBarrier mem_barrier_before = { 344bf215546Sopenharmony_ci .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER, 345bf215546Sopenharmony_ci .pNext = NULL, 346bf215546Sopenharmony_ci /* make pending writes available to stay close to fence signal op */ 347bf215546Sopenharmony_ci .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT, 348bf215546Sopenharmony_ci /* no need to make all memory visible for feedback update */ 349bf215546Sopenharmony_ci .dstAccessMask = 0, 350bf215546Sopenharmony_ci }; 351bf215546Sopenharmony_ci const VkBufferMemoryBarrier buf_barrier_before = { 352bf215546Sopenharmony_ci .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 353bf215546Sopenharmony_ci .pNext = NULL, 354bf215546Sopenharmony_ci /* slot memory has been made available via mem_barrier_before */ 355bf215546Sopenharmony_ci .srcAccessMask = 0, 356bf215546Sopenharmony_ci .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, 357bf215546Sopenharmony_ci .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 358bf215546Sopenharmony_ci .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 359bf215546Sopenharmony_ci .buffer = slot->buffer, 360bf215546Sopenharmony_ci .offset = slot->offset, 361bf215546Sopenharmony_ci .size = 4, 362bf215546Sopenharmony_ci }; 363bf215546Sopenharmony_ci vn_CmdPipelineBarrier(cmd_handle, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 364bf215546Sopenharmony_ci VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 1, 365bf215546Sopenharmony_ci &mem_barrier_before, 1, &buf_barrier_before, 0, 366bf215546Sopenharmony_ci NULL); 367bf215546Sopenharmony_ci vn_CmdFillBuffer(cmd_handle, slot->buffer, slot->offset, 4, VK_SUCCESS); 368bf215546Sopenharmony_ci 369bf215546Sopenharmony_ci const VkBufferMemoryBarrier buf_barrier_after = { 370bf215546Sopenharmony_ci .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 371bf215546Sopenharmony_ci .pNext = NULL, 372bf215546Sopenharmony_ci .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, 373bf215546Sopenharmony_ci .dstAccessMask = VK_ACCESS_HOST_READ_BIT | VK_ACCESS_HOST_WRITE_BIT, 374bf215546Sopenharmony_ci .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 375bf215546Sopenharmony_ci .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 376bf215546Sopenharmony_ci .buffer = slot->buffer, 377bf215546Sopenharmony_ci .offset = slot->offset, 378bf215546Sopenharmony_ci .size = 4, 379bf215546Sopenharmony_ci }; 380bf215546Sopenharmony_ci vn_CmdPipelineBarrier(cmd_handle, VK_PIPELINE_STAGE_TRANSFER_BIT, 381bf215546Sopenharmony_ci VK_PIPELINE_STAGE_HOST_BIT, 0, 0, NULL, 1, 382bf215546Sopenharmony_ci &buf_barrier_after, 0, NULL); 383bf215546Sopenharmony_ci 384bf215546Sopenharmony_ci return vn_EndCommandBuffer(cmd_handle); 385bf215546Sopenharmony_ci} 386bf215546Sopenharmony_ci 387bf215546Sopenharmony_ciVkResult 388bf215546Sopenharmony_civn_feedback_fence_cmd_alloc(VkDevice dev_handle, 389bf215546Sopenharmony_ci struct vn_feedback_cmd_pool *pool, 390bf215546Sopenharmony_ci struct vn_feedback_slot *slot, 391bf215546Sopenharmony_ci VkCommandBuffer *out_cmd_handle) 392bf215546Sopenharmony_ci{ 393bf215546Sopenharmony_ci const VkCommandBufferAllocateInfo info = { 394bf215546Sopenharmony_ci .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, 395bf215546Sopenharmony_ci .pNext = NULL, 396bf215546Sopenharmony_ci .commandPool = pool->pool, 397bf215546Sopenharmony_ci .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, 398bf215546Sopenharmony_ci .commandBufferCount = 1, 399bf215546Sopenharmony_ci }; 400bf215546Sopenharmony_ci VkCommandBuffer cmd_handle; 401bf215546Sopenharmony_ci VkResult result; 402bf215546Sopenharmony_ci 403bf215546Sopenharmony_ci simple_mtx_lock(&pool->mutex); 404bf215546Sopenharmony_ci result = vn_AllocateCommandBuffers(dev_handle, &info, &cmd_handle); 405bf215546Sopenharmony_ci if (result != VK_SUCCESS) 406bf215546Sopenharmony_ci goto out_unlock; 407bf215546Sopenharmony_ci 408bf215546Sopenharmony_ci result = vn_feedback_fence_cmd_record(cmd_handle, slot); 409bf215546Sopenharmony_ci if (result != VK_SUCCESS) { 410bf215546Sopenharmony_ci vn_FreeCommandBuffers(dev_handle, pool->pool, 1, &cmd_handle); 411bf215546Sopenharmony_ci goto out_unlock; 412bf215546Sopenharmony_ci } 413bf215546Sopenharmony_ci 414bf215546Sopenharmony_ci *out_cmd_handle = cmd_handle; 415bf215546Sopenharmony_ci 416bf215546Sopenharmony_ciout_unlock: 417bf215546Sopenharmony_ci simple_mtx_unlock(&pool->mutex); 418bf215546Sopenharmony_ci 419bf215546Sopenharmony_ci return result; 420bf215546Sopenharmony_ci} 421bf215546Sopenharmony_ci 422bf215546Sopenharmony_civoid 423bf215546Sopenharmony_civn_feedback_fence_cmd_free(VkDevice dev_handle, 424bf215546Sopenharmony_ci struct vn_feedback_cmd_pool *pool, 425bf215546Sopenharmony_ci VkCommandBuffer cmd_handle) 426bf215546Sopenharmony_ci{ 427bf215546Sopenharmony_ci simple_mtx_lock(&pool->mutex); 428bf215546Sopenharmony_ci vn_FreeCommandBuffers(dev_handle, pool->pool, 1, &cmd_handle); 429bf215546Sopenharmony_ci simple_mtx_unlock(&pool->mutex); 430bf215546Sopenharmony_ci} 431bf215546Sopenharmony_ci 432bf215546Sopenharmony_ciVkResult 433bf215546Sopenharmony_civn_feedback_cmd_pools_init(struct vn_device *dev) 434bf215546Sopenharmony_ci{ 435bf215546Sopenharmony_ci const VkAllocationCallbacks *alloc = &dev->base.base.alloc; 436bf215546Sopenharmony_ci VkDevice dev_handle = vn_device_to_handle(dev); 437bf215546Sopenharmony_ci struct vn_feedback_cmd_pool *pools; 438bf215546Sopenharmony_ci VkCommandPoolCreateInfo info = { 439bf215546Sopenharmony_ci .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, 440bf215546Sopenharmony_ci .pNext = NULL, 441bf215546Sopenharmony_ci .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, 442bf215546Sopenharmony_ci }; 443bf215546Sopenharmony_ci 444bf215546Sopenharmony_ci /* TODO will also condition on timeline semaphore feedback */ 445bf215546Sopenharmony_ci if (VN_PERF(NO_FENCE_FEEDBACK)) 446bf215546Sopenharmony_ci return VK_SUCCESS; 447bf215546Sopenharmony_ci 448bf215546Sopenharmony_ci assert(dev->queue_family_count); 449bf215546Sopenharmony_ci 450bf215546Sopenharmony_ci pools = vk_zalloc(alloc, sizeof(*pools) * dev->queue_family_count, 451bf215546Sopenharmony_ci VN_DEFAULT_ALIGN, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE); 452bf215546Sopenharmony_ci if (!pools) 453bf215546Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 454bf215546Sopenharmony_ci 455bf215546Sopenharmony_ci for (uint32_t i = 0; i < dev->queue_family_count; i++) { 456bf215546Sopenharmony_ci VkResult result; 457bf215546Sopenharmony_ci 458bf215546Sopenharmony_ci info.queueFamilyIndex = dev->queue_families[i]; 459bf215546Sopenharmony_ci result = vn_CreateCommandPool(dev_handle, &info, alloc, &pools[i].pool); 460bf215546Sopenharmony_ci if (result != VK_SUCCESS) { 461bf215546Sopenharmony_ci for (uint32_t j = 0; j < i; j++) { 462bf215546Sopenharmony_ci vn_DestroyCommandPool(dev_handle, pools[j].pool, alloc); 463bf215546Sopenharmony_ci simple_mtx_destroy(&pools[j].mutex); 464bf215546Sopenharmony_ci } 465bf215546Sopenharmony_ci 466bf215546Sopenharmony_ci vk_free(alloc, pools); 467bf215546Sopenharmony_ci return result; 468bf215546Sopenharmony_ci } 469bf215546Sopenharmony_ci 470bf215546Sopenharmony_ci simple_mtx_init(&pools[i].mutex, mtx_plain); 471bf215546Sopenharmony_ci } 472bf215546Sopenharmony_ci 473bf215546Sopenharmony_ci dev->cmd_pools = pools; 474bf215546Sopenharmony_ci 475bf215546Sopenharmony_ci return VK_SUCCESS; 476bf215546Sopenharmony_ci} 477bf215546Sopenharmony_ci 478bf215546Sopenharmony_civoid 479bf215546Sopenharmony_civn_feedback_cmd_pools_fini(struct vn_device *dev) 480bf215546Sopenharmony_ci{ 481bf215546Sopenharmony_ci const VkAllocationCallbacks *alloc = &dev->base.base.alloc; 482bf215546Sopenharmony_ci VkDevice dev_handle = vn_device_to_handle(dev); 483bf215546Sopenharmony_ci 484bf215546Sopenharmony_ci if (!dev->cmd_pools) 485bf215546Sopenharmony_ci return; 486bf215546Sopenharmony_ci 487bf215546Sopenharmony_ci for (uint32_t i = 0; i < dev->queue_family_count; i++) { 488bf215546Sopenharmony_ci vn_DestroyCommandPool(dev_handle, dev->cmd_pools[i].pool, alloc); 489bf215546Sopenharmony_ci simple_mtx_destroy(&dev->cmd_pools[i].mutex); 490bf215546Sopenharmony_ci } 491bf215546Sopenharmony_ci 492bf215546Sopenharmony_ci vk_free(alloc, dev->cmd_pools); 493bf215546Sopenharmony_ci} 494