The open source OpenXR runtime
1// Copyright 2019-2020, 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_main
9 */
10
11#include "main/comp_compositor.h"
12
13#include "render/comp_render.h"
14
15#include <stdio.h>
16
17
18/*
19 *
20 * Common helpers.
21 *
22 */
23
24static VkResult
25create_buffer(struct vk_bundle *vk,
26 VkBufferUsageFlags usage_flags,
27 VkMemoryPropertyFlags memory_property_flags,
28 VkDeviceSize size,
29 VkBuffer *out_buffer,
30 VkDeviceMemory *out_memory,
31 VkDeviceSize *out_alignment,
32 VkDeviceSize *out_allocation_size)
33{
34 VkResult ret;
35
36 // Create the buffer handle.
37 VkBufferCreateInfo buffer_info = {
38 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
39 .size = size,
40 .usage = usage_flags,
41 };
42
43 VkBuffer buffer = VK_NULL_HANDLE;
44 ret = vk->vkCreateBuffer(vk->device, //
45 &buffer_info, //
46 NULL, //
47 &buffer); //
48 if (ret != VK_SUCCESS) {
49 VK_ERROR(vk, "vkCreateBuffer failed: '%s'", vk_result_string(ret));
50 return ret;
51 }
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 vk_get_memory_type(vk, //
62 mem_reqs.memoryTypeBits, //
63 memory_property_flags, //
64 &memory_type_index); //
65
66 VkMemoryAllocateInfo mem_alloc = {
67 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
68 .allocationSize = mem_reqs.size,
69 .memoryTypeIndex = memory_type_index,
70 };
71
72 VkDeviceMemory memory = VK_NULL_HANDLE;
73 ret = vk->vkAllocateMemory(vk->device, //
74 &mem_alloc, //
75 NULL, //
76 &memory); //
77 if (ret != VK_SUCCESS) {
78 VK_ERROR(vk, "vkAllocateMemory failed: '%s'", vk_result_string(ret));
79 goto err_buffer;
80 }
81
82
83 // Attach the memory to the buffer object
84 ret = vk->vkBindBufferMemory(vk->device, //
85 buffer, // buffer
86 memory, // memory
87 0); // memoryOffset
88 if (ret != VK_SUCCESS) {
89 VK_ERROR(vk, "vkBindBufferMemory failed: '%s'", vk_result_string(ret));
90 goto err_memory;
91 }
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 vk->vkFreeMemory(vk->device, memory, NULL);
103
104err_buffer:
105 vk->vkDestroyBuffer(vk->device, buffer, NULL);
106
107 return ret;
108}
109
110
111/*
112 *
113 * 'Exported' functions.
114 *
115 */
116
117VkResult
118comp_buffer_init(struct vk_bundle *vk,
119 struct comp_buffer *buffer,
120 VkBufferUsageFlags usage_flags,
121 VkMemoryPropertyFlags memory_property_flags,
122 VkDeviceSize size)
123{
124 return create_buffer(vk, //
125 usage_flags, // usage_flags
126 memory_property_flags, // memory_property_flags
127 size, // size
128 &buffer->buffer, // out_buffer
129 &buffer->memory, // out_memory
130 &buffer->alignment, // out_alignment
131 &buffer->allocation_size); // out_allocation_size
132}
133
134void
135comp_buffer_close(struct vk_bundle *vk, struct comp_buffer *buffer)
136{
137 if (buffer->buffer != VK_NULL_HANDLE) {
138 vk->vkDestroyBuffer(vk->device, buffer->buffer, NULL);
139 }
140 if (buffer->memory != VK_NULL_HANDLE) {
141 vk->vkFreeMemory(vk->device, buffer->memory, NULL);
142 }
143
144 U_ZERO(buffer);
145}
146
147VkResult
148comp_buffer_map(struct vk_bundle *vk, struct comp_buffer *buffer)
149{
150 return vk->vkMapMemory(vk->device, //
151 buffer->memory, // memory
152 0, // offset
153 VK_WHOLE_SIZE, // size
154 0, // flags
155 &buffer->mapped); // ppData
156}
157
158void
159comp_buffer_unmap(struct vk_bundle *vk, struct comp_buffer *buffer)
160{
161 if (buffer->mapped != NULL) {
162 vk->vkUnmapMemory(vk->device, buffer->memory);
163 buffer->mapped = NULL;
164 }
165}
166
167VkResult
168comp_buffer_map_and_write(struct vk_bundle *vk, struct comp_buffer *buffer, void *data, VkDeviceSize size)
169{
170 VkResult ret;
171
172 if (size > buffer->allocation_size) {
173 VK_ERROR(vk, "Trying to write more the buffer size!");
174 return VK_ERROR_OUT_OF_DEVICE_MEMORY;
175 }
176
177 if (buffer->mapped == NULL) {
178 ret = comp_buffer_map(vk, buffer);
179 if (ret != VK_SUCCESS) {
180 return ret;
181 }
182 }
183
184 memcpy(buffer->mapped, data, size);
185
186 return VK_SUCCESS;
187}
188
189VkResult
190comp_buffer_write(struct vk_bundle *vk, struct comp_buffer *buffer, void *data, VkDeviceSize size)
191{
192 if (size > buffer->allocation_size) {
193 VK_ERROR(vk, "Trying to write more the buffer size!");
194 return VK_ERROR_OUT_OF_DEVICE_MEMORY;
195 }
196
197 bool mapped = buffer->mapped != NULL;
198 if (!mapped) {
199 VkResult ret = comp_buffer_map(vk, buffer);
200 if (ret != VK_SUCCESS) {
201 return ret;
202 }
203 }
204
205 memcpy(buffer->mapped, data, size);
206
207 // Only unmap if we did the mapping.
208 if (!mapped) {
209 comp_buffer_unmap(vk, buffer);
210 }
211
212 return VK_SUCCESS;
213}