The open source OpenXR runtime
at prediction-2 254 lines 7.2 kB view raw
1// Copyright 2019-2023, Collabora, Ltd. 2// SPDX-License-Identifier: BSL-1.0 3/*! 4 * @file 5 * @brief Buffer functions. 6 * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com> 7 * @author Jakob Bornecrantz <jakob@collabora.com> 8 * @ingroup comp_render 9 */ 10 11#include "vk/vk_mini_helpers.h" 12#include "render/render_interface.h" 13 14#include <stdio.h> 15 16 17/* 18 * 19 * Common helpers. 20 * 21 */ 22 23XRT_CHECK_RESULT static VkResult 24create_buffer(struct vk_bundle *vk, 25 VkBufferUsageFlags usage_flags, 26 VkMemoryPropertyFlags memory_property_flags, 27 VkDeviceSize size, 28 const void *pNext_for_create, 29 const void *pNext_for_allocate, 30 VkBuffer *out_buffer, 31 VkDeviceMemory *out_memory, 32 VkDeviceSize *out_alignment, 33 VkDeviceSize *out_allocation_size) 34{ 35 VkResult ret; 36 bool bret; 37 38 // Create the buffer handle. 39 VkBufferCreateInfo buffer_info = { 40 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 41 .pNext = pNext_for_create, 42 .size = size, 43 .usage = usage_flags, 44 }; 45 46 VkBuffer buffer = VK_NULL_HANDLE; 47 ret = vk->vkCreateBuffer(vk->device, // 48 &buffer_info, // 49 NULL, // 50 &buffer); // 51 VK_CHK_AND_RET(ret, "vkCreateBuffer"); 52 53 // Create the memory backing up the buffer handle. 54 VkMemoryRequirements mem_reqs; 55 vk->vkGetBufferMemoryRequirements(vk->device, // 56 buffer, // 57 &mem_reqs); // 58 59 // Find a memory type index that fits the properties of the buffer. 60 uint32_t memory_type_index = 0; 61 bret = vk_get_memory_type( // 62 vk, // 63 mem_reqs.memoryTypeBits, // 64 memory_property_flags, // 65 &memory_type_index); // 66 if (!bret) { 67 VK_ERROR(vk, "vk_get_memory_type failed: 'false'\n\tFailed to find a matching memory type."); 68 ret = VK_ERROR_OUT_OF_DEVICE_MEMORY; 69 goto err_buffer; 70 } 71 72 VkMemoryAllocateInfo mem_alloc = { 73 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, 74 .allocationSize = mem_reqs.size, 75 .memoryTypeIndex = memory_type_index, 76 .pNext = pNext_for_allocate, 77 }; 78 79 VkDeviceMemory memory = VK_NULL_HANDLE; 80 ret = vk->vkAllocateMemory(vk->device, // 81 &mem_alloc, // 82 NULL, // 83 &memory); // 84 VK_CHK_WITH_GOTO(ret, "vkAllocateMemory", err_buffer); 85 86 // Attach the memory to the buffer object 87 ret = vk->vkBindBufferMemory(vk->device, // 88 buffer, // buffer 89 memory, // memory 90 0); // memoryOffset 91 VK_CHK_WITH_GOTO(ret, "vkBindBufferMemory", err_memory); 92 93 *out_memory = memory; 94 *out_buffer = buffer; 95 *out_alignment = mem_reqs.alignment; 96 *out_allocation_size = mem_alloc.allocationSize; 97 98 return VK_SUCCESS; 99 100 101err_memory: 102 DF(Memory, memory); 103 104err_buffer: 105 D(Buffer, buffer); 106 107 return ret; 108} 109 110 111/* 112 * 113 * 'Exported' functions. 114 * 115 */ 116 117VkResult 118render_buffer_init(struct vk_bundle *vk, 119 struct render_buffer *buffer, 120 VkBufferUsageFlags usage_flags, 121 VkMemoryPropertyFlags memory_property_flags, 122 VkDeviceSize size) 123{ 124 VkResult ret; 125 126 ret = create_buffer(vk, // 127 usage_flags, // usage_flags 128 memory_property_flags, // memory_property_flags 129 size, // size 130 NULL, // pNext for create 131 NULL, // pNext_for_allocate 132 &buffer->buffer, // out_buffer 133 &buffer->memory, // out_memory 134 &buffer->alignment, // out_alignment 135 &buffer->allocation_size); // out_allocation_size 136 if (ret == VK_SUCCESS) { 137 buffer->size = size; 138 } 139 140 return ret; 141} 142 143VkResult 144render_buffer_init_exportable(struct vk_bundle *vk, 145 struct render_buffer *buffer, 146 VkBufferUsageFlags usage_flags, 147 VkMemoryPropertyFlags memory_property_flags, 148 VkDeviceSize size) 149{ 150 VkResult ret; 151 152 VkExternalMemoryBufferCreateInfo export_create_info = { 153 .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO, 154 .handleTypes = vk_cb_get_buffer_external_handle_type(vk), 155 }; 156 157 VkExportMemoryAllocateInfo export_alloc_info = { 158 .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR, 159 .pNext = NULL, 160 .handleTypes = vk_cb_get_buffer_external_handle_type(vk), 161 }; 162 163 ret = create_buffer(vk, // 164 usage_flags, // usage_flags 165 memory_property_flags, // memory_property_flags 166 size, // size 167 &export_create_info, // pNext_for_create 168 &export_alloc_info, // pNext_for_allocate 169 &buffer->buffer, // out_buffer 170 &buffer->memory, // out_memory 171 &buffer->alignment, // out_alignment 172 &buffer->allocation_size); // out_allocation_size 173 if (ret == VK_SUCCESS) { 174 buffer->size = size; 175 } 176 177 return ret; 178} 179 180void 181render_buffer_fini(struct vk_bundle *vk, struct render_buffer *buffer) 182{ 183 D(Buffer, buffer->buffer); 184 DF(Memory, buffer->memory); 185 U_ZERO(buffer); 186} 187 188VkResult 189render_buffer_map(struct vk_bundle *vk, struct render_buffer *buffer) 190{ 191 return vk->vkMapMemory(vk->device, // 192 buffer->memory, // memory 193 0, // offset 194 VK_WHOLE_SIZE, // size 195 0, // flags 196 &buffer->mapped); // ppData 197} 198 199void 200render_buffer_unmap(struct vk_bundle *vk, struct render_buffer *buffer) 201{ 202 if (buffer->mapped != NULL) { 203 vk->vkUnmapMemory(vk->device, buffer->memory); 204 buffer->mapped = NULL; 205 } 206} 207 208VkResult 209render_buffer_map_and_write(struct vk_bundle *vk, struct render_buffer *buffer, void *data, VkDeviceSize size) 210{ 211 VkResult ret; 212 213 if (size > buffer->allocation_size) { 214 VK_ERROR(vk, "Trying to write more the buffer size!"); 215 return VK_ERROR_OUT_OF_DEVICE_MEMORY; 216 } 217 218 if (buffer->mapped == NULL) { 219 ret = render_buffer_map(vk, buffer); 220 if (ret != VK_SUCCESS) { 221 return ret; 222 } 223 } 224 225 memcpy(buffer->mapped, data, size); 226 227 return VK_SUCCESS; 228} 229 230VkResult 231render_buffer_write(struct vk_bundle *vk, struct render_buffer *buffer, void *data, VkDeviceSize size) 232{ 233 if (size > buffer->allocation_size) { 234 VK_ERROR(vk, "Trying to write more the buffer size!"); 235 return VK_ERROR_OUT_OF_DEVICE_MEMORY; 236 } 237 238 bool mapped = buffer->mapped != NULL; 239 if (!mapped) { 240 VkResult ret = render_buffer_map(vk, buffer); 241 if (ret != VK_SUCCESS) { 242 return ret; 243 } 244 } 245 246 memcpy(buffer->mapped, data, size); 247 248 // Only unmap if we did the mapping. 249 if (!mapped) { 250 render_buffer_unmap(vk, buffer); 251 } 252 253 return VK_SUCCESS; 254}