vulkan/wsi: Implement prime in a completely generic way
[mesa.git] / src / vulkan / wsi / wsi_common.c
1 /*
2 * Copyright © 2017 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include "wsi_common_private.h"
25 #include "util/macros.h"
26
27 void
28 wsi_device_init(struct wsi_device *wsi,
29 VkPhysicalDevice pdevice,
30 WSI_FN_GetPhysicalDeviceProcAddr proc_addr)
31 {
32 memset(wsi, 0, sizeof(*wsi));
33
34 #define WSI_GET_CB(func) \
35 PFN_vk##func func = (PFN_vk##func)proc_addr(pdevice, "vk" #func)
36 WSI_GET_CB(GetPhysicalDeviceMemoryProperties);
37 WSI_GET_CB(GetPhysicalDeviceQueueFamilyProperties);
38 #undef WSI_GET_CB
39
40 GetPhysicalDeviceMemoryProperties(pdevice, &wsi->memory_props);
41 GetPhysicalDeviceQueueFamilyProperties(pdevice, &wsi->queue_family_count, NULL);
42
43 #define WSI_GET_CB(func) \
44 wsi->func = (PFN_vk##func)proc_addr(pdevice, "vk" #func)
45 WSI_GET_CB(AllocateMemory);
46 WSI_GET_CB(AllocateCommandBuffers);
47 WSI_GET_CB(BindBufferMemory);
48 WSI_GET_CB(BindImageMemory);
49 WSI_GET_CB(BeginCommandBuffer);
50 WSI_GET_CB(CmdCopyImageToBuffer);
51 WSI_GET_CB(CreateBuffer);
52 WSI_GET_CB(CreateCommandPool);
53 WSI_GET_CB(CreateImage);
54 WSI_GET_CB(DestroyBuffer);
55 WSI_GET_CB(DestroyCommandPool);
56 WSI_GET_CB(DestroyImage);
57 WSI_GET_CB(EndCommandBuffer);
58 WSI_GET_CB(FreeMemory);
59 WSI_GET_CB(FreeCommandBuffers);
60 WSI_GET_CB(GetBufferMemoryRequirements);
61 WSI_GET_CB(GetImageMemoryRequirements);
62 WSI_GET_CB(GetMemoryFdKHR);
63 WSI_GET_CB(QueueSubmit);
64 #undef WSI_GET_CB
65 }
66
67 VkResult
68 wsi_swapchain_init(const struct wsi_device *wsi,
69 struct wsi_swapchain *chain,
70 VkDevice device,
71 const VkSwapchainCreateInfoKHR *pCreateInfo,
72 const VkAllocationCallbacks *pAllocator)
73 {
74 VkResult result;
75
76 memset(chain, 0, sizeof(*chain));
77
78 chain->wsi = wsi;
79 chain->device = device;
80 chain->alloc = *pAllocator;
81
82 chain->cmd_pools =
83 vk_zalloc(pAllocator, sizeof(VkCommandPool) * wsi->queue_family_count, 8,
84 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
85 if (!chain->cmd_pools)
86 return VK_ERROR_OUT_OF_HOST_MEMORY;
87
88 for (uint32_t i = 0; i < wsi->queue_family_count; i++) {
89 const VkCommandPoolCreateInfo cmd_pool_info = {
90 .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
91 .pNext = NULL,
92 .flags = 0,
93 .queueFamilyIndex = i,
94 };
95 result = wsi->CreateCommandPool(device, &cmd_pool_info, &chain->alloc,
96 &chain->cmd_pools[i]);
97 if (result != VK_SUCCESS)
98 goto fail;
99 }
100
101 return VK_SUCCESS;
102
103 fail:
104 wsi_swapchain_finish(chain);
105 return result;
106 }
107
108 void
109 wsi_swapchain_finish(struct wsi_swapchain *chain)
110 {
111 for (uint32_t i = 0; i < chain->wsi->queue_family_count; i++) {
112 chain->wsi->DestroyCommandPool(chain->device, chain->cmd_pools[i],
113 &chain->alloc);
114 }
115 }
116
117 static uint32_t
118 select_memory_type(const struct wsi_device *wsi,
119 VkMemoryPropertyFlags props,
120 uint32_t type_bits)
121 {
122 for (uint32_t i = 0; i < wsi->memory_props.memoryTypeCount; i++) {
123 const VkMemoryType type = wsi->memory_props.memoryTypes[i];
124 if ((type_bits & (1 << i)) && (type.propertyFlags & props) == props)
125 return i;
126 }
127
128 unreachable("No memory type found");
129 }
130
131 static uint32_t
132 vk_format_size(VkFormat format)
133 {
134 switch (format) {
135 case VK_FORMAT_B8G8R8A8_UNORM:
136 case VK_FORMAT_B8G8R8A8_SRGB:
137 return 4;
138 default:
139 unreachable("Unknown WSI Format");
140 }
141 }
142
143 static inline uint32_t
144 align_u32(uint32_t v, uint32_t a)
145 {
146 assert(a != 0 && a == (a & -a));
147 return (v + a - 1) & ~(a - 1);
148 }
149
150 #define WSI_PRIME_LINEAR_STRIDE_ALIGN 256
151
152 VkResult
153 wsi_create_prime_image(const struct wsi_swapchain *chain,
154 const VkSwapchainCreateInfoKHR *pCreateInfo,
155 struct wsi_image *image)
156 {
157 const struct wsi_device *wsi = chain->wsi;
158 VkResult result;
159
160 memset(image, 0, sizeof(*image));
161
162 const uint32_t cpp = vk_format_size(pCreateInfo->imageFormat);
163 const uint32_t linear_stride = align_u32(pCreateInfo->imageExtent.width * cpp,
164 WSI_PRIME_LINEAR_STRIDE_ALIGN);
165
166 uint32_t linear_size = linear_stride * pCreateInfo->imageExtent.height;
167 linear_size = align_u32(linear_size, 4096);
168
169 const VkExternalMemoryBufferCreateInfoKHR prime_buffer_external_info = {
170 .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR,
171 .pNext = NULL,
172 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
173 };
174 const VkBufferCreateInfo prime_buffer_info = {
175 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
176 .pNext = &prime_buffer_external_info,
177 .size = linear_size,
178 .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT,
179 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
180 };
181 result = wsi->CreateBuffer(chain->device, &prime_buffer_info,
182 &chain->alloc, &image->prime.buffer);
183 if (result != VK_SUCCESS)
184 goto fail;
185
186 VkMemoryRequirements reqs;
187 wsi->GetBufferMemoryRequirements(chain->device, image->prime.buffer, &reqs);
188 assert(reqs.size <= linear_size);
189
190 const struct wsi_memory_allocate_info memory_wsi_info = {
191 .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA,
192 .pNext = NULL,
193 .implicit_sync = true,
194 };
195 const VkExportMemoryAllocateInfoKHR prime_memory_export_info = {
196 .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR,
197 .pNext = &memory_wsi_info,
198 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
199 };
200 const VkMemoryDedicatedAllocateInfoKHR prime_memory_dedicated_info = {
201 .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,
202 .pNext = &prime_memory_export_info,
203 .image = VK_NULL_HANDLE,
204 .buffer = image->prime.buffer,
205 };
206 const VkMemoryAllocateInfo prime_memory_info = {
207 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
208 .pNext = &prime_memory_dedicated_info,
209 .allocationSize = linear_size,
210 .memoryTypeIndex = select_memory_type(wsi, 0, reqs.memoryTypeBits),
211 };
212 result = wsi->AllocateMemory(chain->device, &prime_memory_info,
213 &chain->alloc, &image->prime.memory);
214 if (result != VK_SUCCESS)
215 goto fail;
216
217 result = wsi->BindBufferMemory(chain->device, image->prime.buffer,
218 image->prime.memory, 0);
219 if (result != VK_SUCCESS)
220 goto fail;
221
222 const VkImageCreateInfo image_info = {
223 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
224 .pNext = NULL,
225 .flags = 0,
226 .imageType = VK_IMAGE_TYPE_2D,
227 .format = pCreateInfo->imageFormat,
228 .extent = {
229 .width = pCreateInfo->imageExtent.width,
230 .height = pCreateInfo->imageExtent.height,
231 .depth = 1,
232 },
233 .mipLevels = 1,
234 .arrayLayers = 1,
235 .samples = VK_SAMPLE_COUNT_1_BIT,
236 .tiling = VK_IMAGE_TILING_OPTIMAL,
237 .usage = pCreateInfo->imageUsage | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
238 .sharingMode = pCreateInfo->imageSharingMode,
239 .queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount,
240 .pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices,
241 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
242 };
243 result = wsi->CreateImage(chain->device, &image_info,
244 &chain->alloc, &image->image);
245 if (result != VK_SUCCESS)
246 goto fail;
247
248 wsi->GetImageMemoryRequirements(chain->device, image->image, &reqs);
249
250 const VkMemoryDedicatedAllocateInfoKHR memory_dedicated_info = {
251 .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,
252 .pNext = NULL,
253 .image = image->image,
254 .buffer = VK_NULL_HANDLE,
255 };
256 const VkMemoryAllocateInfo memory_info = {
257 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
258 .pNext = &memory_dedicated_info,
259 .allocationSize = reqs.size,
260 .memoryTypeIndex = select_memory_type(wsi, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
261 reqs.memoryTypeBits),
262 };
263 result = wsi->AllocateMemory(chain->device, &memory_info,
264 &chain->alloc, &image->memory);
265 if (result != VK_SUCCESS)
266 goto fail;
267
268 result = wsi->BindImageMemory(chain->device, image->image,
269 image->memory, 0);
270 if (result != VK_SUCCESS)
271 goto fail;
272
273 image->prime.blit_cmd_buffers =
274 vk_zalloc(&chain->alloc,
275 sizeof(VkCommandBuffer) * wsi->queue_family_count, 8,
276 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
277 if (!image->prime.blit_cmd_buffers)
278 goto fail;
279
280 for (uint32_t i = 0; i < wsi->queue_family_count; i++) {
281 const VkCommandBufferAllocateInfo cmd_buffer_info = {
282 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
283 .pNext = NULL,
284 .commandPool = chain->cmd_pools[i],
285 .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
286 .commandBufferCount = 1,
287 };
288 result = wsi->AllocateCommandBuffers(chain->device, &cmd_buffer_info,
289 &image->prime.blit_cmd_buffers[i]);
290 if (result != VK_SUCCESS)
291 goto fail;
292
293 const VkCommandBufferBeginInfo begin_info = {
294 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
295 };
296 wsi->BeginCommandBuffer(image->prime.blit_cmd_buffers[i], &begin_info);
297
298 struct VkBufferImageCopy buffer_image_copy = {
299 .bufferOffset = 0,
300 .bufferRowLength = linear_stride / cpp,
301 .bufferImageHeight = 0,
302 .imageSubresource = {
303 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
304 .mipLevel = 0,
305 .baseArrayLayer = 0,
306 .layerCount = 1,
307 },
308 .imageOffset = { .x = 0, .y = 0, .z = 0 },
309 .imageExtent = {
310 .width = pCreateInfo->imageExtent.width,
311 .height = pCreateInfo->imageExtent.height,
312 .depth = 1,
313 },
314 };
315 wsi->CmdCopyImageToBuffer(image->prime.blit_cmd_buffers[i],
316 image->image,
317 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
318 image->prime.buffer,
319 1, &buffer_image_copy);
320
321 result = wsi->EndCommandBuffer(image->prime.blit_cmd_buffers[i]);
322 if (result != VK_SUCCESS)
323 goto fail;
324 }
325
326 const VkMemoryGetFdInfoKHR linear_memory_get_fd_info = {
327 .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
328 .pNext = NULL,
329 .memory = image->prime.memory,
330 .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
331 };
332 int fd;
333 result = wsi->GetMemoryFdKHR(chain->device, &linear_memory_get_fd_info, &fd);
334 if (result != VK_SUCCESS)
335 goto fail;
336
337 image->size = linear_size;
338 image->row_pitch = linear_stride;
339 image->offset = 0;
340 image->fd = fd;
341
342 return VK_SUCCESS;
343
344 fail:
345 wsi_destroy_prime_image(chain, image);
346
347 return result;
348 }
349
350 void
351 wsi_destroy_prime_image(const struct wsi_swapchain *chain,
352 struct wsi_image *image)
353 {
354 const struct wsi_device *wsi = chain->wsi;
355
356 if (image->prime.blit_cmd_buffers) {
357 for (uint32_t i = 0; i < wsi->queue_family_count; i++) {
358 wsi->FreeCommandBuffers(chain->device, chain->cmd_pools[i],
359 1, &image->prime.blit_cmd_buffers[i]);
360 }
361 vk_free(&chain->alloc, image->prime.blit_cmd_buffers);
362 }
363
364 wsi->FreeMemory(chain->device, image->memory, &chain->alloc);
365 wsi->DestroyImage(chain->device, image->image, &chain->alloc);
366 wsi->FreeMemory(chain->device, image->prime.memory, &chain->alloc);
367 wsi->DestroyBuffer(chain->device, image->prime.buffer, &chain->alloc);
368 }
369
370 VkResult
371 wsi_prime_image_blit_to_linear(const struct wsi_swapchain *chain,
372 struct wsi_image *image,
373 VkQueue queue,
374 uint32_t waitSemaphoreCount,
375 const VkSemaphore *pWaitSemaphores)
376 {
377 uint32_t queue_family = chain->wsi->queue_get_family_index(queue);
378
379 VkPipelineStageFlags stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
380 const VkSubmitInfo submit_info = {
381 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
382 .pNext = NULL,
383 .waitSemaphoreCount = waitSemaphoreCount,
384 .pWaitSemaphores = pWaitSemaphores,
385 .pWaitDstStageMask = &stage_flags,
386 .commandBufferCount = 1,
387 .pCommandBuffers = &image->prime.blit_cmd_buffers[queue_family],
388 .signalSemaphoreCount = 0,
389 .pSignalSemaphores = NULL,
390 };
391 return chain->wsi->QueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE);
392 }