e5a9a28d34732eaa2c5b507b9856c8c3e99e336e
[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 #include "vk_util.h"
27
28 void
29 wsi_device_init(struct wsi_device *wsi,
30 VkPhysicalDevice pdevice,
31 WSI_FN_GetPhysicalDeviceProcAddr proc_addr)
32 {
33 memset(wsi, 0, sizeof(*wsi));
34
35 #define WSI_GET_CB(func) \
36 PFN_vk##func func = (PFN_vk##func)proc_addr(pdevice, "vk" #func)
37 WSI_GET_CB(GetPhysicalDeviceMemoryProperties);
38 WSI_GET_CB(GetPhysicalDeviceQueueFamilyProperties);
39 #undef WSI_GET_CB
40
41 GetPhysicalDeviceMemoryProperties(pdevice, &wsi->memory_props);
42 GetPhysicalDeviceQueueFamilyProperties(pdevice, &wsi->queue_family_count, NULL);
43
44 #define WSI_GET_CB(func) \
45 wsi->func = (PFN_vk##func)proc_addr(pdevice, "vk" #func)
46 WSI_GET_CB(AllocateMemory);
47 WSI_GET_CB(AllocateCommandBuffers);
48 WSI_GET_CB(BindBufferMemory);
49 WSI_GET_CB(BindImageMemory);
50 WSI_GET_CB(BeginCommandBuffer);
51 WSI_GET_CB(CmdCopyImageToBuffer);
52 WSI_GET_CB(CreateBuffer);
53 WSI_GET_CB(CreateCommandPool);
54 WSI_GET_CB(CreateFence);
55 WSI_GET_CB(CreateImage);
56 WSI_GET_CB(DestroyBuffer);
57 WSI_GET_CB(DestroyCommandPool);
58 WSI_GET_CB(DestroyFence);
59 WSI_GET_CB(DestroyImage);
60 WSI_GET_CB(EndCommandBuffer);
61 WSI_GET_CB(FreeMemory);
62 WSI_GET_CB(FreeCommandBuffers);
63 WSI_GET_CB(GetBufferMemoryRequirements);
64 WSI_GET_CB(GetImageMemoryRequirements);
65 WSI_GET_CB(GetImageSubresourceLayout);
66 WSI_GET_CB(GetMemoryFdKHR);
67 WSI_GET_CB(ResetFences);
68 WSI_GET_CB(QueueSubmit);
69 WSI_GET_CB(WaitForFences);
70 #undef WSI_GET_CB
71 }
72
73 VkResult
74 wsi_swapchain_init(const struct wsi_device *wsi,
75 struct wsi_swapchain *chain,
76 VkDevice device,
77 const VkSwapchainCreateInfoKHR *pCreateInfo,
78 const VkAllocationCallbacks *pAllocator)
79 {
80 VkResult result;
81
82 memset(chain, 0, sizeof(*chain));
83
84 chain->wsi = wsi;
85 chain->device = device;
86 chain->alloc = *pAllocator;
87
88 chain->cmd_pools =
89 vk_zalloc(pAllocator, sizeof(VkCommandPool) * wsi->queue_family_count, 8,
90 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
91 if (!chain->cmd_pools)
92 return VK_ERROR_OUT_OF_HOST_MEMORY;
93
94 for (uint32_t i = 0; i < wsi->queue_family_count; i++) {
95 const VkCommandPoolCreateInfo cmd_pool_info = {
96 .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
97 .pNext = NULL,
98 .flags = 0,
99 .queueFamilyIndex = i,
100 };
101 result = wsi->CreateCommandPool(device, &cmd_pool_info, &chain->alloc,
102 &chain->cmd_pools[i]);
103 if (result != VK_SUCCESS)
104 goto fail;
105 }
106
107 return VK_SUCCESS;
108
109 fail:
110 wsi_swapchain_finish(chain);
111 return result;
112 }
113
114 void
115 wsi_swapchain_finish(struct wsi_swapchain *chain)
116 {
117 for (uint32_t i = 0; i < chain->wsi->queue_family_count; i++) {
118 chain->wsi->DestroyCommandPool(chain->device, chain->cmd_pools[i],
119 &chain->alloc);
120 }
121 }
122
123 static uint32_t
124 select_memory_type(const struct wsi_device *wsi,
125 VkMemoryPropertyFlags props,
126 uint32_t type_bits)
127 {
128 for (uint32_t i = 0; i < wsi->memory_props.memoryTypeCount; i++) {
129 const VkMemoryType type = wsi->memory_props.memoryTypes[i];
130 if ((type_bits & (1 << i)) && (type.propertyFlags & props) == props)
131 return i;
132 }
133
134 unreachable("No memory type found");
135 }
136
137 static uint32_t
138 vk_format_size(VkFormat format)
139 {
140 switch (format) {
141 case VK_FORMAT_B8G8R8A8_UNORM:
142 case VK_FORMAT_B8G8R8A8_SRGB:
143 return 4;
144 default:
145 unreachable("Unknown WSI Format");
146 }
147 }
148
149 static inline uint32_t
150 align_u32(uint32_t v, uint32_t a)
151 {
152 assert(a != 0 && a == (a & -a));
153 return (v + a - 1) & ~(a - 1);
154 }
155
156 VkResult
157 wsi_create_native_image(const struct wsi_swapchain *chain,
158 const VkSwapchainCreateInfoKHR *pCreateInfo,
159 struct wsi_image *image)
160 {
161 const struct wsi_device *wsi = chain->wsi;
162 VkResult result;
163
164 memset(image, 0, sizeof(*image));
165
166 const struct wsi_image_create_info image_wsi_info = {
167 .sType = VK_STRUCTURE_TYPE_WSI_IMAGE_CREATE_INFO_MESA,
168 .pNext = NULL,
169 .scanout = true,
170 };
171 const VkImageCreateInfo image_info = {
172 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
173 .pNext = &image_wsi_info,
174 .flags = 0,
175 .imageType = VK_IMAGE_TYPE_2D,
176 .format = pCreateInfo->imageFormat,
177 .extent = {
178 .width = pCreateInfo->imageExtent.width,
179 .height = pCreateInfo->imageExtent.height,
180 .depth = 1,
181 },
182 .mipLevels = 1,
183 .arrayLayers = 1,
184 .samples = VK_SAMPLE_COUNT_1_BIT,
185 .tiling = VK_IMAGE_TILING_OPTIMAL,
186 .usage = pCreateInfo->imageUsage,
187 .sharingMode = pCreateInfo->imageSharingMode,
188 .queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount,
189 .pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices,
190 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
191 };
192 result = wsi->CreateImage(chain->device, &image_info,
193 &chain->alloc, &image->image);
194 if (result != VK_SUCCESS)
195 goto fail;
196
197 VkMemoryRequirements reqs;
198 wsi->GetImageMemoryRequirements(chain->device, image->image, &reqs);
199
200 VkSubresourceLayout image_layout;
201 const VkImageSubresource image_subresource = {
202 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
203 .mipLevel = 0,
204 .arrayLayer = 0,
205 };
206 wsi->GetImageSubresourceLayout(chain->device, image->image,
207 &image_subresource, &image_layout);
208
209 const struct wsi_memory_allocate_info memory_wsi_info = {
210 .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA,
211 .pNext = NULL,
212 .implicit_sync = true,
213 };
214 const VkExportMemoryAllocateInfoKHR memory_export_info = {
215 .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR,
216 .pNext = &memory_wsi_info,
217 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
218 };
219 const VkMemoryDedicatedAllocateInfoKHR memory_dedicated_info = {
220 .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,
221 .pNext = &memory_export_info,
222 .image = image->image,
223 .buffer = VK_NULL_HANDLE,
224 };
225 const VkMemoryAllocateInfo memory_info = {
226 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
227 .pNext = &memory_dedicated_info,
228 .allocationSize = reqs.size,
229 .memoryTypeIndex = select_memory_type(wsi, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
230 reqs.memoryTypeBits),
231 };
232 result = wsi->AllocateMemory(chain->device, &memory_info,
233 &chain->alloc, &image->memory);
234 if (result != VK_SUCCESS)
235 goto fail;
236
237 result = wsi->BindImageMemory(chain->device, image->image,
238 image->memory, 0);
239 if (result != VK_SUCCESS)
240 goto fail;
241
242 const VkMemoryGetFdInfoKHR memory_get_fd_info = {
243 .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
244 .pNext = NULL,
245 .memory = image->memory,
246 .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
247 };
248 int fd;
249 result = wsi->GetMemoryFdKHR(chain->device, &memory_get_fd_info, &fd);
250 if (result != VK_SUCCESS)
251 goto fail;
252
253 image->size = reqs.size;
254 image->row_pitch = image_layout.rowPitch;
255 image->offset = 0;
256 image->fd = fd;
257
258 return VK_SUCCESS;
259
260 fail:
261 wsi_destroy_image(chain, image);
262
263 return result;
264 }
265
266 #define WSI_PRIME_LINEAR_STRIDE_ALIGN 256
267
268 VkResult
269 wsi_create_prime_image(const struct wsi_swapchain *chain,
270 const VkSwapchainCreateInfoKHR *pCreateInfo,
271 struct wsi_image *image)
272 {
273 const struct wsi_device *wsi = chain->wsi;
274 VkResult result;
275
276 memset(image, 0, sizeof(*image));
277
278 const uint32_t cpp = vk_format_size(pCreateInfo->imageFormat);
279 const uint32_t linear_stride = align_u32(pCreateInfo->imageExtent.width * cpp,
280 WSI_PRIME_LINEAR_STRIDE_ALIGN);
281
282 uint32_t linear_size = linear_stride * pCreateInfo->imageExtent.height;
283 linear_size = align_u32(linear_size, 4096);
284
285 const VkExternalMemoryBufferCreateInfoKHR prime_buffer_external_info = {
286 .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR,
287 .pNext = NULL,
288 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
289 };
290 const VkBufferCreateInfo prime_buffer_info = {
291 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
292 .pNext = &prime_buffer_external_info,
293 .size = linear_size,
294 .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT,
295 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
296 };
297 result = wsi->CreateBuffer(chain->device, &prime_buffer_info,
298 &chain->alloc, &image->prime.buffer);
299 if (result != VK_SUCCESS)
300 goto fail;
301
302 VkMemoryRequirements reqs;
303 wsi->GetBufferMemoryRequirements(chain->device, image->prime.buffer, &reqs);
304 assert(reqs.size <= linear_size);
305
306 const struct wsi_memory_allocate_info memory_wsi_info = {
307 .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA,
308 .pNext = NULL,
309 .implicit_sync = true,
310 };
311 const VkExportMemoryAllocateInfoKHR prime_memory_export_info = {
312 .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR,
313 .pNext = &memory_wsi_info,
314 .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
315 };
316 const VkMemoryDedicatedAllocateInfoKHR prime_memory_dedicated_info = {
317 .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,
318 .pNext = &prime_memory_export_info,
319 .image = VK_NULL_HANDLE,
320 .buffer = image->prime.buffer,
321 };
322 const VkMemoryAllocateInfo prime_memory_info = {
323 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
324 .pNext = &prime_memory_dedicated_info,
325 .allocationSize = linear_size,
326 .memoryTypeIndex = select_memory_type(wsi, 0, reqs.memoryTypeBits),
327 };
328 result = wsi->AllocateMemory(chain->device, &prime_memory_info,
329 &chain->alloc, &image->prime.memory);
330 if (result != VK_SUCCESS)
331 goto fail;
332
333 result = wsi->BindBufferMemory(chain->device, image->prime.buffer,
334 image->prime.memory, 0);
335 if (result != VK_SUCCESS)
336 goto fail;
337
338 const VkImageCreateInfo image_info = {
339 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
340 .pNext = NULL,
341 .flags = 0,
342 .imageType = VK_IMAGE_TYPE_2D,
343 .format = pCreateInfo->imageFormat,
344 .extent = {
345 .width = pCreateInfo->imageExtent.width,
346 .height = pCreateInfo->imageExtent.height,
347 .depth = 1,
348 },
349 .mipLevels = 1,
350 .arrayLayers = 1,
351 .samples = VK_SAMPLE_COUNT_1_BIT,
352 .tiling = VK_IMAGE_TILING_OPTIMAL,
353 .usage = pCreateInfo->imageUsage | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
354 .sharingMode = pCreateInfo->imageSharingMode,
355 .queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount,
356 .pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices,
357 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
358 };
359 result = wsi->CreateImage(chain->device, &image_info,
360 &chain->alloc, &image->image);
361 if (result != VK_SUCCESS)
362 goto fail;
363
364 wsi->GetImageMemoryRequirements(chain->device, image->image, &reqs);
365
366 const VkMemoryDedicatedAllocateInfoKHR memory_dedicated_info = {
367 .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,
368 .pNext = NULL,
369 .image = image->image,
370 .buffer = VK_NULL_HANDLE,
371 };
372 const VkMemoryAllocateInfo memory_info = {
373 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
374 .pNext = &memory_dedicated_info,
375 .allocationSize = reqs.size,
376 .memoryTypeIndex = select_memory_type(wsi, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
377 reqs.memoryTypeBits),
378 };
379 result = wsi->AllocateMemory(chain->device, &memory_info,
380 &chain->alloc, &image->memory);
381 if (result != VK_SUCCESS)
382 goto fail;
383
384 result = wsi->BindImageMemory(chain->device, image->image,
385 image->memory, 0);
386 if (result != VK_SUCCESS)
387 goto fail;
388
389 image->prime.blit_cmd_buffers =
390 vk_zalloc(&chain->alloc,
391 sizeof(VkCommandBuffer) * wsi->queue_family_count, 8,
392 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
393 if (!image->prime.blit_cmd_buffers)
394 goto fail;
395
396 for (uint32_t i = 0; i < wsi->queue_family_count; i++) {
397 const VkCommandBufferAllocateInfo cmd_buffer_info = {
398 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
399 .pNext = NULL,
400 .commandPool = chain->cmd_pools[i],
401 .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
402 .commandBufferCount = 1,
403 };
404 result = wsi->AllocateCommandBuffers(chain->device, &cmd_buffer_info,
405 &image->prime.blit_cmd_buffers[i]);
406 if (result != VK_SUCCESS)
407 goto fail;
408
409 const VkCommandBufferBeginInfo begin_info = {
410 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
411 };
412 wsi->BeginCommandBuffer(image->prime.blit_cmd_buffers[i], &begin_info);
413
414 struct VkBufferImageCopy buffer_image_copy = {
415 .bufferOffset = 0,
416 .bufferRowLength = linear_stride / cpp,
417 .bufferImageHeight = 0,
418 .imageSubresource = {
419 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
420 .mipLevel = 0,
421 .baseArrayLayer = 0,
422 .layerCount = 1,
423 },
424 .imageOffset = { .x = 0, .y = 0, .z = 0 },
425 .imageExtent = {
426 .width = pCreateInfo->imageExtent.width,
427 .height = pCreateInfo->imageExtent.height,
428 .depth = 1,
429 },
430 };
431 wsi->CmdCopyImageToBuffer(image->prime.blit_cmd_buffers[i],
432 image->image,
433 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
434 image->prime.buffer,
435 1, &buffer_image_copy);
436
437 result = wsi->EndCommandBuffer(image->prime.blit_cmd_buffers[i]);
438 if (result != VK_SUCCESS)
439 goto fail;
440 }
441
442 const VkMemoryGetFdInfoKHR linear_memory_get_fd_info = {
443 .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
444 .pNext = NULL,
445 .memory = image->prime.memory,
446 .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
447 };
448 int fd;
449 result = wsi->GetMemoryFdKHR(chain->device, &linear_memory_get_fd_info, &fd);
450 if (result != VK_SUCCESS)
451 goto fail;
452
453 image->size = linear_size;
454 image->row_pitch = linear_stride;
455 image->offset = 0;
456 image->fd = fd;
457
458 return VK_SUCCESS;
459
460 fail:
461 wsi_destroy_image(chain, image);
462
463 return result;
464 }
465
466 void
467 wsi_destroy_image(const struct wsi_swapchain *chain,
468 struct wsi_image *image)
469 {
470 const struct wsi_device *wsi = chain->wsi;
471
472 if (image->prime.blit_cmd_buffers) {
473 for (uint32_t i = 0; i < wsi->queue_family_count; i++) {
474 wsi->FreeCommandBuffers(chain->device, chain->cmd_pools[i],
475 1, &image->prime.blit_cmd_buffers[i]);
476 }
477 vk_free(&chain->alloc, image->prime.blit_cmd_buffers);
478 }
479
480 wsi->FreeMemory(chain->device, image->memory, &chain->alloc);
481 wsi->DestroyImage(chain->device, image->image, &chain->alloc);
482 wsi->FreeMemory(chain->device, image->prime.memory, &chain->alloc);
483 wsi->DestroyBuffer(chain->device, image->prime.buffer, &chain->alloc);
484 }
485
486 VkResult
487 wsi_prime_image_blit_to_linear(const struct wsi_swapchain *chain,
488 struct wsi_image *image,
489 VkQueue queue,
490 uint32_t waitSemaphoreCount,
491 const VkSemaphore *pWaitSemaphores)
492 {
493 uint32_t queue_family = chain->wsi->queue_get_family_index(queue);
494
495 VkPipelineStageFlags stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
496 const VkSubmitInfo submit_info = {
497 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
498 .pNext = NULL,
499 .waitSemaphoreCount = waitSemaphoreCount,
500 .pWaitSemaphores = pWaitSemaphores,
501 .pWaitDstStageMask = &stage_flags,
502 .commandBufferCount = 1,
503 .pCommandBuffers = &image->prime.blit_cmd_buffers[queue_family],
504 .signalSemaphoreCount = 0,
505 .pSignalSemaphores = NULL,
506 };
507 return chain->wsi->QueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE);
508 }
509
510 VkResult
511 wsi_common_queue_present(const struct wsi_device *wsi,
512 VkDevice device,
513 VkQueue queue,
514 int queue_family_index,
515 const VkPresentInfoKHR *pPresentInfo)
516 {
517 VkResult final_result = VK_SUCCESS;
518
519 const VkPresentRegionsKHR *regions =
520 vk_find_struct_const(pPresentInfo->pNext, PRESENT_REGIONS_KHR);
521
522 for (uint32_t i = 0; i < pPresentInfo->swapchainCount; i++) {
523 WSI_FROM_HANDLE(wsi_swapchain, swapchain, pPresentInfo->pSwapchains[i]);
524 VkResult result;
525
526 if (swapchain->fences[0] == VK_NULL_HANDLE) {
527 const VkFenceCreateInfo fence_info = {
528 .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
529 .pNext = NULL,
530 .flags = 0,
531 };
532 result = wsi->CreateFence(device, &fence_info,
533 &swapchain->alloc,
534 &swapchain->fences[0]);
535 if (result != VK_SUCCESS)
536 goto fail_present;
537 } else {
538 wsi->ResetFences(device, 1, &swapchain->fences[0]);
539 }
540
541 VkSubmitInfo submit_info = {
542 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
543 .pNext = NULL,
544 };
545 VkPipelineStageFlags *stage_flags = NULL;
546 if (i == 0) {
547 /* We only need/want to wait on semaphores once. After that, we're
548 * guaranteed ordering since it all happens on the same queue.
549 */
550 submit_info.waitSemaphoreCount = pPresentInfo->waitSemaphoreCount,
551 submit_info.pWaitSemaphores = pPresentInfo->pWaitSemaphores,
552
553 /* Set up the pWaitDstStageMasks */
554 stage_flags = vk_alloc(&swapchain->alloc,
555 sizeof(VkPipelineStageFlags) *
556 pPresentInfo->waitSemaphoreCount,
557 8,
558 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
559 if (!stage_flags) {
560 result = VK_ERROR_OUT_OF_HOST_MEMORY;
561 goto fail_present;
562 }
563 for (uint32_t s = 0; s < pPresentInfo->waitSemaphoreCount; s++)
564 stage_flags[s] = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
565
566 submit_info.pWaitDstStageMask = stage_flags;
567 }
568 result = wsi->QueueSubmit(queue, 1, &submit_info, swapchain->fences[0]);
569 vk_free(&swapchain->alloc, stage_flags);
570 if (result != VK_SUCCESS)
571 goto fail_present;
572
573 const VkPresentRegionKHR *region = NULL;
574 if (regions && regions->pRegions)
575 region = &regions->pRegions[i];
576
577 result = swapchain->queue_present(swapchain,
578 queue,
579 pPresentInfo->waitSemaphoreCount,
580 pPresentInfo->pWaitSemaphores,
581 pPresentInfo->pImageIndices[i],
582 region);
583 if (result != VK_SUCCESS)
584 goto fail_present;
585
586 VkFence last = swapchain->fences[2];
587 swapchain->fences[2] = swapchain->fences[1];
588 swapchain->fences[1] = swapchain->fences[0];
589 swapchain->fences[0] = last;
590
591 if (last != VK_NULL_HANDLE) {
592 wsi->WaitForFences(device, 1, &last, true, 1);
593 }
594
595 fail_present:
596 if (pPresentInfo->pResults != NULL)
597 pPresentInfo->pResults[i] = result;
598
599 /* Let the final result be our first unsuccessful result */
600 if (final_result == VK_SUCCESS)
601 final_result = result;
602 }
603
604 return final_result;
605 }