b86bb90cec695e07aa0315214dbd9ed517fb0284
[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(GetImageSubresourceLayout);
63 WSI_GET_CB(GetMemoryFdKHR);
64 WSI_GET_CB(QueueSubmit);
65 #undef WSI_GET_CB
66 }
67
68 VkResult
69 wsi_swapchain_init(const struct wsi_device *wsi,
70 struct wsi_swapchain *chain,
71 VkDevice device,
72 const VkSwapchainCreateInfoKHR *pCreateInfo,
73 const VkAllocationCallbacks *pAllocator)
74 {
75 VkResult result;
76
77 memset(chain, 0, sizeof(*chain));
78
79 chain->wsi = wsi;
80 chain->device = device;
81 chain->alloc = *pAllocator;
82
83 chain->cmd_pools =
84 vk_zalloc(pAllocator, sizeof(VkCommandPool) * wsi->queue_family_count, 8,
85 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
86 if (!chain->cmd_pools)
87 return VK_ERROR_OUT_OF_HOST_MEMORY;
88
89 for (uint32_t i = 0; i < wsi->queue_family_count; i++) {
90 const VkCommandPoolCreateInfo cmd_pool_info = {
91 .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
92 .pNext = NULL,
93 .flags = 0,
94 .queueFamilyIndex = i,
95 };
96 result = wsi->CreateCommandPool(device, &cmd_pool_info, &chain->alloc,
97 &chain->cmd_pools[i]);
98 if (result != VK_SUCCESS)
99 goto fail;
100 }
101
102 return VK_SUCCESS;
103
104 fail:
105 wsi_swapchain_finish(chain);
106 return result;
107 }
108
109 void
110 wsi_swapchain_finish(struct wsi_swapchain *chain)
111 {
112 for (uint32_t i = 0; i < chain->wsi->queue_family_count; i++) {
113 chain->wsi->DestroyCommandPool(chain->device, chain->cmd_pools[i],
114 &chain->alloc);
115 }
116 }
117
118 static uint32_t
119 select_memory_type(const struct wsi_device *wsi,
120 VkMemoryPropertyFlags props,
121 uint32_t type_bits)
122 {
123 for (uint32_t i = 0; i < wsi->memory_props.memoryTypeCount; i++) {
124 const VkMemoryType type = wsi->memory_props.memoryTypes[i];
125 if ((type_bits & (1 << i)) && (type.propertyFlags & props) == props)
126 return i;
127 }
128
129 unreachable("No memory type found");
130 }
131
132 static uint32_t
133 vk_format_size(VkFormat format)
134 {
135 switch (format) {
136 case VK_FORMAT_B8G8R8A8_UNORM:
137 case VK_FORMAT_B8G8R8A8_SRGB:
138 return 4;
139 default:
140 unreachable("Unknown WSI Format");
141 }
142 }
143
144 static inline uint32_t
145 align_u32(uint32_t v, uint32_t a)
146 {
147 assert(a != 0 && a == (a & -a));
148 return (v + a - 1) & ~(a - 1);
149 }
150
151 VkResult
152 wsi_create_native_image(const struct wsi_swapchain *chain,
153 const VkSwapchainCreateInfoKHR *pCreateInfo,
154 struct wsi_image *image)
155 {
156 const struct wsi_device *wsi = chain->wsi;
157 VkResult result;
158
159 memset(image, 0, sizeof(*image));
160
161 const struct wsi_image_create_info image_wsi_info = {
162 .sType = VK_STRUCTURE_TYPE_WSI_IMAGE_CREATE_INFO_MESA,
163 .pNext = NULL,
164 .scanout = true,
165 };
166 const VkImageCreateInfo image_info = {
167 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
168 .pNext = &image_wsi_info,
169 .flags = 0,
170 .imageType = VK_IMAGE_TYPE_2D,
171 .format = pCreateInfo->imageFormat,
172 .extent = {
173 .width = pCreateInfo->imageExtent.width,
174 .height = pCreateInfo->imageExtent.height,
175 .depth = 1,
176 },
177 .mipLevels = 1,
178 .arrayLayers = 1,
179 .samples = VK_SAMPLE_COUNT_1_BIT,
180 .tiling = VK_IMAGE_TILING_OPTIMAL,
181 .usage = pCreateInfo->imageUsage,
182 .sharingMode = pCreateInfo->imageSharingMode,
183 .queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount,
184 .pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices,
185 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
186 };
187 result = wsi->CreateImage(chain->device, &image_info,
188 &chain->alloc, &image->image);
189 if (result != VK_SUCCESS)
190 goto fail;
191
192 VkMemoryRequirements reqs;
193 wsi->GetImageMemoryRequirements(chain->device, image->image, &reqs);
194
195 VkSubresourceLayout image_layout;
196 const VkImageSubresource image_subresource = {
197 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
198 .mipLevel = 0,
199 .arrayLayer = 0,
200 };
201 wsi->GetImageSubresourceLayout(chain->device, image->image,
202 &image_subresource, &image_layout);
203
204 const struct wsi_memory_allocate_info memory_wsi_info = {
205 .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA,
206 .pNext = NULL,
207 .implicit_sync = true,
208 };
209 const VkExportMemoryAllocateInfoKHR memory_export_info = {
210 .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR,
211 .pNext = &memory_wsi_info,
212 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
213 };
214 const VkMemoryDedicatedAllocateInfoKHR memory_dedicated_info = {
215 .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,
216 .pNext = &memory_export_info,
217 .image = image->image,
218 .buffer = VK_NULL_HANDLE,
219 };
220 const VkMemoryAllocateInfo memory_info = {
221 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
222 .pNext = &memory_dedicated_info,
223 .allocationSize = reqs.size,
224 .memoryTypeIndex = select_memory_type(wsi, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
225 reqs.memoryTypeBits),
226 };
227 result = wsi->AllocateMemory(chain->device, &memory_info,
228 &chain->alloc, &image->memory);
229 if (result != VK_SUCCESS)
230 goto fail;
231
232 result = wsi->BindImageMemory(chain->device, image->image,
233 image->memory, 0);
234 if (result != VK_SUCCESS)
235 goto fail;
236
237 const VkMemoryGetFdInfoKHR memory_get_fd_info = {
238 .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
239 .pNext = NULL,
240 .memory = image->memory,
241 .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
242 };
243 int fd;
244 result = wsi->GetMemoryFdKHR(chain->device, &memory_get_fd_info, &fd);
245 if (result != VK_SUCCESS)
246 goto fail;
247
248 image->size = reqs.size;
249 image->row_pitch = image_layout.rowPitch;
250 image->offset = 0;
251 image->fd = fd;
252
253 return VK_SUCCESS;
254
255 fail:
256 wsi_destroy_image(chain, image);
257
258 return result;
259 }
260
261 #define WSI_PRIME_LINEAR_STRIDE_ALIGN 256
262
263 VkResult
264 wsi_create_prime_image(const struct wsi_swapchain *chain,
265 const VkSwapchainCreateInfoKHR *pCreateInfo,
266 struct wsi_image *image)
267 {
268 const struct wsi_device *wsi = chain->wsi;
269 VkResult result;
270
271 memset(image, 0, sizeof(*image));
272
273 const uint32_t cpp = vk_format_size(pCreateInfo->imageFormat);
274 const uint32_t linear_stride = align_u32(pCreateInfo->imageExtent.width * cpp,
275 WSI_PRIME_LINEAR_STRIDE_ALIGN);
276
277 uint32_t linear_size = linear_stride * pCreateInfo->imageExtent.height;
278 linear_size = align_u32(linear_size, 4096);
279
280 const VkExternalMemoryBufferCreateInfoKHR prime_buffer_external_info = {
281 .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR,
282 .pNext = NULL,
283 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
284 };
285 const VkBufferCreateInfo prime_buffer_info = {
286 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
287 .pNext = &prime_buffer_external_info,
288 .size = linear_size,
289 .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT,
290 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
291 };
292 result = wsi->CreateBuffer(chain->device, &prime_buffer_info,
293 &chain->alloc, &image->prime.buffer);
294 if (result != VK_SUCCESS)
295 goto fail;
296
297 VkMemoryRequirements reqs;
298 wsi->GetBufferMemoryRequirements(chain->device, image->prime.buffer, &reqs);
299 assert(reqs.size <= linear_size);
300
301 const struct wsi_memory_allocate_info memory_wsi_info = {
302 .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA,
303 .pNext = NULL,
304 .implicit_sync = true,
305 };
306 const VkExportMemoryAllocateInfoKHR prime_memory_export_info = {
307 .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR,
308 .pNext = &memory_wsi_info,
309 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
310 };
311 const VkMemoryDedicatedAllocateInfoKHR prime_memory_dedicated_info = {
312 .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,
313 .pNext = &prime_memory_export_info,
314 .image = VK_NULL_HANDLE,
315 .buffer = image->prime.buffer,
316 };
317 const VkMemoryAllocateInfo prime_memory_info = {
318 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
319 .pNext = &prime_memory_dedicated_info,
320 .allocationSize = linear_size,
321 .memoryTypeIndex = select_memory_type(wsi, 0, reqs.memoryTypeBits),
322 };
323 result = wsi->AllocateMemory(chain->device, &prime_memory_info,
324 &chain->alloc, &image->prime.memory);
325 if (result != VK_SUCCESS)
326 goto fail;
327
328 result = wsi->BindBufferMemory(chain->device, image->prime.buffer,
329 image->prime.memory, 0);
330 if (result != VK_SUCCESS)
331 goto fail;
332
333 const VkImageCreateInfo image_info = {
334 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
335 .pNext = NULL,
336 .flags = 0,
337 .imageType = VK_IMAGE_TYPE_2D,
338 .format = pCreateInfo->imageFormat,
339 .extent = {
340 .width = pCreateInfo->imageExtent.width,
341 .height = pCreateInfo->imageExtent.height,
342 .depth = 1,
343 },
344 .mipLevels = 1,
345 .arrayLayers = 1,
346 .samples = VK_SAMPLE_COUNT_1_BIT,
347 .tiling = VK_IMAGE_TILING_OPTIMAL,
348 .usage = pCreateInfo->imageUsage | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
349 .sharingMode = pCreateInfo->imageSharingMode,
350 .queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount,
351 .pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices,
352 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
353 };
354 result = wsi->CreateImage(chain->device, &image_info,
355 &chain->alloc, &image->image);
356 if (result != VK_SUCCESS)
357 goto fail;
358
359 wsi->GetImageMemoryRequirements(chain->device, image->image, &reqs);
360
361 const VkMemoryDedicatedAllocateInfoKHR memory_dedicated_info = {
362 .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,
363 .pNext = NULL,
364 .image = image->image,
365 .buffer = VK_NULL_HANDLE,
366 };
367 const VkMemoryAllocateInfo memory_info = {
368 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
369 .pNext = &memory_dedicated_info,
370 .allocationSize = reqs.size,
371 .memoryTypeIndex = select_memory_type(wsi, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
372 reqs.memoryTypeBits),
373 };
374 result = wsi->AllocateMemory(chain->device, &memory_info,
375 &chain->alloc, &image->memory);
376 if (result != VK_SUCCESS)
377 goto fail;
378
379 result = wsi->BindImageMemory(chain->device, image->image,
380 image->memory, 0);
381 if (result != VK_SUCCESS)
382 goto fail;
383
384 image->prime.blit_cmd_buffers =
385 vk_zalloc(&chain->alloc,
386 sizeof(VkCommandBuffer) * wsi->queue_family_count, 8,
387 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
388 if (!image->prime.blit_cmd_buffers)
389 goto fail;
390
391 for (uint32_t i = 0; i < wsi->queue_family_count; i++) {
392 const VkCommandBufferAllocateInfo cmd_buffer_info = {
393 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
394 .pNext = NULL,
395 .commandPool = chain->cmd_pools[i],
396 .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
397 .commandBufferCount = 1,
398 };
399 result = wsi->AllocateCommandBuffers(chain->device, &cmd_buffer_info,
400 &image->prime.blit_cmd_buffers[i]);
401 if (result != VK_SUCCESS)
402 goto fail;
403
404 const VkCommandBufferBeginInfo begin_info = {
405 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
406 };
407 wsi->BeginCommandBuffer(image->prime.blit_cmd_buffers[i], &begin_info);
408
409 struct VkBufferImageCopy buffer_image_copy = {
410 .bufferOffset = 0,
411 .bufferRowLength = linear_stride / cpp,
412 .bufferImageHeight = 0,
413 .imageSubresource = {
414 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
415 .mipLevel = 0,
416 .baseArrayLayer = 0,
417 .layerCount = 1,
418 },
419 .imageOffset = { .x = 0, .y = 0, .z = 0 },
420 .imageExtent = {
421 .width = pCreateInfo->imageExtent.width,
422 .height = pCreateInfo->imageExtent.height,
423 .depth = 1,
424 },
425 };
426 wsi->CmdCopyImageToBuffer(image->prime.blit_cmd_buffers[i],
427 image->image,
428 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
429 image->prime.buffer,
430 1, &buffer_image_copy);
431
432 result = wsi->EndCommandBuffer(image->prime.blit_cmd_buffers[i]);
433 if (result != VK_SUCCESS)
434 goto fail;
435 }
436
437 const VkMemoryGetFdInfoKHR linear_memory_get_fd_info = {
438 .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
439 .pNext = NULL,
440 .memory = image->prime.memory,
441 .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
442 };
443 int fd;
444 result = wsi->GetMemoryFdKHR(chain->device, &linear_memory_get_fd_info, &fd);
445 if (result != VK_SUCCESS)
446 goto fail;
447
448 image->size = linear_size;
449 image->row_pitch = linear_stride;
450 image->offset = 0;
451 image->fd = fd;
452
453 return VK_SUCCESS;
454
455 fail:
456 wsi_destroy_image(chain, image);
457
458 return result;
459 }
460
461 void
462 wsi_destroy_image(const struct wsi_swapchain *chain,
463 struct wsi_image *image)
464 {
465 const struct wsi_device *wsi = chain->wsi;
466
467 if (image->prime.blit_cmd_buffers) {
468 for (uint32_t i = 0; i < wsi->queue_family_count; i++) {
469 wsi->FreeCommandBuffers(chain->device, chain->cmd_pools[i],
470 1, &image->prime.blit_cmd_buffers[i]);
471 }
472 vk_free(&chain->alloc, image->prime.blit_cmd_buffers);
473 }
474
475 wsi->FreeMemory(chain->device, image->memory, &chain->alloc);
476 wsi->DestroyImage(chain->device, image->image, &chain->alloc);
477 wsi->FreeMemory(chain->device, image->prime.memory, &chain->alloc);
478 wsi->DestroyBuffer(chain->device, image->prime.buffer, &chain->alloc);
479 }
480
481 VkResult
482 wsi_prime_image_blit_to_linear(const struct wsi_swapchain *chain,
483 struct wsi_image *image,
484 VkQueue queue,
485 uint32_t waitSemaphoreCount,
486 const VkSemaphore *pWaitSemaphores)
487 {
488 uint32_t queue_family = chain->wsi->queue_get_family_index(queue);
489
490 VkPipelineStageFlags stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
491 const VkSubmitInfo submit_info = {
492 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
493 .pNext = NULL,
494 .waitSemaphoreCount = waitSemaphoreCount,
495 .pWaitSemaphores = pWaitSemaphores,
496 .pWaitDstStageMask = &stage_flags,
497 .commandBufferCount = 1,
498 .pCommandBuffers = &image->prime.blit_cmd_buffers[queue_family],
499 .signalSemaphoreCount = 0,
500 .pSignalSemaphores = NULL,
501 };
502 return chain->wsi->QueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE);
503 }