1 /*  RetroArch - A frontend for libretro.
2  *  Copyright (C) 2016-2017 - Hans-Kristian Arntzen
3  *  Copyright (C) 2016-2019 - Brad Parker
4  *
5  *  RetroArch is free software: you can redistribute it and/or modify it under the terms
6  *  of the GNU General Public License as published by the Free Software Found-
7  *  ation, either version 3 of the License, or (at your option) any later version.
8  *
9  *  RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
10  *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11  *  PURPOSE.  See the GNU General Public License for more details.
12  *
13  *  You should have received a copy of the GNU General Public License along with RetroArch.
14  *  If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 #include <retro_assert.h>
18 #include <dynamic/dylib.h>
19 #include <string/stdstring.h>
20 
21 #ifdef HAVE_CONFIG_H
22 #include "../../config.h"
23 #endif
24 
25 #ifdef HAVE_X11
26 #ifdef HAVE_XCB
27 #include <X11/Xlib-xcb.h>
28 #endif
29 #endif
30 
31 #include "vulkan_common.h"
32 #include <retro_timers.h>
33 #include "../../configuration.h"
34 #include "../include/vulkan/vulkan.h"
35 #include <retro_assert.h>
36 #include "vksym.h"
37 #include <libretro_vulkan.h>
38 #include <retro_math.h>
39 #include <lists/string_list.h>
40 
41 #define VENDOR_ID_AMD 0x1002
42 #define VENDOR_ID_NV 0x10DE
43 #define VENDOR_ID_INTEL 0x8086
44 
45 #if defined(_WIN32)
46 #define VULKAN_EMULATE_MAILBOX
47 #endif
48 
49 /* TODO/FIXME - static globals */
50 static dylib_t                       vulkan_library;
51 static VkInstance                    cached_instance_vk;
52 static VkDevice                      cached_device_vk;
53 static retro_vulkan_destroy_device_t cached_destroy_device_vk;
54 
55 #if 0
56 #define WSI_HARDENING_TEST
57 #endif
58 
59 #ifdef WSI_HARDENING_TEST
60 static unsigned wsi_harden_counter         = 0;
61 static unsigned wsi_harden_counter2        = 0;
62 
trigger_spurious_error_vkresult(VkResult * res)63 static void trigger_spurious_error_vkresult(VkResult *res)
64 {
65    ++wsi_harden_counter;
66    if ((wsi_harden_counter & 15) == 12)
67       *res = VK_ERROR_OUT_OF_DATE_KHR;
68    else if ((wsi_harden_counter & 31) == 13)
69       *res = VK_ERROR_OUT_OF_DATE_KHR;
70    else if ((wsi_harden_counter & 15) == 6)
71       *res = VK_ERROR_SURFACE_LOST_KHR;
72 }
73 
trigger_spurious_error(void)74 static bool trigger_spurious_error(void)
75 {
76    ++wsi_harden_counter2;
77    return ((wsi_harden_counter2 & 15) == 9) || ((wsi_harden_counter2 & 15) == 10);
78 }
79 #endif
80 
81 #ifdef VULKAN_DEBUG
vulkan_debug_cb(VkDebugReportFlagsEXT flags,VkDebugReportObjectTypeEXT objectType,uint64_t object,size_t location,int32_t messageCode,const char * pLayerPrefix,const char * pMessage,void * pUserData)82 static VKAPI_ATTR VkBool32 VKAPI_CALL vulkan_debug_cb(
83       VkDebugReportFlagsEXT flags,
84       VkDebugReportObjectTypeEXT objectType,
85       uint64_t object,
86       size_t location,
87       int32_t messageCode,
88       const char *pLayerPrefix,
89       const char *pMessage,
90       void *pUserData)
91 {
92    (void)objectType;
93    (void)object;
94    (void)location;
95    (void)messageCode;
96    (void)pUserData;
97 
98    if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT)
99    {
100       RARCH_ERR("[Vulkan]: Error: %s: %s\n",
101             pLayerPrefix, pMessage);
102    }
103 #if 0
104    else if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT)
105    {
106       RARCH_WARN("[Vulkan]: Warning: %s: %s\n",
107             pLayerPrefix, pMessage);
108    }
109    else if (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT)
110    {
111       RARCH_LOG("[Vulkan]: Performance warning: %s: %s\n",
112             pLayerPrefix, pMessage);
113    }
114    else
115    {
116       RARCH_LOG("[Vulkan]: Information: %s: %s\n",
117             pLayerPrefix, pMessage);
118    }
119 #endif
120 
121    return VK_FALSE;
122 }
123 #endif
124 
vulkan_emulated_mailbox_deinit(struct vulkan_emulated_mailbox * mailbox)125 static void vulkan_emulated_mailbox_deinit(
126       struct vulkan_emulated_mailbox *mailbox)
127 {
128    if (mailbox->thread)
129    {
130       slock_lock(mailbox->lock);
131       mailbox->dead = true;
132       scond_signal(mailbox->cond);
133       slock_unlock(mailbox->lock);
134       sthread_join(mailbox->thread);
135    }
136 
137    if (mailbox->lock)
138       slock_free(mailbox->lock);
139    if (mailbox->cond)
140       scond_free(mailbox->cond);
141 
142    memset(mailbox, 0, sizeof(*mailbox));
143 }
144 
vulkan_emulated_mailbox_acquire_next_image(struct vulkan_emulated_mailbox * mailbox,unsigned * index)145 static VkResult vulkan_emulated_mailbox_acquire_next_image(
146       struct vulkan_emulated_mailbox *mailbox,
147       unsigned *index)
148 {
149    VkResult res                    = VK_TIMEOUT;
150 
151    slock_lock(mailbox->lock);
152 
153    if (!mailbox->has_pending_request)
154    {
155       mailbox->request_acquire     = true;
156       scond_signal(mailbox->cond);
157    }
158 
159    mailbox->has_pending_request    = true;
160 
161    if (mailbox->acquired)
162    {
163       res                          = mailbox->result;
164       *index                       = mailbox->index;
165       mailbox->has_pending_request = false;
166       mailbox->acquired            = false;
167    }
168 
169    slock_unlock(mailbox->lock);
170    return res;
171 }
172 
vulkan_emulated_mailbox_acquire_next_image_blocking(struct vulkan_emulated_mailbox * mailbox,unsigned * index)173 static VkResult vulkan_emulated_mailbox_acquire_next_image_blocking(
174       struct vulkan_emulated_mailbox *mailbox,
175       unsigned *index)
176 {
177    VkResult res;
178 
179    slock_lock(mailbox->lock);
180 
181    if (!mailbox->has_pending_request)
182    {
183       mailbox->request_acquire  = true;
184       scond_signal(mailbox->cond);
185    }
186 
187    mailbox->has_pending_request = true;
188 
189    while (!mailbox->acquired)
190       scond_wait(mailbox->cond, mailbox->lock);
191 
192    res = mailbox->result;
193    if (res == VK_SUCCESS)
194       *index                    = mailbox->index;
195    mailbox->has_pending_request = false;
196    mailbox->acquired            = false;
197 
198    slock_unlock(mailbox->lock);
199    return res;
200 }
201 
vulkan_emulated_mailbox_loop(void * userdata)202 static void vulkan_emulated_mailbox_loop(void *userdata)
203 {
204    VkFence fence;
205    VkFenceCreateInfo info;
206    struct vulkan_emulated_mailbox *mailbox =
207       (struct vulkan_emulated_mailbox*)userdata;
208 
209    if (!mailbox)
210       return;
211 
212    info.sType             = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
213    info.pNext             = NULL;
214    info.flags             = 0;
215 
216    vkCreateFence(mailbox->device, &info, NULL, &fence);
217 
218    for (;;)
219    {
220       slock_lock(mailbox->lock);
221       while (!mailbox->dead && !mailbox->request_acquire)
222          scond_wait(mailbox->cond, mailbox->lock);
223 
224       if (mailbox->dead)
225       {
226          slock_unlock(mailbox->lock);
227          break;
228       }
229 
230       mailbox->request_acquire = false;
231       slock_unlock(mailbox->lock);
232 
233       mailbox->result          = vkAcquireNextImageKHR(
234             mailbox->device, mailbox->swapchain, UINT64_MAX,
235             VK_NULL_HANDLE, fence, &mailbox->index);
236 
237       /* VK_SUBOPTIMAL_KHR can be returned on Android 10
238        * when prerotate is not dealt with.
239        * This is not an error we need to care about,
240        * and we'll treat it as SUCCESS. */
241       if (mailbox->result == VK_SUBOPTIMAL_KHR)
242          mailbox->result = VK_SUCCESS;
243 
244       if (mailbox->result == VK_SUCCESS)
245          vkWaitForFences(mailbox->device, 1,
246                &fence, true, UINT64_MAX);
247       vkResetFences(mailbox->device, 1, &fence);
248 
249       if (mailbox->result == VK_SUCCESS)
250       {
251          slock_lock(mailbox->lock);
252          mailbox->acquired = true;
253          scond_signal(mailbox->cond);
254          slock_unlock(mailbox->lock);
255       }
256    }
257 
258    vkDestroyFence(mailbox->device, fence, NULL);
259 }
260 
vulkan_emulated_mailbox_init(struct vulkan_emulated_mailbox * mailbox,VkDevice device,VkSwapchainKHR swapchain)261 static bool vulkan_emulated_mailbox_init(
262       struct vulkan_emulated_mailbox *mailbox,
263       VkDevice device,
264       VkSwapchainKHR swapchain)
265 {
266    memset(mailbox, 0, sizeof(*mailbox));
267    mailbox->device    = device;
268    mailbox->swapchain = swapchain;
269 
270    mailbox->cond      = scond_new();
271    if (!mailbox->cond)
272       return false;
273    mailbox->lock      = slock_new();
274    if (!mailbox->lock)
275       return false;
276    mailbox->thread    = sthread_create(vulkan_emulated_mailbox_loop, mailbox);
277    if (!mailbox->thread)
278       return false;
279    return true;
280 }
281 
vulkan_find_memory_type(const VkPhysicalDeviceMemoryProperties * mem_props,uint32_t device_reqs,uint32_t host_reqs)282 uint32_t vulkan_find_memory_type(
283       const VkPhysicalDeviceMemoryProperties *mem_props,
284       uint32_t device_reqs, uint32_t host_reqs)
285 {
286    uint32_t i;
287    for (i = 0; i < VK_MAX_MEMORY_TYPES; i++)
288    {
289       if ((device_reqs & (1u << i)) &&
290             (mem_props->memoryTypes[i].propertyFlags & host_reqs) == host_reqs)
291          return i;
292    }
293 
294    RARCH_ERR("[Vulkan]: Failed to find valid memory type. This should never happen.");
295    abort();
296 }
297 
vulkan_find_memory_type_fallback(const VkPhysicalDeviceMemoryProperties * mem_props,uint32_t device_reqs,uint32_t host_reqs_first,uint32_t host_reqs_second)298 uint32_t vulkan_find_memory_type_fallback(
299       const VkPhysicalDeviceMemoryProperties *mem_props,
300       uint32_t device_reqs, uint32_t host_reqs_first,
301       uint32_t host_reqs_second)
302 {
303    uint32_t i;
304    for (i = 0; i < VK_MAX_MEMORY_TYPES; i++)
305    {
306       if ((device_reqs & (1u << i)) &&
307             (mem_props->memoryTypes[i].propertyFlags & host_reqs_first) == host_reqs_first)
308          return i;
309    }
310 
311    if (host_reqs_first == 0)
312    {
313       RARCH_ERR("[Vulkan]: Failed to find valid memory type. This should never happen.");
314       abort();
315    }
316 
317    return vulkan_find_memory_type_fallback(mem_props,
318          device_reqs, host_reqs_second, 0);
319 }
320 
321 #ifdef VULKAN_DEBUG_TEXTURE_ALLOC
322 static VkImage vk_images[4 * 1024];
323 static unsigned vk_count;
324 static unsigned track_seq;
325 
vulkan_log_textures(void)326 void vulkan_log_textures(void)
327 {
328    unsigned i;
329    for (i = 0; i < vk_count; i++)
330    {
331       RARCH_WARN("[Vulkan]: Found leaked texture %llu.\n",
332             (unsigned long long)vk_images[i]);
333    }
334    vk_count = 0;
335 }
336 
vulkan_track_alloc(VkImage image)337 static void vulkan_track_alloc(VkImage image)
338 {
339    vk_images[vk_count++] = image;
340    RARCH_LOG("[Vulkan]: Alloc %llu (%u).\n",
341          (unsigned long long)image, track_seq);
342    track_seq++;
343 }
344 
vulkan_track_dealloc(VkImage image)345 static void vulkan_track_dealloc(VkImage image)
346 {
347    unsigned i;
348    for (i = 0; i < vk_count; i++)
349    {
350       if (image == vk_images[i])
351       {
352          vk_count--;
353          memmove(vk_images + i, vk_images + 1 + i,
354                sizeof(VkImage) * (vk_count - i));
355          return;
356       }
357    }
358    retro_assert(0 && "Couldn't find VkImage in dealloc!");
359 }
360 #endif
361 
vulkan_num_miplevels(unsigned width,unsigned height)362 static unsigned vulkan_num_miplevels(unsigned width, unsigned height)
363 {
364    unsigned size = MAX(width, height);
365    unsigned levels = 0;
366    while (size)
367    {
368       levels++;
369       size >>= 1;
370    }
371    return levels;
372 }
373 
vulkan_create_texture(vk_t * vk,struct vk_texture * old,unsigned width,unsigned height,VkFormat format,const void * initial,const VkComponentMapping * swizzle,enum vk_texture_type type)374 struct vk_texture vulkan_create_texture(vk_t *vk,
375       struct vk_texture *old,
376       unsigned width, unsigned height,
377       VkFormat format,
378       const void *initial,
379       const VkComponentMapping *swizzle,
380       enum vk_texture_type type)
381 {
382    unsigned i;
383    struct vk_texture tex;
384    VkMemoryRequirements mem_reqs;
385    VkSubresourceLayout layout;
386    VkDevice device                      = vk->context->device;
387    VkImageCreateInfo info               = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
388    VkBufferCreateInfo buffer_info       = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
389    VkImageViewCreateInfo view           = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
390    VkMemoryAllocateInfo alloc           = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
391    VkImageSubresource subresource       = { VK_IMAGE_ASPECT_COLOR_BIT };
392    VkCommandBufferAllocateInfo cmd_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
393    VkSubmitInfo submit_info             = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
394    VkCommandBufferBeginInfo begin_info  = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
395 
396    memset(&tex, 0, sizeof(tex));
397 
398    info.imageType          = VK_IMAGE_TYPE_2D;
399    info.format             = format;
400    info.extent.width       = width;
401    info.extent.height      = height;
402    info.extent.depth       = 1;
403    info.arrayLayers        = 1;
404    info.sharingMode        = VK_SHARING_MODE_EXCLUSIVE;
405    info.mipLevels          = 1;
406    info.samples            = VK_SAMPLE_COUNT_1_BIT;
407 
408    buffer_info.size        = width * height * vulkan_format_to_bpp(format);
409    buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
410 
411    if (type == VULKAN_TEXTURE_STREAMED)
412    {
413       VkFormatProperties format_properties;
414       const VkFormatFeatureFlags required = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
415          VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
416 
417       vkGetPhysicalDeviceFormatProperties(
418             vk->context->gpu, format, &format_properties);
419 
420       if ((format_properties.linearTilingFeatures & required) != required)
421       {
422          RARCH_LOG("[Vulkan]: GPU does not support using linear images as textures. Falling back to copy path.\n");
423          type = VULKAN_TEXTURE_STAGING;
424       }
425    }
426 
427    switch (type)
428    {
429       case VULKAN_TEXTURE_STATIC:
430          /* For simplicity, always build mipmaps for
431           * static textures, samplers can be used to enable it dynamically.
432           */
433          info.mipLevels     = vulkan_num_miplevels(width, height);
434          tex.mipmap         = true;
435          retro_assert(initial && "Static textures must have initial data.\n");
436          info.tiling        = VK_IMAGE_TILING_OPTIMAL;
437          info.usage         = VK_IMAGE_USAGE_SAMPLED_BIT |
438                               VK_IMAGE_USAGE_TRANSFER_DST_BIT |
439                               VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
440          info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
441          break;
442 
443       case VULKAN_TEXTURE_DYNAMIC:
444          retro_assert(!initial && "Dynamic textures must not have initial data.\n");
445          info.tiling        = VK_IMAGE_TILING_OPTIMAL;
446          info.usage         = VK_IMAGE_USAGE_SAMPLED_BIT |
447                               VK_IMAGE_USAGE_TRANSFER_DST_BIT |
448                               VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
449          info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
450          break;
451 
452       case VULKAN_TEXTURE_STREAMED:
453          info.usage         = VK_IMAGE_USAGE_SAMPLED_BIT |
454                               VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
455          info.tiling        = VK_IMAGE_TILING_LINEAR;
456          info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
457          break;
458 
459       case VULKAN_TEXTURE_STAGING:
460          buffer_info.usage  = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
461          info.initialLayout = VK_IMAGE_LAYOUT_GENERAL;
462          info.tiling        = VK_IMAGE_TILING_LINEAR;
463          break;
464 
465       case VULKAN_TEXTURE_READBACK:
466          buffer_info.usage  = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
467          info.initialLayout = VK_IMAGE_LAYOUT_GENERAL;
468          info.tiling        = VK_IMAGE_TILING_LINEAR;
469          break;
470    }
471 
472    if (type != VULKAN_TEXTURE_STAGING && type != VULKAN_TEXTURE_READBACK)
473    {
474       vkCreateImage(device, &info, NULL, &tex.image);
475 #if 0
476       vulkan_track_alloc(tex.image);
477 #endif
478       vkGetImageMemoryRequirements(device, tex.image, &mem_reqs);
479    }
480    else
481    {
482       /* Linear staging textures are not guaranteed to be supported,
483        * use buffers instead. */
484       vkCreateBuffer(device, &buffer_info, NULL, &tex.buffer);
485       vkGetBufferMemoryRequirements(device, tex.buffer, &mem_reqs);
486    }
487    alloc.allocationSize = mem_reqs.size;
488 
489    switch (type)
490    {
491       case VULKAN_TEXTURE_STATIC:
492       case VULKAN_TEXTURE_DYNAMIC:
493          alloc.memoryTypeIndex = vulkan_find_memory_type_fallback(
494                &vk->context->memory_properties,
495                mem_reqs.memoryTypeBits,
496                VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0);
497          break;
498 
499       default:
500          /* Try to find a memory type which is cached, even if it means manual cache management. */
501          alloc.memoryTypeIndex = vulkan_find_memory_type_fallback(
502                &vk->context->memory_properties,
503                mem_reqs.memoryTypeBits,
504                VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
505                VK_MEMORY_PROPERTY_HOST_CACHED_BIT,
506                VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
507                VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
508 
509          tex.need_manual_cache_management =
510             (vk->context->memory_properties.memoryTypes[alloc.memoryTypeIndex].propertyFlags &
511              VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0;
512 
513          /* If the texture is STREAMED and it's not DEVICE_LOCAL, we expect to hit a slower path,
514           * so fallback to copy path. */
515          if (type == VULKAN_TEXTURE_STREAMED &&
516                (vk->context->memory_properties.memoryTypes[alloc.memoryTypeIndex].propertyFlags &
517                 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) == 0)
518          {
519             /* Recreate texture but for STAGING this time ... */
520 #ifdef VULKAN_DEBUG
521             RARCH_LOG("[Vulkan]: GPU supports linear images as textures, but not DEVICE_LOCAL. Falling back to copy path.\n");
522 #endif
523             type = VULKAN_TEXTURE_STAGING;
524             vkDestroyImage(device, tex.image, NULL);
525             tex.image          = (VkImage)NULL;
526             info.initialLayout = VK_IMAGE_LAYOUT_GENERAL;
527 
528             buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
529             vkCreateBuffer(device, &buffer_info, NULL, &tex.buffer);
530             vkGetBufferMemoryRequirements(device, tex.buffer, &mem_reqs);
531 
532             alloc.allocationSize  = mem_reqs.size;
533             alloc.memoryTypeIndex = vulkan_find_memory_type_fallback(
534                   &vk->context->memory_properties,
535                   mem_reqs.memoryTypeBits,
536                   VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
537                   VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
538                   VK_MEMORY_PROPERTY_HOST_CACHED_BIT,
539                   VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
540                   VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
541          }
542          break;
543    }
544 
545    /* We're not reusing the objects themselves. */
546    if (old)
547    {
548       if (old->view != VK_NULL_HANDLE)
549          vkDestroyImageView(vk->context->device, old->view, NULL);
550       if (old->image != VK_NULL_HANDLE)
551       {
552          vkDestroyImage(vk->context->device, old->image, NULL);
553 #ifdef VULKAN_DEBUG_TEXTURE_ALLOC
554          vulkan_track_dealloc(old->image);
555 #endif
556       }
557       if (old->buffer != VK_NULL_HANDLE)
558          vkDestroyBuffer(vk->context->device, old->buffer, NULL);
559    }
560 
561    /* We can pilfer the old memory and move it over to the new texture. */
562    if (old &&
563          old->memory_size >= mem_reqs.size &&
564          old->memory_type == alloc.memoryTypeIndex)
565    {
566       tex.memory      = old->memory;
567       tex.memory_size = old->memory_size;
568       tex.memory_type = old->memory_type;
569 
570       if (old->mapped)
571          vkUnmapMemory(device, old->memory);
572 
573       old->memory     = VK_NULL_HANDLE;
574    }
575    else
576    {
577       vkAllocateMemory(device, &alloc, NULL, &tex.memory);
578       tex.memory_size = alloc.allocationSize;
579       tex.memory_type = alloc.memoryTypeIndex;
580    }
581 
582    if (old)
583    {
584       if (old->memory != VK_NULL_HANDLE)
585          vkFreeMemory(device, old->memory, NULL);
586       memset(old, 0, sizeof(*old));
587    }
588 
589    if (tex.image)
590       vkBindImageMemory(device, tex.image, tex.memory, 0);
591    if (tex.buffer)
592       vkBindBufferMemory(device, tex.buffer, tex.memory, 0);
593 
594    if (type != VULKAN_TEXTURE_STAGING && type != VULKAN_TEXTURE_READBACK)
595    {
596       view.image                       = tex.image;
597       view.viewType                    = VK_IMAGE_VIEW_TYPE_2D;
598       view.format                      = format;
599       if (swizzle)
600          view.components               = *swizzle;
601       else
602       {
603          view.components.r             = VK_COMPONENT_SWIZZLE_R;
604          view.components.g             = VK_COMPONENT_SWIZZLE_G;
605          view.components.b             = VK_COMPONENT_SWIZZLE_B;
606          view.components.a             = VK_COMPONENT_SWIZZLE_A;
607       }
608       view.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
609       view.subresourceRange.levelCount = info.mipLevels;
610       view.subresourceRange.layerCount = 1;
611 
612       vkCreateImageView(device, &view, NULL, &tex.view);
613    }
614    else
615       tex.view        = VK_NULL_HANDLE;
616 
617    if (tex.image && info.tiling == VK_IMAGE_TILING_LINEAR)
618       vkGetImageSubresourceLayout(device, tex.image, &subresource, &layout);
619    else if (tex.buffer)
620    {
621       layout.offset   = 0;
622       layout.size     = buffer_info.size;
623       layout.rowPitch = width * vulkan_format_to_bpp(format);
624    }
625    else
626       memset(&layout, 0, sizeof(layout));
627 
628    tex.stride = layout.rowPitch;
629    tex.offset = layout.offset;
630    tex.size   = layout.size;
631    tex.layout = info.initialLayout;
632 
633    tex.width  = width;
634    tex.height = height;
635    tex.format = format;
636    tex.type   = type;
637 
638    if (initial)
639    {
640       switch (type)
641       {
642          case VULKAN_TEXTURE_STREAMED:
643          case VULKAN_TEXTURE_STAGING:
644             {
645                unsigned y;
646                uint8_t *dst       = NULL;
647                const uint8_t *src = NULL;
648                void *ptr          = NULL;
649                unsigned bpp       = vulkan_format_to_bpp(tex.format);
650                unsigned stride    = tex.width * bpp;
651 
652                vkMapMemory(device, tex.memory, tex.offset, tex.size, 0, &ptr);
653 
654                dst                = (uint8_t*)ptr;
655                src                = (const uint8_t*)initial;
656                for (y = 0; y < tex.height; y++, dst += tex.stride, src += stride)
657                   memcpy(dst, src, width * bpp);
658 
659                if (  tex.need_manual_cache_management &&
660                      tex.memory != VK_NULL_HANDLE)
661                   VULKAN_SYNC_TEXTURE_TO_GPU(vk->context->device, tex.memory);
662                vkUnmapMemory(device, tex.memory);
663             }
664             break;
665          case VULKAN_TEXTURE_STATIC:
666             {
667                VkBufferImageCopy region;
668                VkCommandBuffer staging;
669                struct vk_texture tmp       = vulkan_create_texture(vk, NULL,
670                      width, height, format, initial, NULL, VULKAN_TEXTURE_STAGING);
671 
672                cmd_info.commandPool        = vk->staging_pool;
673                cmd_info.level              = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
674                cmd_info.commandBufferCount = 1;
675 
676                vkAllocateCommandBuffers(vk->context->device,
677                      &cmd_info, &staging);
678 
679                begin_info.flags            = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
680 
681                vkBeginCommandBuffer(staging, &begin_info);
682 
683                /* If doing mipmapping on upload, keep in general
684                 * so we can easily do transfers to
685                 * and transfers from the images without having to
686                 * mess around with lots of extra transitions at
687                 * per-level granularity.
688                 */
689                VULKAN_IMAGE_LAYOUT_TRANSITION(
690                      staging,
691                      tex.image,
692                      VK_IMAGE_LAYOUT_UNDEFINED,
693                      tex.mipmap
694                      ? VK_IMAGE_LAYOUT_GENERAL
695                      : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
696                      0, VK_ACCESS_TRANSFER_WRITE_BIT,
697                      VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
698                      VK_PIPELINE_STAGE_TRANSFER_BIT);
699 
700                memset(&region, 0, sizeof(region));
701                region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
702                region.imageSubresource.layerCount = 1;
703                region.imageExtent.width           = width;
704                region.imageExtent.height          = height;
705                region.imageExtent.depth           = 1;
706 
707                vkCmdCopyBufferToImage(staging,
708                      tmp.buffer,
709                      tex.image,
710                      tex.mipmap
711                      ? VK_IMAGE_LAYOUT_GENERAL
712                      : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
713                      1, &region);
714 
715                if (tex.mipmap)
716                {
717                   for (i = 1; i < info.mipLevels; i++)
718                   {
719                      VkImageBlit blit_region;
720                      unsigned src_width                        = MAX(width >> (i - 1), 1);
721                      unsigned src_height                       = MAX(height >> (i - 1), 1);
722                      unsigned target_width                     = MAX(width >> i, 1);
723                      unsigned target_height                    = MAX(height >> i, 1);
724                      memset(&blit_region, 0, sizeof(blit_region));
725 
726                      blit_region.srcSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
727                      blit_region.srcSubresource.mipLevel       = i - 1;
728                      blit_region.srcSubresource.baseArrayLayer = 0;
729                      blit_region.srcSubresource.layerCount     = 1;
730                      blit_region.dstSubresource                = blit_region.srcSubresource;
731                      blit_region.dstSubresource.mipLevel       = i;
732                      blit_region.srcOffsets[1].x               = src_width;
733                      blit_region.srcOffsets[1].y               = src_height;
734                      blit_region.srcOffsets[1].z               = 1;
735                      blit_region.dstOffsets[1].x               = target_width;
736                      blit_region.dstOffsets[1].y               = target_height;
737                      blit_region.dstOffsets[1].z               = 1;
738 
739                      /* Only injects execution and memory barriers,
740                       * not actual transition. */
741                      VULKAN_IMAGE_LAYOUT_TRANSITION(
742                            staging,
743                            tex.image,
744                            VK_IMAGE_LAYOUT_GENERAL,
745                            VK_IMAGE_LAYOUT_GENERAL,
746                            VK_ACCESS_TRANSFER_WRITE_BIT,
747                            VK_ACCESS_TRANSFER_READ_BIT,
748                            VK_PIPELINE_STAGE_TRANSFER_BIT,
749                            VK_PIPELINE_STAGE_TRANSFER_BIT);
750 
751                      vkCmdBlitImage(
752                            staging,
753                            tex.image,
754                            VK_IMAGE_LAYOUT_GENERAL,
755                            tex.image,
756                            VK_IMAGE_LAYOUT_GENERAL,
757                            1,
758                            &blit_region,
759                            VK_FILTER_LINEAR);
760                   }
761 
762                   /* Complete our texture. */
763                   VULKAN_IMAGE_LAYOUT_TRANSITION(
764                         staging,
765                         tex.image,
766                         VK_IMAGE_LAYOUT_GENERAL,
767                         VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
768                         VK_ACCESS_TRANSFER_WRITE_BIT,
769                         VK_ACCESS_SHADER_READ_BIT,
770                         VK_PIPELINE_STAGE_TRANSFER_BIT,
771                         VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
772                }
773                else
774                {
775                   VULKAN_IMAGE_LAYOUT_TRANSITION(
776                         staging,
777                         tex.image,
778                         VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
779                         VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
780                         VK_ACCESS_TRANSFER_WRITE_BIT,
781                         VK_ACCESS_SHADER_READ_BIT,
782                         VK_PIPELINE_STAGE_TRANSFER_BIT,
783                         VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
784                }
785 
786                vkEndCommandBuffer(staging);
787                submit_info.commandBufferCount = 1;
788                submit_info.pCommandBuffers    = &staging;
789 
790 #ifdef HAVE_THREADS
791                slock_lock(vk->context->queue_lock);
792 #endif
793                vkQueueSubmit(vk->context->queue,
794                      1, &submit_info, VK_NULL_HANDLE);
795 
796                /* TODO: Very crude, but texture uploads only happen
797                 * during init, so waiting for GPU to complete transfer
798                 * and blocking isn't a big deal. */
799                vkQueueWaitIdle(vk->context->queue);
800 #ifdef HAVE_THREADS
801                slock_unlock(vk->context->queue_lock);
802 #endif
803 
804                vkFreeCommandBuffers(vk->context->device,
805                      vk->staging_pool, 1, &staging);
806                vulkan_destroy_texture(
807                      vk->context->device, &tmp);
808                tex.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
809             }
810             break;
811          case VULKAN_TEXTURE_DYNAMIC:
812          case VULKAN_TEXTURE_READBACK:
813             /* TODO/FIXME - stubs */
814             break;
815       }
816    }
817 
818    return tex;
819 }
820 
vulkan_destroy_texture(VkDevice device,struct vk_texture * tex)821 void vulkan_destroy_texture(
822       VkDevice device,
823       struct vk_texture *tex)
824 {
825    if (tex->mapped)
826       vkUnmapMemory(device, tex->memory);
827    if (tex->view)
828       vkDestroyImageView(device, tex->view, NULL);
829    if (tex->image)
830       vkDestroyImage(device, tex->image, NULL);
831    if (tex->buffer)
832       vkDestroyBuffer(device, tex->buffer, NULL);
833    if (tex->memory)
834       vkFreeMemory(device, tex->memory, NULL);
835 
836 #ifdef VULKAN_DEBUG_TEXTURE_ALLOC
837    if (tex->image)
838       vulkan_track_dealloc(tex->image);
839 #endif
840    tex->type                          = VULKAN_TEXTURE_STREAMED;
841    tex->default_smooth                = false;
842    tex->need_manual_cache_management  = false;
843    tex->mipmap                        = false;
844    tex->memory_type                   = 0;
845    tex->width                         = 0;
846    tex->height                        = 0;
847    tex->offset                        = 0;
848    tex->stride                        = 0;
849    tex->size                          = 0;
850    tex->mapped                        = NULL;
851    tex->image                         = VK_NULL_HANDLE;
852    tex->view                          = VK_NULL_HANDLE;
853    tex->memory                        = VK_NULL_HANDLE;
854    tex->buffer                        = VK_NULL_HANDLE;
855    tex->format                        = VK_FORMAT_UNDEFINED;
856    tex->memory_size                   = 0;
857    tex->layout                        = VK_IMAGE_LAYOUT_UNDEFINED;
858 }
859 
vulkan_write_quad_descriptors(VkDevice device,VkDescriptorSet set,VkBuffer buffer,VkDeviceSize offset,VkDeviceSize range,const struct vk_texture * texture,VkSampler sampler)860 static void vulkan_write_quad_descriptors(
861       VkDevice device,
862       VkDescriptorSet set,
863       VkBuffer buffer,
864       VkDeviceSize offset,
865       VkDeviceSize range,
866       const struct vk_texture *texture,
867       VkSampler sampler)
868 {
869    VkWriteDescriptorSet write;
870    VkDescriptorBufferInfo buffer_info;
871 
872    buffer_info.buffer              = buffer;
873    buffer_info.offset              = offset;
874    buffer_info.range               = range;
875 
876    write.sType                     = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
877    write.pNext                     = NULL;
878    write.dstSet                    = set;
879    write.dstBinding                = 0;
880    write.dstArrayElement           = 0;
881    write.descriptorCount           = 1;
882    write.descriptorType            = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
883    write.pImageInfo                = NULL;
884    write.pBufferInfo               = &buffer_info;
885    write.pTexelBufferView          = NULL;
886    vkUpdateDescriptorSets(device, 1, &write, 0, NULL);
887 
888    if (texture)
889    {
890       VkDescriptorImageInfo image_info;
891 
892       image_info.sampler              = sampler;
893       image_info.imageView            = texture->view;
894       image_info.imageLayout          = texture->layout;
895 
896       write.dstSet                    = set;
897       write.dstBinding                = 1;
898       write.descriptorCount           = 1;
899       write.descriptorType            = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
900       write.pImageInfo                = &image_info;
901       vkUpdateDescriptorSets(device, 1, &write, 0, NULL);
902    }
903 }
904 
vulkan_transition_texture(vk_t * vk,VkCommandBuffer cmd,struct vk_texture * texture)905 void vulkan_transition_texture(vk_t *vk, VkCommandBuffer cmd, struct vk_texture *texture)
906 {
907    if (!texture->image)
908       return;
909 
910    /* Transition to GENERAL layout for linear streamed textures.
911     * We're using linear textures here, so only
912     * GENERAL layout is supported.
913     * If we're already in GENERAL, add a host -> shader read memory barrier
914     * to invalidate texture caches.
915     */
916    if (texture->layout != VK_IMAGE_LAYOUT_PREINITIALIZED &&
917        texture->layout != VK_IMAGE_LAYOUT_GENERAL)
918       return;
919 
920    switch (texture->type)
921    {
922       case VULKAN_TEXTURE_STREAMED:
923          VULKAN_IMAGE_LAYOUT_TRANSITION(cmd, texture->image,
924                texture->layout, VK_IMAGE_LAYOUT_GENERAL,
925                VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
926                VK_PIPELINE_STAGE_HOST_BIT,
927                VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
928          break;
929 
930       default:
931          retro_assert(0 && "Attempting to transition invalid texture type.\n");
932          break;
933    }
934    texture->layout = VK_IMAGE_LAYOUT_GENERAL;
935 }
936 
vulkan_check_dynamic_state(vk_t * vk)937 static void vulkan_check_dynamic_state(vk_t *vk)
938 {
939    VkRect2D sci;
940 
941    if (vk->tracker.use_scissor)
942       sci = vk->tracker.scissor;
943    else
944    {
945       /* No scissor -> viewport */
946       sci.offset.x      = vk->vp.x;
947       sci.offset.y      = vk->vp.y;
948       sci.extent.width  = vk->vp.width;
949       sci.extent.height = vk->vp.height;
950    }
951 
952    vkCmdSetViewport(vk->cmd, 0, 1, &vk->vk_vp);
953    vkCmdSetScissor (vk->cmd, 0, 1, &sci);
954 
955    vk->tracker.dirty &= ~VULKAN_DIRTY_DYNAMIC_BIT;
956 }
957 
vulkan_draw_triangles(vk_t * vk,const struct vk_draw_triangles * call)958 void vulkan_draw_triangles(vk_t *vk, const struct vk_draw_triangles *call)
959 {
960    if (call->texture)
961       vulkan_transition_texture(vk, vk->cmd, call->texture);
962 
963    if (call->pipeline != vk->tracker.pipeline)
964    {
965       vkCmdBindPipeline(vk->cmd,
966             VK_PIPELINE_BIND_POINT_GRAPHICS, call->pipeline);
967       vk->tracker.pipeline = call->pipeline;
968 
969       /* Changing pipeline invalidates dynamic state. */
970       vk->tracker.dirty |= VULKAN_DIRTY_DYNAMIC_BIT;
971    }
972 
973    if (vk->tracker.dirty & VULKAN_DIRTY_DYNAMIC_BIT)
974       vulkan_check_dynamic_state(vk);
975 
976    /* Upload descriptors */
977    {
978       VkDescriptorSet set;
979       /* Upload UBO */
980       struct vk_buffer_range range;
981       float *mvp_data_ptr          = NULL;
982 
983       if (!vulkan_buffer_chain_alloc(vk->context, &vk->chain->ubo,
984                call->uniform_size, &range))
985          return;
986 
987       memcpy(range.data, call->uniform, call->uniform_size);
988 
989       set = vulkan_descriptor_manager_alloc(
990             vk->context->device,
991             &vk->chain->descriptor_manager);
992 
993       vulkan_write_quad_descriptors(
994             vk->context->device,
995             set,
996             range.buffer,
997             range.offset,
998             call->uniform_size,
999             call->texture,
1000             call->sampler);
1001 
1002       vkCmdBindDescriptorSets(vk->cmd,
1003             VK_PIPELINE_BIND_POINT_GRAPHICS,
1004             vk->pipelines.layout, 0,
1005             1, &set, 0, NULL);
1006 
1007       vk->tracker.view    = VK_NULL_HANDLE;
1008       vk->tracker.sampler = VK_NULL_HANDLE;
1009       for (
1010               mvp_data_ptr = &vk->tracker.mvp.data[0]
1011             ; mvp_data_ptr < vk->tracker.mvp.data + 16
1012             ; mvp_data_ptr++)
1013          *mvp_data_ptr = 0.0f;
1014    }
1015 
1016    /* VBO is already uploaded. */
1017    vkCmdBindVertexBuffers(vk->cmd, 0, 1,
1018          &call->vbo->buffer, &call->vbo->offset);
1019 
1020    /* Draw the quad */
1021    vkCmdDraw(vk->cmd, call->vertices, 1, 0, 0);
1022 }
1023 
vulkan_draw_quad(vk_t * vk,const struct vk_draw_quad * quad)1024 void vulkan_draw_quad(vk_t *vk, const struct vk_draw_quad *quad)
1025 {
1026    vulkan_transition_texture(vk, vk->cmd, quad->texture);
1027 
1028    if (quad->pipeline != vk->tracker.pipeline)
1029    {
1030       vkCmdBindPipeline(vk->cmd,
1031             VK_PIPELINE_BIND_POINT_GRAPHICS, quad->pipeline);
1032 
1033       vk->tracker.pipeline = quad->pipeline;
1034       /* Changing pipeline invalidates dynamic state. */
1035       vk->tracker.dirty   |= VULKAN_DIRTY_DYNAMIC_BIT;
1036    }
1037 
1038    if (vk->tracker.dirty & VULKAN_DIRTY_DYNAMIC_BIT)
1039       vulkan_check_dynamic_state(vk);
1040 
1041    /* Upload descriptors */
1042    {
1043       VkDescriptorSet set;
1044       struct vk_buffer_range range;
1045 
1046       if (!vulkan_buffer_chain_alloc(vk->context, &vk->chain->ubo,
1047                sizeof(*quad->mvp), &range))
1048          return;
1049 
1050       if (
1051                string_is_equal_fast(quad->mvp,
1052                   &vk->tracker.mvp, sizeof(*quad->mvp))
1053             || quad->texture->view != vk->tracker.view
1054             || quad->sampler != vk->tracker.sampler)
1055       {
1056          /* Upload UBO */
1057          struct vk_buffer_range range;
1058 
1059          if (!vulkan_buffer_chain_alloc(vk->context, &vk->chain->ubo,
1060                   sizeof(*quad->mvp), &range))
1061             return;
1062 
1063          memcpy(range.data, quad->mvp, sizeof(*quad->mvp));
1064 
1065          set = vulkan_descriptor_manager_alloc(
1066                vk->context->device,
1067                &vk->chain->descriptor_manager);
1068 
1069          vulkan_write_quad_descriptors(
1070                vk->context->device,
1071                set,
1072                range.buffer,
1073                range.offset,
1074                sizeof(*quad->mvp),
1075                quad->texture,
1076                quad->sampler);
1077 
1078          vkCmdBindDescriptorSets(vk->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
1079                vk->pipelines.layout, 0,
1080                1, &set, 0, NULL);
1081 
1082          vk->tracker.view    = quad->texture->view;
1083          vk->tracker.sampler = quad->sampler;
1084          vk->tracker.mvp     = *quad->mvp;
1085       }
1086    }
1087 
1088    /* Upload VBO */
1089    {
1090       struct vk_buffer_range range;
1091       if (!vulkan_buffer_chain_alloc(vk->context, &vk->chain->vbo,
1092                6 * sizeof(struct vk_vertex), &range))
1093          return;
1094 
1095       {
1096          struct vk_vertex         *pv = (struct vk_vertex*)range.data;
1097          const struct vk_color *color = &quad->color;
1098 
1099          VULKAN_WRITE_QUAD_VBO(pv, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, color);
1100       }
1101 
1102       vkCmdBindVertexBuffers(vk->cmd, 0, 1,
1103             &range.buffer, &range.offset);
1104    }
1105 
1106    /* Draw the quad */
1107    vkCmdDraw(vk->cmd, 6, 1, 0, 0);
1108 }
1109 
vulkan_create_buffer(const struct vulkan_context * context,size_t size,VkBufferUsageFlags usage)1110 struct vk_buffer vulkan_create_buffer(
1111       const struct vulkan_context *context,
1112       size_t size, VkBufferUsageFlags usage)
1113 {
1114    struct vk_buffer buffer;
1115    VkMemoryRequirements mem_reqs;
1116    VkBufferCreateInfo info;
1117    VkMemoryAllocateInfo alloc;
1118 
1119    info.sType                 = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
1120    info.pNext                 = NULL;
1121    info.flags                 = 0;
1122    info.size                  = size;
1123    info.usage                 = usage;
1124    info.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
1125    info.queueFamilyIndexCount = 0;
1126    info.pQueueFamilyIndices   = NULL;
1127    vkCreateBuffer(context->device, &info, NULL, &buffer.buffer);
1128 
1129    vkGetBufferMemoryRequirements(context->device, buffer.buffer, &mem_reqs);
1130 
1131    alloc.sType                = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
1132    alloc.pNext                = NULL;
1133    alloc.allocationSize       = mem_reqs.size;
1134    alloc.memoryTypeIndex      = vulkan_find_memory_type(
1135          &context->memory_properties,
1136          mem_reqs.memoryTypeBits,
1137          VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
1138          VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
1139    vkAllocateMemory(context->device, &alloc, NULL, &buffer.memory);
1140    vkBindBufferMemory(context->device, buffer.buffer, buffer.memory, 0);
1141 
1142    buffer.size                = size;
1143 
1144    vkMapMemory(context->device,
1145          buffer.memory, 0, buffer.size, 0, &buffer.mapped);
1146    return buffer;
1147 }
1148 
vulkan_destroy_buffer(VkDevice device,struct vk_buffer * buffer)1149 void vulkan_destroy_buffer(
1150       VkDevice device,
1151       struct vk_buffer *buffer)
1152 {
1153    vkUnmapMemory(device, buffer->memory);
1154    vkFreeMemory(device, buffer->memory, NULL);
1155 
1156    vkDestroyBuffer(device, buffer->buffer, NULL);
1157 
1158    memset(buffer, 0, sizeof(*buffer));
1159 }
1160 
vulkan_alloc_descriptor_pool(VkDevice device,const struct vk_descriptor_manager * manager)1161 static struct vk_descriptor_pool *vulkan_alloc_descriptor_pool(
1162       VkDevice device,
1163       const struct vk_descriptor_manager *manager)
1164 {
1165    unsigned i;
1166    VkDescriptorPoolCreateInfo pool_info;
1167    VkDescriptorSetAllocateInfo alloc_info;
1168    struct vk_descriptor_pool *pool        =
1169       (struct vk_descriptor_pool*)malloc(sizeof(*pool));
1170    if (!pool)
1171       return NULL;
1172 
1173    pool_info.sType         = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
1174    pool_info.pNext         = NULL;
1175    pool_info.flags         = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
1176    pool_info.maxSets       = VULKAN_DESCRIPTOR_MANAGER_BLOCK_SETS;
1177    pool_info.poolSizeCount = manager->num_sizes;
1178    pool_info.pPoolSizes    = manager->sizes;
1179 
1180    pool->pool              = VK_NULL_HANDLE;
1181    for (i = 0; i < VULKAN_DESCRIPTOR_MANAGER_BLOCK_SETS; i++)
1182       pool->sets[i]        = VK_NULL_HANDLE;
1183    pool->next              = NULL;
1184 
1185    vkCreateDescriptorPool(device, &pool_info, NULL, &pool->pool);
1186 
1187    /* Just allocate all descriptor sets up front. */
1188    alloc_info.sType              = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
1189    alloc_info.pNext              = NULL;
1190    alloc_info.descriptorPool     = pool->pool;
1191    alloc_info.descriptorSetCount = 1;
1192    alloc_info.pSetLayouts        = &manager->set_layout;
1193 
1194    for (i = 0; i < VULKAN_DESCRIPTOR_MANAGER_BLOCK_SETS; i++)
1195       vkAllocateDescriptorSets(device, &alloc_info, &pool->sets[i]);
1196 
1197    return pool;
1198 }
1199 
vulkan_descriptor_manager_alloc(VkDevice device,struct vk_descriptor_manager * manager)1200 VkDescriptorSet vulkan_descriptor_manager_alloc(
1201       VkDevice device, struct vk_descriptor_manager *manager)
1202 {
1203    if (manager->count < VULKAN_DESCRIPTOR_MANAGER_BLOCK_SETS)
1204       return manager->current->sets[manager->count++];
1205 
1206    while (manager->current->next)
1207    {
1208       manager->current = manager->current->next;
1209       manager->count   = 0;
1210       return manager->current->sets[manager->count++];
1211    }
1212 
1213    manager->current->next = vulkan_alloc_descriptor_pool(device, manager);
1214    retro_assert(manager->current->next);
1215 
1216    manager->current = manager->current->next;
1217    manager->count   = 0;
1218    return manager->current->sets[manager->count++];
1219 }
1220 
vulkan_create_descriptor_manager(VkDevice device,const VkDescriptorPoolSize * sizes,unsigned num_sizes,VkDescriptorSetLayout set_layout)1221 struct vk_descriptor_manager vulkan_create_descriptor_manager(
1222       VkDevice device,
1223       const VkDescriptorPoolSize *sizes,
1224       unsigned num_sizes,
1225       VkDescriptorSetLayout set_layout)
1226 {
1227    unsigned i;
1228    struct vk_descriptor_manager manager;
1229 
1230    retro_assert(num_sizes <= VULKAN_MAX_DESCRIPTOR_POOL_SIZES);
1231 
1232    manager.current    = NULL;
1233    manager.count      = 0;
1234 
1235    for (i = 0; i < VULKAN_MAX_DESCRIPTOR_POOL_SIZES; i++)
1236    {
1237       manager.sizes[i].type            = VK_DESCRIPTOR_TYPE_SAMPLER;
1238       manager.sizes[i].descriptorCount = 0;
1239    }
1240    memcpy(manager.sizes, sizes, num_sizes * sizeof(*sizes));
1241    manager.set_layout = set_layout;
1242    manager.num_sizes  = num_sizes;
1243 
1244    manager.head       = vulkan_alloc_descriptor_pool(device, &manager);
1245    retro_assert(manager.head);
1246    return manager;
1247 }
1248 
vulkan_destroy_descriptor_manager(VkDevice device,struct vk_descriptor_manager * manager)1249 void vulkan_destroy_descriptor_manager(
1250       VkDevice device,
1251       struct vk_descriptor_manager *manager)
1252 {
1253    struct vk_descriptor_pool *node = manager->head;
1254 
1255    while (node)
1256    {
1257       struct vk_descriptor_pool *next = node->next;
1258 
1259       vkFreeDescriptorSets(device, node->pool,
1260             VULKAN_DESCRIPTOR_MANAGER_BLOCK_SETS, node->sets);
1261       vkDestroyDescriptorPool(device, node->pool, NULL);
1262 
1263       free(node);
1264       node = next;
1265    }
1266 
1267    memset(manager, 0, sizeof(*manager));
1268 }
1269 
vulkan_buffer_chain_step(struct vk_buffer_chain * chain)1270 static void vulkan_buffer_chain_step(struct vk_buffer_chain *chain)
1271 {
1272    chain->current = chain->current->next;
1273    chain->offset  = 0;
1274 }
1275 
vulkan_buffer_chain_suballoc(struct vk_buffer_chain * chain,size_t size,struct vk_buffer_range * range)1276 static bool vulkan_buffer_chain_suballoc(struct vk_buffer_chain *chain,
1277       size_t size, struct vk_buffer_range *range)
1278 {
1279    VkDeviceSize next_offset = chain->offset + size;
1280    if (next_offset <= chain->current->buffer.size)
1281    {
1282       range->data   = (uint8_t*)chain->current->buffer.mapped + chain->offset;
1283       range->buffer = chain->current->buffer.buffer;
1284       range->offset = chain->offset;
1285       chain->offset = (next_offset + chain->alignment - 1)
1286          & ~(chain->alignment - 1);
1287 
1288       return true;
1289    }
1290 
1291    return false;
1292 }
1293 
vulkan_buffer_chain_alloc_node(const struct vulkan_context * context,size_t size,VkBufferUsageFlags usage)1294 static struct vk_buffer_node *vulkan_buffer_chain_alloc_node(
1295       const struct vulkan_context *context,
1296       size_t size, VkBufferUsageFlags usage)
1297 {
1298    struct vk_buffer_node *node = (struct vk_buffer_node*)
1299       malloc(sizeof(*node));
1300    if (!node)
1301       return NULL;
1302 
1303    node->buffer = vulkan_create_buffer(
1304          context, size, usage);
1305    node->next   = NULL;
1306    return node;
1307 }
1308 
vulkan_buffer_chain_init(VkDeviceSize block_size,VkDeviceSize alignment,VkBufferUsageFlags usage)1309 struct vk_buffer_chain vulkan_buffer_chain_init(
1310       VkDeviceSize block_size,
1311       VkDeviceSize alignment,
1312       VkBufferUsageFlags usage)
1313 {
1314    struct vk_buffer_chain chain;
1315 
1316    chain.block_size = block_size;
1317    chain.alignment  = alignment;
1318    chain.offset     = 0;
1319    chain.usage      = usage;
1320    chain.head       = NULL;
1321    chain.current    = NULL;
1322 
1323    return chain;
1324 }
1325 
vulkan_buffer_chain_alloc(const struct vulkan_context * context,struct vk_buffer_chain * chain,size_t size,struct vk_buffer_range * range)1326 bool vulkan_buffer_chain_alloc(const struct vulkan_context *context,
1327       struct vk_buffer_chain *chain,
1328       size_t size, struct vk_buffer_range *range)
1329 {
1330    if (!chain->head)
1331    {
1332       chain->head = vulkan_buffer_chain_alloc_node(context,
1333             chain->block_size, chain->usage);
1334       if (!chain->head)
1335          return false;
1336 
1337       chain->current = chain->head;
1338       chain->offset = 0;
1339    }
1340 
1341    if (vulkan_buffer_chain_suballoc(chain, size, range))
1342       return true;
1343 
1344    /* We've exhausted the current chain, traverse list until we
1345     * can find a block we can use. Usually, we just step once. */
1346    while (chain->current->next)
1347    {
1348       vulkan_buffer_chain_step(chain);
1349       if (vulkan_buffer_chain_suballoc(chain, size, range))
1350          return true;
1351    }
1352 
1353    /* We have to allocate a new node, might allocate larger
1354     * buffer here than block_size in case we have
1355     * a very large allocation. */
1356    if (size < chain->block_size)
1357       size = chain->block_size;
1358 
1359    chain->current->next = vulkan_buffer_chain_alloc_node(
1360          context, size, chain->usage);
1361    if (!chain->current->next)
1362       return false;
1363 
1364    vulkan_buffer_chain_step(chain);
1365    /* This cannot possibly fail. */
1366    retro_assert(vulkan_buffer_chain_suballoc(chain, size, range));
1367    return true;
1368 }
1369 
vulkan_buffer_chain_free(VkDevice device,struct vk_buffer_chain * chain)1370 void vulkan_buffer_chain_free(
1371       VkDevice device,
1372       struct vk_buffer_chain *chain)
1373 {
1374    struct vk_buffer_node *node = chain->head;
1375    while (node)
1376    {
1377       struct vk_buffer_node *next = node->next;
1378       vulkan_destroy_buffer(device, &node->buffer);
1379 
1380       free(node);
1381       node = next;
1382    }
1383    memset(chain, 0, sizeof(*chain));
1384 }
1385 
vulkan_load_instance_symbols(gfx_ctx_vulkan_data_t * vk)1386 static bool vulkan_load_instance_symbols(gfx_ctx_vulkan_data_t *vk)
1387 {
1388    if (!vulkan_symbol_wrapper_load_core_instance_symbols(vk->context.instance))
1389       return false;
1390 
1391    VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(vk->context.instance, vkDestroySurfaceKHR);
1392    VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(vk->context.instance, vkGetPhysicalDeviceSurfaceSupportKHR);
1393    VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(vk->context.instance, vkGetPhysicalDeviceSurfaceCapabilitiesKHR);
1394    VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(vk->context.instance, vkGetPhysicalDeviceSurfaceFormatsKHR);
1395    VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(vk->context.instance, vkGetPhysicalDeviceSurfacePresentModesKHR);
1396    return true;
1397 }
1398 
vulkan_load_device_symbols(gfx_ctx_vulkan_data_t * vk)1399 static bool vulkan_load_device_symbols(gfx_ctx_vulkan_data_t *vk)
1400 {
1401    if (!vulkan_symbol_wrapper_load_core_device_symbols(vk->context.device))
1402       return false;
1403 
1404    VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_EXTENSION_SYMBOL(vk->context.device, vkCreateSwapchainKHR);
1405    VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_EXTENSION_SYMBOL(vk->context.device, vkDestroySwapchainKHR);
1406    VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_EXTENSION_SYMBOL(vk->context.device, vkGetSwapchainImagesKHR);
1407    VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_EXTENSION_SYMBOL(vk->context.device, vkAcquireNextImageKHR);
1408    VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_EXTENSION_SYMBOL(vk->context.device, vkQueuePresentKHR);
1409    return true;
1410 }
1411 
vulkan_find_extensions(const char ** exts,unsigned num_exts,const VkExtensionProperties * properties,unsigned property_count)1412 static bool vulkan_find_extensions(const char **exts, unsigned num_exts,
1413       const VkExtensionProperties *properties, unsigned property_count)
1414 {
1415    unsigned i, ext;
1416    bool found;
1417    for (ext = 0; ext < num_exts; ext++)
1418    {
1419       found = false;
1420       for (i = 0; i < property_count; i++)
1421       {
1422          if (string_is_equal(exts[ext], properties[i].extensionName))
1423          {
1424             found = true;
1425             break;
1426          }
1427       }
1428 
1429       if (!found)
1430          return false;
1431    }
1432    return true;
1433 }
1434 
vulkan_find_instance_extensions(const char ** exts,unsigned num_exts)1435 static bool vulkan_find_instance_extensions(const char **exts, unsigned num_exts)
1436 {
1437    uint32_t property_count;
1438    bool ret                          = true;
1439    VkExtensionProperties *properties = NULL;
1440 
1441    if (vkEnumerateInstanceExtensionProperties(NULL, &property_count, NULL) != VK_SUCCESS)
1442       return false;
1443 
1444    properties = (VkExtensionProperties*)malloc(property_count * sizeof(*properties));
1445    if (!properties)
1446    {
1447       ret = false;
1448       goto end;
1449    }
1450 
1451    if (vkEnumerateInstanceExtensionProperties(NULL, &property_count, properties) != VK_SUCCESS)
1452    {
1453       ret = false;
1454       goto end;
1455    }
1456 
1457    if (!vulkan_find_extensions(exts, num_exts, properties, property_count))
1458    {
1459       RARCH_ERR("[Vulkan]: Could not find instance extensions. Will attempt without them.\n");
1460       ret = false;
1461       goto end;
1462    }
1463 
1464 end:
1465    free(properties);
1466    return ret;
1467 }
1468 
vulkan_find_device_extensions(VkPhysicalDevice gpu,const char ** enabled,unsigned * enabled_count,const char ** exts,unsigned num_exts,const char ** optional_exts,unsigned num_optional_exts)1469 static bool vulkan_find_device_extensions(VkPhysicalDevice gpu,
1470       const char **enabled, unsigned *enabled_count,
1471       const char **exts, unsigned num_exts,
1472       const char **optional_exts, unsigned num_optional_exts)
1473 {
1474    uint32_t property_count;
1475    unsigned i;
1476    bool ret                          = true;
1477    VkExtensionProperties *properties = NULL;
1478 
1479    if (vkEnumerateDeviceExtensionProperties(gpu, NULL, &property_count, NULL) != VK_SUCCESS)
1480       return false;
1481 
1482    properties = (VkExtensionProperties*)malloc(property_count * sizeof(*properties));
1483    if (!properties)
1484    {
1485       ret = false;
1486       goto end;
1487    }
1488 
1489    if (vkEnumerateDeviceExtensionProperties(gpu, NULL, &property_count, properties) != VK_SUCCESS)
1490    {
1491       ret = false;
1492       goto end;
1493    }
1494 
1495    if (!vulkan_find_extensions(exts, num_exts, properties, property_count))
1496    {
1497       RARCH_ERR("[Vulkan]: Could not find device extension. Will attempt without it.\n");
1498       ret = false;
1499       goto end;
1500    }
1501 
1502    memcpy((void*)enabled, exts, num_exts * sizeof(*exts));
1503    *enabled_count = num_exts;
1504 
1505    for (i = 0; i < num_optional_exts; i++)
1506       if (vulkan_find_extensions(&optional_exts[i], 1, properties, property_count))
1507          enabled[(*enabled_count)++] = optional_exts[i];
1508 
1509 end:
1510    free(properties);
1511    return ret;
1512 }
1513 
vulkan_context_init_gpu(gfx_ctx_vulkan_data_t * vk)1514 static bool vulkan_context_init_gpu(gfx_ctx_vulkan_data_t *vk)
1515 {
1516    unsigned i;
1517    uint32_t gpu_count               = 0;
1518    VkPhysicalDevice *gpus           = NULL;
1519    union string_list_elem_attr attr = {0};
1520    settings_t *settings             = config_get_ptr();
1521    int gpu_index                    = settings->ints.vulkan_gpu_index;
1522 
1523    if (vkEnumeratePhysicalDevices(vk->context.instance,
1524             &gpu_count, NULL) != VK_SUCCESS)
1525    {
1526       RARCH_ERR("[Vulkan]: Failed to enumerate physical devices.\n");
1527       return false;
1528    }
1529 
1530    gpus = (VkPhysicalDevice*)calloc(gpu_count, sizeof(*gpus));
1531    if (!gpus)
1532    {
1533       RARCH_ERR("[Vulkan]: Failed to enumerate physical devices.\n");
1534       return false;
1535    }
1536 
1537    if (vkEnumeratePhysicalDevices(vk->context.instance,
1538             &gpu_count, gpus) != VK_SUCCESS)
1539    {
1540       RARCH_ERR("[Vulkan]: Failed to enumerate physical devices.\n");
1541       free(gpus);
1542       return false;
1543    }
1544 
1545    if (gpu_count < 1)
1546    {
1547       RARCH_ERR("[Vulkan]: Failed to enumerate Vulkan physical device.\n");
1548       free(gpus);
1549       return false;
1550    }
1551 
1552    if (vk->gpu_list)
1553       string_list_free(vk->gpu_list);
1554 
1555    vk->gpu_list = string_list_new();
1556 
1557    for (i = 0; i < gpu_count; i++)
1558    {
1559       VkPhysicalDeviceProperties gpu_properties;
1560 
1561       vkGetPhysicalDeviceProperties(gpus[i],
1562             &gpu_properties);
1563 
1564       RARCH_LOG("[Vulkan]: Found GPU at index %d: %s\n", i, gpu_properties.deviceName);
1565 
1566       string_list_append(vk->gpu_list, gpu_properties.deviceName, attr);
1567    }
1568 
1569    video_driver_set_gpu_api_devices(GFX_CTX_VULKAN_API, vk->gpu_list);
1570 
1571    if (0 <= gpu_index && gpu_index < (int)gpu_count)
1572    {
1573       RARCH_LOG("[Vulkan]: Using GPU index %d.\n", gpu_index);
1574       vk->context.gpu = gpus[gpu_index];
1575    }
1576    else
1577    {
1578       RARCH_WARN("[Vulkan]: Invalid GPU index %d, using first device found.\n", gpu_index);
1579       vk->context.gpu = gpus[0];
1580    }
1581 
1582    free(gpus);
1583    return true;
1584 }
1585 
vulkan_context_init_device(gfx_ctx_vulkan_data_t * vk)1586 static bool vulkan_context_init_device(gfx_ctx_vulkan_data_t *vk)
1587 {
1588    bool use_device_ext;
1589    uint32_t queue_count;
1590    unsigned i;
1591    static const float one             = 1.0f;
1592    bool found_queue                   = false;
1593 
1594    VkPhysicalDeviceFeatures features  = { false };
1595    VkDeviceQueueCreateInfo queue_info = { VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO };
1596    VkDeviceCreateInfo device_info     = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
1597 
1598    const char *enabled_device_extensions[8];
1599    unsigned enabled_device_extension_count = 0;
1600 
1601    static const char *device_extensions[] = {
1602       "VK_KHR_swapchain",
1603    };
1604 
1605    static const char *optional_device_extensions[] = {
1606       "VK_KHR_sampler_mirror_clamp_to_edge",
1607    };
1608 
1609    struct retro_hw_render_context_negotiation_interface_vulkan *iface =
1610       (struct retro_hw_render_context_negotiation_interface_vulkan*)video_driver_get_context_negotiation_interface();
1611 
1612    if (iface && iface->interface_type != RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN)
1613    {
1614       RARCH_WARN("[Vulkan]: Got HW context negotiation interface, but it's the wrong API.\n");
1615       iface = NULL;
1616    }
1617 
1618    if (iface && iface->interface_version != RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN_VERSION)
1619    {
1620       RARCH_WARN("[Vulkan]: Got HW context negotiation interface, but it's the wrong interface version.\n");
1621       iface = NULL;
1622    }
1623 
1624    if (!cached_device_vk && iface && iface->create_device)
1625    {
1626       struct retro_vulkan_context context = { 0 };
1627       const VkPhysicalDeviceFeatures features = { 0 };
1628 
1629       bool ret = iface->create_device(&context, vk->context.instance,
1630             vk->context.gpu,
1631             vk->vk_surface,
1632             vulkan_symbol_wrapper_instance_proc_addr(),
1633             device_extensions,
1634             ARRAY_SIZE(device_extensions),
1635             NULL,
1636             0,
1637             &features);
1638 
1639       if (!ret)
1640       {
1641          RARCH_WARN("[Vulkan]: Failed to create device with negotiation interface. Falling back to default path.\n");
1642       }
1643       else
1644       {
1645          vk->context.destroy_device = iface->destroy_device;
1646 
1647          vk->context.device = context.device;
1648          vk->context.queue = context.queue;
1649          vk->context.gpu = context.gpu;
1650          vk->context.graphics_queue_index = context.queue_family_index;
1651 
1652          if (context.presentation_queue != context.queue)
1653          {
1654             RARCH_ERR("[Vulkan]: Present queue != graphics queue. This is currently not supported.\n");
1655             return false;
1656          }
1657       }
1658    }
1659 
1660    if (cached_device_vk && cached_destroy_device_vk)
1661    {
1662       vk->context.destroy_device = cached_destroy_device_vk;
1663       cached_destroy_device_vk   = NULL;
1664    }
1665 
1666    if (!vulkan_context_init_gpu(vk))
1667       return false;
1668 
1669    vkGetPhysicalDeviceProperties(vk->context.gpu,
1670          &vk->context.gpu_properties);
1671    vkGetPhysicalDeviceMemoryProperties(vk->context.gpu,
1672          &vk->context.memory_properties);
1673 
1674 #ifdef VULKAN_EMULATE_MAILBOX
1675    /* Win32 windowed mode seems to deal just fine with toggling VSync.
1676     * Fullscreen however ... */
1677    vk->emulate_mailbox = vk->fullscreen;
1678 #endif
1679 
1680    /* If we're emulating mailbox, stick to using fences rather than semaphores.
1681     * Avoids some really weird driver bugs. */
1682    if (!vk->emulate_mailbox)
1683    {
1684       if (vk->context.gpu_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU)
1685       {
1686          vk->use_wsi_semaphore = true;
1687          RARCH_LOG("[Vulkan]: Using semaphores for WSI acquire.\n");
1688       }
1689       else
1690       {
1691          vk->use_wsi_semaphore = false;
1692          RARCH_LOG("[Vulkan]: Using fences for WSI acquire.\n");
1693       }
1694    }
1695 
1696    RARCH_LOG("[Vulkan]: Using GPU: %s\n", vk->context.gpu_properties.deviceName);
1697 
1698    {
1699       char device_str[128];
1700       char driver_version[64];
1701       char api_version[64];
1702       char version_str[128];
1703       int pos = 0;
1704 
1705       device_str[0] = driver_version[0] = api_version[0] = version_str[0] = '\0';
1706 
1707       strlcpy(device_str, vk->context.gpu_properties.deviceName, sizeof(device_str));
1708       strlcat(device_str, " ", sizeof(device_str));
1709 
1710       pos += snprintf(driver_version + pos, sizeof(driver_version) - pos, "%u", VK_VERSION_MAJOR(vk->context.gpu_properties.driverVersion));
1711       strlcat(driver_version, ".", sizeof(driver_version));
1712       pos++;
1713       pos += snprintf(driver_version + pos, sizeof(driver_version) - pos, "%u", VK_VERSION_MINOR(vk->context.gpu_properties.driverVersion));
1714       pos++;
1715       strlcat(driver_version, ".", sizeof(driver_version));
1716       pos += snprintf(driver_version + pos, sizeof(driver_version) - pos, "%u", VK_VERSION_PATCH(vk->context.gpu_properties.driverVersion));
1717 
1718       strlcat(device_str, driver_version, sizeof(device_str));
1719 
1720       pos = 0;
1721 
1722       pos += snprintf(api_version + pos, sizeof(api_version) - pos, "%u", VK_VERSION_MAJOR(vk->context.gpu_properties.apiVersion));
1723       strlcat(api_version, ".", sizeof(api_version));
1724       pos++;
1725       pos += snprintf(api_version + pos, sizeof(api_version) - pos, "%u", VK_VERSION_MINOR(vk->context.gpu_properties.apiVersion));
1726       pos++;
1727       strlcat(api_version, ".", sizeof(api_version));
1728       pos += snprintf(api_version + pos, sizeof(api_version) - pos, "%u", VK_VERSION_PATCH(vk->context.gpu_properties.apiVersion));
1729 
1730       strlcat(version_str, api_version, sizeof(device_str));
1731 
1732       video_driver_set_gpu_device_string(device_str);
1733       video_driver_set_gpu_api_version_string(version_str);
1734    }
1735 
1736    if (vk->context.device == VK_NULL_HANDLE)
1737    {
1738       VkQueueFamilyProperties *queue_properties = NULL;
1739       vkGetPhysicalDeviceQueueFamilyProperties(vk->context.gpu,
1740             &queue_count, NULL);
1741 
1742       if (queue_count < 1)
1743       {
1744          RARCH_ERR("[Vulkan]: Invalid number of queues detected.\n");
1745          return false;
1746       }
1747 
1748       queue_properties = (VkQueueFamilyProperties*)malloc(queue_count * sizeof(*queue_properties));
1749       if (!queue_properties)
1750          return false;
1751 
1752       vkGetPhysicalDeviceQueueFamilyProperties(vk->context.gpu,
1753             &queue_count, queue_properties);
1754 
1755       for (i = 0; i < queue_count; i++)
1756       {
1757          VkQueueFlags required;
1758          VkBool32 supported = VK_FALSE;
1759          vkGetPhysicalDeviceSurfaceSupportKHR(
1760                vk->context.gpu, i,
1761                vk->vk_surface, &supported);
1762 
1763          required = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT;
1764          if (supported && ((queue_properties[i].queueFlags & required) == required))
1765          {
1766             vk->context.graphics_queue_index = i;
1767             RARCH_LOG("[Vulkan]: Queue family %u supports %u sub-queues.\n",
1768                   i, queue_properties[i].queueCount);
1769             found_queue = true;
1770             break;
1771          }
1772       }
1773 
1774       free(queue_properties);
1775 
1776       if (!found_queue)
1777       {
1778          RARCH_ERR("[Vulkan]: Did not find suitable graphics queue.\n");
1779          return false;
1780       }
1781 
1782       use_device_ext = vulkan_find_device_extensions(vk->context.gpu,
1783               enabled_device_extensions, &enabled_device_extension_count,
1784               device_extensions, ARRAY_SIZE(device_extensions),
1785               optional_device_extensions, ARRAY_SIZE(optional_device_extensions));
1786 
1787       if (!use_device_ext)
1788       {
1789           RARCH_ERR("[Vulkan]: Could not find required device extensions.\n");
1790           return false;
1791       }
1792 
1793       queue_info.queueFamilyIndex         = vk->context.graphics_queue_index;
1794       queue_info.queueCount               = 1;
1795       queue_info.pQueuePriorities         = &one;
1796 
1797       device_info.queueCreateInfoCount    = 1;
1798       device_info.pQueueCreateInfos       = &queue_info;
1799       device_info.enabledExtensionCount   = enabled_device_extension_count;
1800       device_info.ppEnabledExtensionNames = enabled_device_extension_count ? enabled_device_extensions : NULL;
1801       device_info.pEnabledFeatures        = &features;
1802 
1803       if (cached_device_vk)
1804       {
1805          vk->context.device = cached_device_vk;
1806          cached_device_vk   = NULL;
1807 
1808          video_driver_set_video_cache_context_ack();
1809          RARCH_LOG("[Vulkan]: Using cached Vulkan context.\n");
1810       }
1811       else if (vkCreateDevice(vk->context.gpu, &device_info,
1812                NULL, &vk->context.device) != VK_SUCCESS)
1813       {
1814          RARCH_ERR("[Vulkan]: Failed to create device.\n");
1815          return false;
1816       }
1817    }
1818 
1819    if (!vulkan_load_device_symbols(vk))
1820    {
1821       RARCH_ERR("[Vulkan]: Failed to load device symbols.\n");
1822       return false;
1823    }
1824 
1825    vkGetDeviceQueue(vk->context.device,
1826       vk->context.graphics_queue_index, 0, &vk->context.queue);
1827 
1828 #ifdef HAVE_THREADS
1829    vk->context.queue_lock = slock_new();
1830    if (!vk->context.queue_lock)
1831    {
1832       RARCH_ERR("[Vulkan]: Failed to create queue lock.\n");
1833       return false;
1834    }
1835 #endif
1836 
1837    return true;
1838 }
1839 
vulkan_context_init(gfx_ctx_vulkan_data_t * vk,enum vulkan_wsi_type type)1840 bool vulkan_context_init(gfx_ctx_vulkan_data_t *vk,
1841       enum vulkan_wsi_type type)
1842 {
1843    unsigned i;
1844    VkResult res;
1845    PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
1846    VkInstanceCreateInfo info          = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
1847    VkApplicationInfo app              = { VK_STRUCTURE_TYPE_APPLICATION_INFO };
1848 
1849    const char *instance_extensions[4];
1850    unsigned ext_count = 0;
1851 
1852 #ifdef VULKAN_DEBUG
1853    instance_extensions[ext_count++] = "VK_EXT_debug_report";
1854    static const char *instance_layers[] = { "VK_LAYER_KHRONOS_validation" };
1855 #endif
1856 
1857    bool use_instance_ext;
1858    struct retro_hw_render_context_negotiation_interface_vulkan *iface =
1859       (struct retro_hw_render_context_negotiation_interface_vulkan*)video_driver_get_context_negotiation_interface();
1860 
1861    if (iface && iface->interface_type != RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN)
1862    {
1863       RARCH_WARN("[Vulkan]: Got HW context negotiation interface, but it's the wrong API.\n");
1864       iface = NULL;
1865    }
1866 
1867    if (iface && iface->interface_version != RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN_VERSION)
1868    {
1869       RARCH_WARN("[Vulkan]: Got HW context negotiation interface, but it's the wrong interface version.\n");
1870       iface = NULL;
1871    }
1872 
1873    instance_extensions[ext_count++] = "VK_KHR_surface";
1874 
1875    switch (type)
1876    {
1877       case VULKAN_WSI_WAYLAND:
1878          instance_extensions[ext_count++] = "VK_KHR_wayland_surface";
1879          break;
1880       case VULKAN_WSI_ANDROID:
1881          instance_extensions[ext_count++] = "VK_KHR_android_surface";
1882          break;
1883       case VULKAN_WSI_WIN32:
1884          instance_extensions[ext_count++] = "VK_KHR_win32_surface";
1885          break;
1886       case VULKAN_WSI_XLIB:
1887          instance_extensions[ext_count++] = "VK_KHR_xlib_surface";
1888          break;
1889       case VULKAN_WSI_XCB:
1890          instance_extensions[ext_count++] = "VK_KHR_xcb_surface";
1891          break;
1892       case VULKAN_WSI_MIR:
1893          instance_extensions[ext_count++] = "VK_KHR_mir_surface";
1894          break;
1895       case VULKAN_WSI_DISPLAY:
1896          instance_extensions[ext_count++] = "VK_KHR_display";
1897          break;
1898       case VULKAN_WSI_MVK_MACOS:
1899          instance_extensions[ext_count++] = "VK_MVK_macos_surface";
1900          break;
1901       case VULKAN_WSI_MVK_IOS:
1902          instance_extensions[ext_count++] = "VK_MVK_ios_surface";
1903          break;
1904       case VULKAN_WSI_NONE:
1905       default:
1906          break;
1907    }
1908 
1909    if (!vulkan_library)
1910    {
1911 #ifdef _WIN32
1912       vulkan_library = dylib_load("vulkan-1.dll");
1913 #elif __APPLE__
1914       vulkan_library = dylib_load("libMoltenVK.dylib");
1915 #else
1916       vulkan_library = dylib_load("libvulkan.so");
1917       if (!vulkan_library)
1918          vulkan_library = dylib_load("libvulkan.so.1");
1919 #endif
1920    }
1921 
1922    if (!vulkan_library)
1923    {
1924       RARCH_ERR("[Vulkan]: Failed to open Vulkan loader.\n");
1925       return false;
1926    }
1927 
1928    RARCH_LOG("[Vulkan]: Vulkan dynamic library loaded.\n");
1929 
1930    GetInstanceProcAddr =
1931       (PFN_vkGetInstanceProcAddr)dylib_proc(vulkan_library, "vkGetInstanceProcAddr");
1932 
1933    if (!GetInstanceProcAddr)
1934    {
1935       RARCH_ERR("[Vulkan]: Failed to load vkGetInstanceProcAddr symbol, broken loader?\n");
1936       return false;
1937    }
1938 
1939    vulkan_symbol_wrapper_init(GetInstanceProcAddr);
1940 
1941    if (!vulkan_symbol_wrapper_load_global_symbols())
1942    {
1943       RARCH_ERR("[Vulkan]: Failed to load global Vulkan symbols, broken loader?\n");
1944       return false;
1945    }
1946 
1947    use_instance_ext = vulkan_find_instance_extensions(instance_extensions, ext_count);
1948 
1949    app.pApplicationName              = msg_hash_to_str(MSG_PROGRAM);
1950    app.applicationVersion            = 0;
1951    app.pEngineName                   = msg_hash_to_str(MSG_PROGRAM);
1952    app.engineVersion                 = 0;
1953    app.apiVersion                    = VK_MAKE_VERSION(1, 0, 18);
1954 
1955    info.pApplicationInfo             = &app;
1956    info.enabledExtensionCount        = use_instance_ext ? ext_count : 0;
1957    info.ppEnabledExtensionNames      = use_instance_ext ? instance_extensions : NULL;
1958 #ifdef VULKAN_DEBUG
1959    info.enabledLayerCount            = ARRAY_SIZE(instance_layers);
1960    info.ppEnabledLayerNames          = instance_layers;
1961 #endif
1962 
1963    if (iface && iface->get_application_info)
1964    {
1965       info.pApplicationInfo = iface->get_application_info();
1966       if (info.pApplicationInfo->pApplicationName)
1967       {
1968          RARCH_LOG("[Vulkan]: App: %s (version %u)\n",
1969                info.pApplicationInfo->pApplicationName,
1970                info.pApplicationInfo->applicationVersion);
1971       }
1972 
1973       if (info.pApplicationInfo->pEngineName)
1974       {
1975          RARCH_LOG("[Vulkan]: Engine: %s (version %u)\n",
1976                info.pApplicationInfo->pEngineName,
1977                info.pApplicationInfo->engineVersion);
1978       }
1979    }
1980 
1981    if (cached_instance_vk)
1982    {
1983       vk->context.instance           = cached_instance_vk;
1984       cached_instance_vk             = NULL;
1985       res                            = VK_SUCCESS;
1986    }
1987    else
1988       res = vkCreateInstance(&info, NULL, &vk->context.instance);
1989 
1990 #ifdef VULKAN_DEBUG
1991    VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(vk->context.instance,
1992          vkCreateDebugReportCallbackEXT);
1993    VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(vk->context.instance,
1994          vkDebugReportMessageEXT);
1995    VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(vk->context.instance,
1996          vkDestroyDebugReportCallbackEXT);
1997 
1998    {
1999       VkDebugReportCallbackCreateInfoEXT info =
2000       { VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT };
2001       info.flags =
2002          VK_DEBUG_REPORT_ERROR_BIT_EXT |
2003          VK_DEBUG_REPORT_WARNING_BIT_EXT |
2004          VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
2005       info.pfnCallback = vulkan_debug_cb;
2006 
2007       if (vk->context.instance)
2008          vkCreateDebugReportCallbackEXT(vk->context.instance, &info, NULL,
2009                &vk->context.debug_callback);
2010    }
2011    RARCH_LOG("[Vulkan]: Enabling Vulkan debug layers.\n");
2012 #endif
2013 
2014    /* Try different API versions if driver has compatible
2015     * but slightly different VK_API_VERSION. */
2016    for (i = 1; i < 4 && res == VK_ERROR_INCOMPATIBLE_DRIVER; i++)
2017    {
2018       info.pApplicationInfo = &app;
2019       app.apiVersion = VK_MAKE_VERSION(1, 0, i);
2020       res = vkCreateInstance(&info, NULL, &vk->context.instance);
2021    }
2022 
2023    if (res != VK_SUCCESS)
2024    {
2025       RARCH_ERR("Failed to create Vulkan instance (%d).\n", res);
2026       return false;
2027    }
2028 
2029    if (!vulkan_load_instance_symbols(vk))
2030    {
2031       RARCH_ERR("[Vulkan]: Failed to load instance symbols.\n");
2032       return false;
2033    }
2034 
2035    return true;
2036 }
2037 
vulkan_update_display_mode(unsigned * width,unsigned * height,const VkDisplayModePropertiesKHR * mode,const struct vulkan_display_surface_info * info)2038 static bool vulkan_update_display_mode(
2039       unsigned *width,
2040       unsigned *height,
2041       const VkDisplayModePropertiesKHR *mode,
2042       const struct vulkan_display_surface_info *info)
2043 {
2044    unsigned visible_width  = mode->parameters.visibleRegion.width;
2045    unsigned visible_height = mode->parameters.visibleRegion.height;
2046 
2047    if (!info->width || !info->height)
2048    {
2049       /* Strategy here is to pick something which is largest resolution. */
2050       unsigned area = visible_width * visible_height;
2051       if (area > (*width) * (*height))
2052       {
2053          *width     = visible_width;
2054          *height    = visible_height;
2055          return true;
2056       }
2057    }
2058    else
2059    {
2060       /* For particular resolutions, find the closest. */
2061       int delta_x     = (int)info->width - (int)visible_width;
2062       int delta_y     = (int)info->height - (int)visible_height;
2063       int old_delta_x = (int)info->width - (int)*width;
2064       int old_delta_y = (int)info->height - (int)*height;
2065 
2066       int dist        = delta_x * delta_x + delta_y * delta_y;
2067       int old_dist    = old_delta_x * old_delta_x + old_delta_y * old_delta_y;
2068 
2069       if (dist < old_dist)
2070       {
2071          *width       = visible_width;
2072          *height      = visible_height;
2073          return true;
2074       }
2075    }
2076 
2077    return false;
2078 }
2079 
vulkan_create_display_surface(gfx_ctx_vulkan_data_t * vk,unsigned * width,unsigned * height,const struct vulkan_display_surface_info * info)2080 static bool vulkan_create_display_surface(gfx_ctx_vulkan_data_t *vk,
2081       unsigned *width, unsigned *height,
2082       const struct vulkan_display_surface_info *info)
2083 {
2084    bool ret                                  = true;
2085    uint32_t display_count                    = 0;
2086    uint32_t plane_count                      = 0;
2087    VkDisplayPropertiesKHR *displays          = NULL;
2088    VkDisplayPlanePropertiesKHR *planes       = NULL;
2089    uint32_t mode_count                       = 0;
2090    VkDisplayModePropertiesKHR *modes         = NULL;
2091    unsigned dpy, i, j;
2092    uint32_t best_plane                       = UINT32_MAX;
2093    VkDisplayPlaneAlphaFlagBitsKHR alpha_mode = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR;
2094    VkDisplaySurfaceCreateInfoKHR create_info = { VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR };
2095    VkDisplayModeKHR best_mode                = VK_NULL_HANDLE;
2096    /* Monitor index starts on 1, 0 is auto. */
2097    unsigned monitor_index                    = info->monitor_index;
2098    unsigned saved_width                      = *width;
2099    unsigned saved_height                     = *height;
2100 
2101    /* We need to decide on GPU here to be able to query support. */
2102    if (!vulkan_context_init_gpu(vk))
2103       return false;
2104 
2105    VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(vk->context.instance,
2106          vkGetPhysicalDeviceDisplayPropertiesKHR);
2107    VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(vk->context.instance,
2108          vkGetPhysicalDeviceDisplayPlanePropertiesKHR);
2109    VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(vk->context.instance,
2110          vkGetDisplayPlaneSupportedDisplaysKHR);
2111    VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(vk->context.instance,
2112          vkGetDisplayModePropertiesKHR);
2113    VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(vk->context.instance,
2114          vkCreateDisplayModeKHR);
2115    VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(vk->context.instance,
2116          vkGetDisplayPlaneCapabilitiesKHR);
2117    VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(vk->context.instance,
2118          vkCreateDisplayPlaneSurfaceKHR);
2119 
2120 #define GOTO_FAIL() do { \
2121    ret = false; \
2122    goto end; \
2123 } while(0)
2124 
2125    if (vkGetPhysicalDeviceDisplayPropertiesKHR(vk->context.gpu, &display_count, NULL) != VK_SUCCESS)
2126       GOTO_FAIL();
2127    displays = (VkDisplayPropertiesKHR*)calloc(display_count, sizeof(*displays));
2128    if (!displays)
2129       GOTO_FAIL();
2130    if (vkGetPhysicalDeviceDisplayPropertiesKHR(vk->context.gpu, &display_count, displays) != VK_SUCCESS)
2131       GOTO_FAIL();
2132 
2133    if (vkGetPhysicalDeviceDisplayPlanePropertiesKHR(vk->context.gpu, &plane_count, NULL) != VK_SUCCESS)
2134       GOTO_FAIL();
2135    planes = (VkDisplayPlanePropertiesKHR*)calloc(plane_count, sizeof(*planes));
2136    if (!planes)
2137       GOTO_FAIL();
2138    if (vkGetPhysicalDeviceDisplayPlanePropertiesKHR(vk->context.gpu, &plane_count, planes) != VK_SUCCESS)
2139       GOTO_FAIL();
2140 
2141    if (monitor_index > display_count)
2142    {
2143       RARCH_WARN("Monitor index is out of range, using automatic display.\n");
2144       monitor_index = 0;
2145    }
2146 
2147 retry:
2148    for (dpy = 0; dpy < display_count; dpy++)
2149    {
2150       VkDisplayKHR display;
2151       if (monitor_index != 0 && (monitor_index - 1) != dpy)
2152          continue;
2153 
2154       display    = displays[dpy].display;
2155       best_mode  = VK_NULL_HANDLE;
2156       best_plane = UINT32_MAX;
2157 
2158       if (vkGetDisplayModePropertiesKHR(vk->context.gpu,
2159             display, &mode_count, NULL) != VK_SUCCESS)
2160          GOTO_FAIL();
2161 
2162       modes = (VkDisplayModePropertiesKHR*)calloc(mode_count, sizeof(*modes));
2163       if (!modes)
2164          GOTO_FAIL();
2165 
2166       if (vkGetDisplayModePropertiesKHR(vk->context.gpu,
2167             display, &mode_count, modes) != VK_SUCCESS)
2168          GOTO_FAIL();
2169 
2170       for (i = 0; i < mode_count; i++)
2171       {
2172          const VkDisplayModePropertiesKHR *mode = &modes[i];
2173          if (vulkan_update_display_mode(width, height, mode, info))
2174             best_mode = modes[i].displayMode;
2175       }
2176 
2177       free(modes);
2178       modes = NULL;
2179       mode_count = 0;
2180 
2181       if (best_mode == VK_NULL_HANDLE)
2182          continue;
2183 
2184       for (i = 0; i < plane_count; i++)
2185       {
2186          uint32_t supported_count = 0;
2187          VkDisplayKHR *supported = NULL;
2188          VkDisplayPlaneCapabilitiesKHR plane_caps;
2189          vkGetDisplayPlaneSupportedDisplaysKHR(vk->context.gpu, i, &supported_count, NULL);
2190          if (!supported_count)
2191             continue;
2192 
2193          supported = (VkDisplayKHR*)calloc(supported_count, sizeof(*supported));
2194          if (!supported)
2195             GOTO_FAIL();
2196 
2197          vkGetDisplayPlaneSupportedDisplaysKHR(vk->context.gpu, i, &supported_count,
2198                supported);
2199 
2200          for (j = 0; j < supported_count; j++)
2201          {
2202             if (supported[j] == display)
2203             {
2204                if (best_plane == UINT32_MAX)
2205                   best_plane = j;
2206                break;
2207             }
2208          }
2209 
2210          free(supported);
2211          supported = NULL;
2212 
2213          if (j == supported_count)
2214             continue;
2215 
2216          if (planes[i].currentDisplay == VK_NULL_HANDLE ||
2217              planes[i].currentDisplay == display)
2218             best_plane = j;
2219          else
2220             continue;
2221 
2222          vkGetDisplayPlaneCapabilitiesKHR(vk->context.gpu,
2223                best_mode, i, &plane_caps);
2224 
2225          if (plane_caps.supportedAlpha & VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR)
2226          {
2227             best_plane = j;
2228             alpha_mode = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR;
2229             goto out;
2230          }
2231       }
2232    }
2233 out:
2234 
2235    if (best_plane == UINT32_MAX && monitor_index != 0)
2236    {
2237       RARCH_WARN("Could not find suitable surface for monitor index: %u.\n",
2238             monitor_index);
2239       RARCH_WARN("Retrying first suitable monitor.\n");
2240       monitor_index = 0;
2241       best_mode = VK_NULL_HANDLE;
2242       *width = saved_width;
2243       *height = saved_height;
2244       goto retry;
2245    }
2246 
2247    if (best_mode == VK_NULL_HANDLE)
2248       GOTO_FAIL();
2249    if (best_plane == UINT32_MAX)
2250       GOTO_FAIL();
2251 
2252    create_info.displayMode = best_mode;
2253    create_info.planeIndex = best_plane;
2254    create_info.planeStackIndex = planes[best_plane].currentStackIndex;
2255    create_info.transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
2256    create_info.globalAlpha = 1.0f;
2257    create_info.alphaMode = alpha_mode;
2258    create_info.imageExtent.width = *width;
2259    create_info.imageExtent.height = *height;
2260 
2261    if (vkCreateDisplayPlaneSurfaceKHR(vk->context.instance,
2262             &create_info, NULL, &vk->vk_surface) != VK_SUCCESS)
2263       GOTO_FAIL();
2264 
2265 end:
2266    free(displays);
2267    free(planes);
2268    free(modes);
2269    return ret;
2270 }
2271 
vulkan_surface_create(gfx_ctx_vulkan_data_t * vk,enum vulkan_wsi_type type,void * display,void * surface,unsigned width,unsigned height,unsigned swap_interval)2272 bool vulkan_surface_create(gfx_ctx_vulkan_data_t *vk,
2273       enum vulkan_wsi_type type,
2274       void *display, void *surface,
2275       unsigned width, unsigned height,
2276       unsigned swap_interval)
2277 {
2278    switch (type)
2279    {
2280       case VULKAN_WSI_WAYLAND:
2281 #ifdef HAVE_WAYLAND
2282          {
2283             PFN_vkCreateWaylandSurfaceKHR create;
2284             if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(vk->context.instance, "vkCreateWaylandSurfaceKHR", create))
2285                return false;
2286             VkWaylandSurfaceCreateInfoKHR surf_info;
2287 
2288             memset(&surf_info, 0, sizeof(surf_info));
2289 
2290             surf_info.sType   = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
2291             surf_info.pNext   = NULL;
2292             surf_info.flags   = 0;
2293             surf_info.display = (struct wl_display*)display;
2294             surf_info.surface = (struct wl_surface*)surface;
2295 
2296             if (create(vk->context.instance,
2297                      &surf_info, NULL, &vk->vk_surface) != VK_SUCCESS)
2298                return false;
2299          }
2300 #endif
2301          break;
2302       case VULKAN_WSI_ANDROID:
2303 #ifdef ANDROID
2304          {
2305             PFN_vkCreateAndroidSurfaceKHR create;
2306             if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(vk->context.instance, "vkCreateAndroidSurfaceKHR", create))
2307                return false;
2308             VkAndroidSurfaceCreateInfoKHR surf_info;
2309 
2310             memset(&surf_info, 0, sizeof(surf_info));
2311 
2312             surf_info.sType  = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
2313             surf_info.flags  = 0;
2314             surf_info.window = (ANativeWindow*)surface;
2315 
2316             if (create(vk->context.instance,
2317                      &surf_info, NULL, &vk->vk_surface) != VK_SUCCESS)
2318             {
2319                RARCH_ERR("[Vulkan]: Failed to create Android surface.\n");
2320                return false;
2321             }
2322             RARCH_LOG("[Vulkan]: Created Android surface: %llu\n",
2323                   (unsigned long long)vk->vk_surface);
2324          }
2325 #endif
2326          break;
2327       case VULKAN_WSI_WIN32:
2328 #ifdef _WIN32
2329          {
2330             VkWin32SurfaceCreateInfoKHR surf_info;
2331             PFN_vkCreateWin32SurfaceKHR create;
2332 
2333             if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(vk->context.instance, "vkCreateWin32SurfaceKHR", create))
2334                return false;
2335 
2336             memset(&surf_info, 0, sizeof(surf_info));
2337 
2338             surf_info.sType     = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
2339             surf_info.flags     = 0;
2340             surf_info.hinstance = *(const HINSTANCE*)display;
2341             surf_info.hwnd      = *(const HWND*)surface;
2342 
2343             if (create(vk->context.instance,
2344                      &surf_info, NULL, &vk->vk_surface) != VK_SUCCESS)
2345                return false;
2346          }
2347 #endif
2348          break;
2349       case VULKAN_WSI_XLIB:
2350 #ifdef HAVE_XLIB
2351          {
2352             PFN_vkCreateXlibSurfaceKHR create;
2353             if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(vk->context.instance, "vkCreateXlibSurfaceKHR", create))
2354                return false;
2355             VkXlibSurfaceCreateInfoKHR surf_info;
2356 
2357             memset(&surf_info, 0, sizeof(surf_info));
2358 
2359             surf_info.sType  = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
2360             surf_info.flags  = 0;
2361             surf_info.dpy    = (Display*)display;
2362             surf_info.window = *(const Window*)surface;
2363 
2364             if (create(vk->context.instance,
2365                      &surf_info, NULL, &vk->vk_surface)
2366                   != VK_SUCCESS)
2367                return false;
2368          }
2369 #endif
2370          break;
2371       case VULKAN_WSI_XCB:
2372 #ifdef HAVE_X11
2373 #ifdef HAVE_XCB
2374          {
2375             PFN_vkCreateXcbSurfaceKHR create;
2376             if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(vk->context.instance, "vkCreateXcbSurfaceKHR", create))
2377                return false;
2378             VkXcbSurfaceCreateInfoKHR surf_info;
2379 
2380             memset(&surf_info, 0, sizeof(surf_info));
2381 
2382             surf_info.sType      = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
2383             surf_info.flags      = 0;
2384             surf_info.connection = XGetXCBConnection((Display*)display);
2385             surf_info.window     = *(const xcb_window_t*)surface;
2386 
2387             if (create(vk->context.instance,
2388                      &surf_info, NULL, &vk->vk_surface)
2389                   != VK_SUCCESS)
2390                return false;
2391          }
2392 #endif
2393 #endif
2394          break;
2395       case VULKAN_WSI_MIR:
2396 #ifdef HAVE_MIR
2397          {
2398             PFN_vkCreateMirSurfaceKHR create;
2399             if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(vk->context.instance, "vkCreateMirSurfaceKHR", create))
2400                return false;
2401             VkMirSurfaceCreateInfoKHR surf_info;
2402 
2403             memset(&surf_info, 0, sizeof(surf_info));
2404 
2405             surf_info.sType      = VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR;
2406             surf_info.connection = display;
2407             surf_info.mirSurface = surface;
2408 
2409             if (create(vk->context.instance,
2410                      &surf_info, NULL, &vk->vk_surface)
2411                   != VK_SUCCESS)
2412                return false;
2413          }
2414 #endif
2415          break;
2416       case VULKAN_WSI_DISPLAY:
2417          {
2418             if (!vulkan_create_display_surface(vk,
2419                      &width, &height,
2420                      (const struct vulkan_display_surface_info*)display))
2421                return false;
2422          }
2423          break;
2424       case VULKAN_WSI_MVK_MACOS:
2425 #ifdef HAVE_COCOA
2426          {
2427             PFN_vkCreateMacOSSurfaceMVK create;
2428             if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(vk->context.instance, "vkCreateMacOSSurfaceMVK", create))
2429                return false;
2430             VkMacOSSurfaceCreateInfoMVK surf_info;
2431 
2432             memset(&surf_info, 0, sizeof(surf_info));
2433 
2434             surf_info.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
2435             surf_info.pNext = NULL;
2436             surf_info.flags = 0;
2437             surf_info.pView = surface;
2438 
2439             if (create(vk->context.instance, &surf_info, NULL, &vk->vk_surface)
2440                 != VK_SUCCESS)
2441                return false;
2442          }
2443 #endif
2444          break;
2445       case VULKAN_WSI_MVK_IOS:
2446 #ifdef HAVE_COCOATOUCH
2447          {
2448             PFN_vkCreateIOSSurfaceMVK create;
2449             if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(vk->context.instance, "vkCreateIOSSurfaceMVK", create))
2450                return false;
2451             VkIOSSurfaceCreateInfoMVK surf_info;
2452 
2453             memset(&surf_info, 0, sizeof(surf_info));
2454 
2455             surf_info.sType = VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK;
2456             surf_info.pNext = NULL;
2457             surf_info.flags = 0;
2458             surf_info.pView = surface;
2459 
2460             if (create(vk->context.instance, &surf_info, NULL, &vk->vk_surface)
2461                 != VK_SUCCESS)
2462                return false;
2463          }
2464 #endif
2465          break;
2466       case VULKAN_WSI_NONE:
2467       default:
2468          return false;
2469    }
2470 
2471    /* Must create device after surface since we need to be able to query queues to use for presentation. */
2472    if (!vulkan_context_init_device(vk))
2473       return false;
2474 
2475    if (!vulkan_create_swapchain(
2476             vk, width, height, swap_interval))
2477       return false;
2478 
2479    vulkan_acquire_next_image(vk);
2480    return true;
2481 }
2482 
vulkan_destroy_swapchain(gfx_ctx_vulkan_data_t * vk)2483 static void vulkan_destroy_swapchain(gfx_ctx_vulkan_data_t *vk)
2484 {
2485    unsigned i;
2486 
2487    vulkan_emulated_mailbox_deinit(&vk->mailbox);
2488    if (vk->swapchain != VK_NULL_HANDLE)
2489    {
2490       vkDeviceWaitIdle(vk->context.device);
2491       vkDestroySwapchainKHR(vk->context.device, vk->swapchain, NULL);
2492       memset(vk->context.swapchain_images, 0, sizeof(vk->context.swapchain_images));
2493       vk->swapchain                      = VK_NULL_HANDLE;
2494       vk->context.has_acquired_swapchain = false;
2495    }
2496 
2497    for (i = 0; i < VULKAN_MAX_SWAPCHAIN_IMAGES; i++)
2498    {
2499       if (vk->context.swapchain_semaphores[i] != VK_NULL_HANDLE)
2500          vkDestroySemaphore(vk->context.device,
2501                vk->context.swapchain_semaphores[i], NULL);
2502       if (vk->context.swapchain_fences[i] != VK_NULL_HANDLE)
2503          vkDestroyFence(vk->context.device,
2504                vk->context.swapchain_fences[i], NULL);
2505       if (vk->context.swapchain_recycled_semaphores[i] != VK_NULL_HANDLE)
2506          vkDestroySemaphore(vk->context.device,
2507                vk->context.swapchain_recycled_semaphores[i], NULL);
2508       if (vk->context.swapchain_wait_semaphores[i] != VK_NULL_HANDLE)
2509          vkDestroySemaphore(vk->context.device,
2510                vk->context.swapchain_wait_semaphores[i], NULL);
2511    }
2512 
2513    if (vk->context.swapchain_acquire_semaphore != VK_NULL_HANDLE)
2514       vkDestroySemaphore(vk->context.device,
2515             vk->context.swapchain_acquire_semaphore, NULL);
2516    vk->context.swapchain_acquire_semaphore = VK_NULL_HANDLE;
2517 
2518    memset(vk->context.swapchain_semaphores, 0,
2519          sizeof(vk->context.swapchain_semaphores));
2520    memset(vk->context.swapchain_recycled_semaphores, 0,
2521          sizeof(vk->context.swapchain_recycled_semaphores));
2522    memset(vk->context.swapchain_wait_semaphores, 0,
2523          sizeof(vk->context.swapchain_wait_semaphores));
2524    memset(vk->context.swapchain_fences, 0,
2525          sizeof(vk->context.swapchain_fences));
2526    vk->context.num_recycled_acquire_semaphores = 0;
2527 }
2528 
vulkan_present(gfx_ctx_vulkan_data_t * vk,unsigned index)2529 void vulkan_present(gfx_ctx_vulkan_data_t *vk, unsigned index)
2530 {
2531    VkPresentInfoKHR present;
2532    VkResult result                 = VK_SUCCESS;
2533    VkResult err                    = VK_SUCCESS;
2534 
2535    present.sType                   = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
2536    present.pNext                   = NULL;
2537    present.waitSemaphoreCount      = 1;
2538    present.pWaitSemaphores         = &vk->context.swapchain_semaphores[index];
2539    present.swapchainCount          = 1;
2540    present.pSwapchains             = &vk->swapchain;
2541    present.pImageIndices           = &index;
2542    present.pResults                = &result;
2543 
2544    /* Better hope QueuePresent doesn't block D: */
2545 #ifdef HAVE_THREADS
2546    slock_lock(vk->context.queue_lock);
2547 #endif
2548    err = vkQueuePresentKHR(vk->context.queue, &present);
2549 
2550    /* VK_SUBOPTIMAL_KHR can be returned on
2551     * Android 10 when prerotate is not dealt with.
2552     * This is not an error we need to care about,
2553     * and we'll treat it as SUCCESS. */
2554    if (result == VK_SUBOPTIMAL_KHR)
2555       result = VK_SUCCESS;
2556    if (err == VK_SUBOPTIMAL_KHR)
2557       err = VK_SUCCESS;
2558 
2559 #ifdef WSI_HARDENING_TEST
2560    trigger_spurious_error_vkresult(&err);
2561 #endif
2562 
2563    if (err != VK_SUCCESS || result != VK_SUCCESS)
2564    {
2565       RARCH_LOG("[Vulkan]: QueuePresent failed, destroying swapchain.\n");
2566       vulkan_destroy_swapchain(vk);
2567    }
2568 
2569 #ifdef HAVE_THREADS
2570    slock_unlock(vk->context.queue_lock);
2571 #endif
2572 }
2573 
vulkan_context_destroy(gfx_ctx_vulkan_data_t * vk,bool destroy_surface)2574 void vulkan_context_destroy(gfx_ctx_vulkan_data_t *vk,
2575       bool destroy_surface)
2576 {
2577    if (!vk->context.instance)
2578       return;
2579 
2580    if (vk->context.device)
2581       vkDeviceWaitIdle(vk->context.device);
2582 
2583    vulkan_destroy_swapchain(vk);
2584 
2585    if (destroy_surface && vk->vk_surface != VK_NULL_HANDLE)
2586    {
2587       vkDestroySurfaceKHR(vk->context.instance,
2588             vk->vk_surface, NULL);
2589       vk->vk_surface = VK_NULL_HANDLE;
2590    }
2591 
2592 #ifdef VULKAN_DEBUG
2593    if (vk->context.debug_callback)
2594       vkDestroyDebugReportCallbackEXT(vk->context.instance, vk->context.debug_callback, NULL);
2595 #endif
2596 
2597    if (video_driver_is_video_cache_context())
2598    {
2599       cached_device_vk         = vk->context.device;
2600       cached_instance_vk       = vk->context.instance;
2601       cached_destroy_device_vk = vk->context.destroy_device;
2602    }
2603    else
2604    {
2605       if (vk->context.device)
2606       {
2607          vkDestroyDevice(vk->context.device, NULL);
2608          vk->context.device = NULL;
2609       }
2610       if (vk->context.instance)
2611       {
2612          if (vk->context.destroy_device)
2613             vk->context.destroy_device();
2614 
2615          vkDestroyInstance(vk->context.instance, NULL);
2616          vk->context.instance = NULL;
2617 
2618          if (vulkan_library)
2619          {
2620             dylib_close(vulkan_library);
2621             vulkan_library = NULL;
2622          }
2623       }
2624    }
2625 
2626    video_driver_set_gpu_api_devices(GFX_CTX_VULKAN_API, NULL);
2627    if (vk->gpu_list)
2628    {
2629       string_list_free(vk->gpu_list);
2630       vk->gpu_list = NULL;
2631    }
2632 }
2633 
vulkan_recycle_acquire_semaphore(struct vulkan_context * ctx,VkSemaphore sem)2634 static void vulkan_recycle_acquire_semaphore(struct vulkan_context *ctx, VkSemaphore sem)
2635 {
2636    assert(ctx->num_recycled_acquire_semaphores < VULKAN_MAX_SWAPCHAIN_IMAGES);
2637    ctx->swapchain_recycled_semaphores[ctx->num_recycled_acquire_semaphores++] = sem;
2638 }
2639 
vulkan_acquire_clear_fences(gfx_ctx_vulkan_data_t * vk)2640 static void vulkan_acquire_clear_fences(gfx_ctx_vulkan_data_t *vk)
2641 {
2642    unsigned i;
2643    for (i = 0; i < vk->context.num_swapchain_images; i++)
2644    {
2645       if (vk->context.swapchain_fences[i])
2646       {
2647          vkDestroyFence(vk->context.device,
2648                vk->context.swapchain_fences[i], NULL);
2649          vk->context.swapchain_fences[i] = VK_NULL_HANDLE;
2650       }
2651       vk->context.swapchain_fences_signalled[i] = false;
2652 
2653       if (vk->context.swapchain_wait_semaphores[i])
2654          vulkan_recycle_acquire_semaphore(&vk->context, vk->context.swapchain_wait_semaphores[i]);
2655       vk->context.swapchain_wait_semaphores[i] = VK_NULL_HANDLE;
2656    }
2657 
2658    vk->context.current_frame_index = 0;
2659 }
2660 
vulkan_get_wsi_acquire_semaphore(struct vulkan_context * ctx)2661 static VkSemaphore vulkan_get_wsi_acquire_semaphore(struct vulkan_context *ctx)
2662 {
2663    VkSemaphore sem;
2664 
2665    if (ctx->num_recycled_acquire_semaphores == 0)
2666    {
2667       VkSemaphoreCreateInfo sem_info;
2668 
2669       sem_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2670       sem_info.pNext = NULL;
2671       sem_info.flags = 0;
2672       vkCreateSemaphore(ctx->device, &sem_info, NULL,
2673             &ctx->swapchain_recycled_semaphores[ctx->num_recycled_acquire_semaphores++]);
2674    }
2675 
2676    sem               =
2677       ctx->swapchain_recycled_semaphores[--ctx->num_recycled_acquire_semaphores];
2678    ctx->swapchain_recycled_semaphores[ctx->num_recycled_acquire_semaphores] =
2679       VK_NULL_HANDLE;
2680    return sem;
2681 }
2682 
vulkan_acquire_wait_fences(gfx_ctx_vulkan_data_t * vk)2683 static void vulkan_acquire_wait_fences(gfx_ctx_vulkan_data_t *vk)
2684 {
2685    unsigned index;
2686    VkFenceCreateInfo fence_info;
2687    VkFence *next_fence             = NULL;
2688 
2689    fence_info.sType                = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
2690    fence_info.pNext                = NULL;
2691    fence_info.flags                = 0;
2692 
2693    /* Decouples the frame fence index from swapchain index. */
2694    vk->context.current_frame_index =
2695        (vk->context.current_frame_index + 1) %
2696        vk->context.num_swapchain_images;
2697 
2698    index                           = vk->context.current_frame_index;
2699    next_fence                      = &vk->context.swapchain_fences[index];
2700 
2701    if (*next_fence != VK_NULL_HANDLE)
2702    {
2703       if (vk->context.swapchain_fences_signalled[index])
2704          vkWaitForFences(vk->context.device, 1, next_fence, true, UINT64_MAX);
2705       vkResetFences(vk->context.device, 1, next_fence);
2706    }
2707    else
2708       vkCreateFence(vk->context.device, &fence_info, NULL, next_fence);
2709    vk->context.swapchain_fences_signalled[index] = false;
2710 
2711    if (vk->context.swapchain_wait_semaphores[index] != VK_NULL_HANDLE)
2712        vulkan_recycle_acquire_semaphore(&vk->context, vk->context.swapchain_wait_semaphores[index]);
2713    vk->context.swapchain_wait_semaphores[index] = VK_NULL_HANDLE;
2714 }
2715 
vulkan_create_wait_fences(gfx_ctx_vulkan_data_t * vk)2716 static void vulkan_create_wait_fences(gfx_ctx_vulkan_data_t *vk)
2717 {
2718    VkFenceCreateInfo fence_info =
2719    { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
2720 
2721    unsigned i;
2722    for (i = 0; i < vk->context.num_swapchain_images; i++)
2723    {
2724       if (!vk->context.swapchain_fences[i])
2725          vkCreateFence(vk->context.device, &fence_info, NULL,
2726                &vk->context.swapchain_fences[i]);
2727    }
2728 
2729    vk->context.current_frame_index = 0;
2730 }
2731 
vulkan_acquire_next_image(gfx_ctx_vulkan_data_t * vk)2732 void vulkan_acquire_next_image(gfx_ctx_vulkan_data_t *vk)
2733 {
2734    unsigned index;
2735    VkResult err;
2736    VkFenceCreateInfo fence_info;
2737    VkSemaphoreCreateInfo sem_info;
2738    VkFence fence                  = VK_NULL_HANDLE;
2739    VkSemaphore semaphore          = VK_NULL_HANDLE;
2740    bool is_retrying               = false;
2741 
2742    fence_info.sType               = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
2743    fence_info.pNext               = NULL;
2744    fence_info.flags               = 0;
2745 
2746    sem_info.sType                 = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2747    sem_info.pNext                 = NULL;
2748    sem_info.flags                 = 0;
2749 
2750 retry:
2751    if (vk->swapchain == VK_NULL_HANDLE)
2752    {
2753       /* We don't have a swapchain, try to create one now. */
2754       if (!vulkan_create_swapchain(vk, vk->context.swapchain_width,
2755                vk->context.swapchain_height, vk->context.swap_interval))
2756       {
2757 #ifdef VULKAN_DEBUG
2758          RARCH_ERR("[Vulkan]: Failed to create new swapchain.\n");
2759 #endif
2760          retro_sleep(20);
2761          return;
2762       }
2763 
2764       if (vk->swapchain == VK_NULL_HANDLE)
2765       {
2766          /* We still don't have a swapchain, so just fake it ... */
2767          vk->context.current_swapchain_index = 0;
2768          vk->context.current_frame_index     = 0;
2769          vulkan_acquire_clear_fences(vk);
2770          vulkan_acquire_wait_fences(vk);
2771          vk->context.invalid_swapchain       = true;
2772          return;
2773       }
2774    }
2775 
2776    retro_assert(!vk->context.has_acquired_swapchain);
2777 
2778    if (vk->emulating_mailbox)
2779    {
2780       /* Non-blocking acquire. If we don't get a swapchain frame right away,
2781        * just skip rendering to the swapchain this frame, similar to what
2782        * MAILBOX would do. */
2783       if (vk->mailbox.swapchain == VK_NULL_HANDLE)
2784          err   = VK_ERROR_OUT_OF_DATE_KHR;
2785       else
2786          err   = vulkan_emulated_mailbox_acquire_next_image(
2787                &vk->mailbox, &vk->context.current_swapchain_index);
2788    }
2789    else
2790    {
2791       if (vk->use_wsi_semaphore)
2792           semaphore = vulkan_get_wsi_acquire_semaphore(&vk->context);
2793       else
2794           vkCreateFence(vk->context.device, &fence_info, NULL, &fence);
2795 
2796       err = vkAcquireNextImageKHR(vk->context.device,
2797             vk->swapchain, UINT64_MAX,
2798             semaphore, fence, &vk->context.current_swapchain_index);
2799 
2800 #ifdef ANDROID
2801       /* VK_SUBOPTIMAL_KHR can be returned on Android 10
2802        * when prerotate is not dealt with.
2803        * This is not an error we need to care about, and
2804        * we'll treat it as SUCCESS. */
2805       if (err == VK_SUBOPTIMAL_KHR)
2806          err = VK_SUCCESS;
2807 #endif
2808    }
2809 
2810    if (err == VK_SUCCESS || err == VK_SUBOPTIMAL_KHR)
2811    {
2812       if (fence != VK_NULL_HANDLE)
2813          vkWaitForFences(vk->context.device, 1, &fence, true, UINT64_MAX);
2814       vk->context.has_acquired_swapchain = true;
2815 
2816       if (vk->context.swapchain_acquire_semaphore)
2817       {
2818 #ifdef HAVE_THREADS
2819          slock_lock(vk->context.queue_lock);
2820 #endif
2821          RARCH_LOG("[Vulkan]: Destroying stale acquire semaphore.\n");
2822          vkDeviceWaitIdle(vk->context.device);
2823          vkDestroySemaphore(vk->context.device, vk->context.swapchain_acquire_semaphore, NULL);
2824 #ifdef HAVE_THREADS
2825          slock_unlock(vk->context.queue_lock);
2826 #endif
2827       }
2828       vk->context.swapchain_acquire_semaphore = semaphore;
2829    }
2830    else
2831    {
2832       vk->context.has_acquired_swapchain = false;
2833       if (semaphore)
2834          vulkan_recycle_acquire_semaphore(&vk->context, semaphore);
2835    }
2836 
2837 #ifdef WSI_HARDENING_TEST
2838    trigger_spurious_error_vkresult(&err);
2839 #endif
2840 
2841    if (fence != VK_NULL_HANDLE)
2842       vkDestroyFence(vk->context.device, fence, NULL);
2843 
2844    switch (err)
2845    {
2846       case VK_NOT_READY:
2847       case VK_TIMEOUT:
2848          /* Do nothing. */
2849          break;
2850       case VK_ERROR_OUT_OF_DATE_KHR:
2851       case VK_SUBOPTIMAL_KHR:
2852          /* Throw away the old swapchain and try again. */
2853          vulkan_destroy_swapchain(vk);
2854 
2855          if (is_retrying)
2856          {
2857             RARCH_ERR("[Vulkan]: Swapchain is out of date, trying to create new one. Have tried multiple times ...\n");
2858             retro_sleep(10);
2859          }
2860          else
2861             RARCH_ERR("[Vulkan]: Swapchain is out of date, trying to create new one.\n");
2862          is_retrying = true;
2863          vulkan_acquire_clear_fences(vk);
2864          goto retry;
2865       default:
2866          if (err != VK_SUCCESS)
2867          {
2868             /* We are screwed, don't try anymore. Maybe it will work later. */
2869             vulkan_destroy_swapchain(vk);
2870             RARCH_ERR("[Vulkan]: Failed to acquire from swapchain (err = %d).\n",
2871                   (int)err);
2872             if (err == VK_ERROR_SURFACE_LOST_KHR)
2873                RARCH_ERR("[Vulkan]: Got VK_ERROR_SURFACE_LOST_KHR.\n");
2874             /* Force driver to reset swapchain image handles. */
2875             vk->context.invalid_swapchain = true;
2876             vulkan_acquire_clear_fences(vk);
2877             return;
2878          }
2879          break;
2880    }
2881 
2882    index = vk->context.current_swapchain_index;
2883    if (vk->context.swapchain_semaphores[index] == VK_NULL_HANDLE)
2884       vkCreateSemaphore(vk->context.device, &sem_info,
2885             NULL, &vk->context.swapchain_semaphores[index]);
2886    vulkan_acquire_wait_fences(vk);
2887 }
2888 
vulkan_create_swapchain(gfx_ctx_vulkan_data_t * vk,unsigned width,unsigned height,unsigned swap_interval)2889 bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
2890       unsigned width, unsigned height,
2891       unsigned swap_interval)
2892 {
2893    unsigned i;
2894    uint32_t format_count;
2895    uint32_t present_mode_count;
2896    uint32_t desired_swapchain_images;
2897    VkResult res;
2898    VkSurfaceCapabilitiesKHR surface_properties;
2899    VkSurfaceFormatKHR formats[256];
2900    VkPresentModeKHR present_modes[16];
2901    VkSurfaceFormatKHR format;
2902    VkExtent2D swapchain_size;
2903    VkSwapchainKHR old_swapchain;
2904    VkSurfaceTransformFlagBitsKHR pre_transform;
2905    VkSwapchainCreateInfoKHR info           = {
2906       VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR };
2907    VkPresentModeKHR swapchain_present_mode = VK_PRESENT_MODE_FIFO_KHR;
2908    settings_t                    *settings = config_get_ptr();
2909    VkCompositeAlphaFlagBitsKHR composite   = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
2910 
2911    vkDeviceWaitIdle(vk->context.device);
2912    vulkan_acquire_clear_fences(vk);
2913 
2914    vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk->context.gpu,
2915          vk->vk_surface, &surface_properties);
2916 
2917    /* Skip creation when window is minimized */
2918    if (!surface_properties.currentExtent.width &&
2919        !surface_properties.currentExtent.height)
2920       return false;
2921 
2922    if (swap_interval == 0 && vk->emulate_mailbox)
2923    {
2924       swap_interval          = 1;
2925       vk->emulating_mailbox  = true;
2926    }
2927    else
2928       vk->emulating_mailbox  = false;
2929 
2930    vk->created_new_swapchain = true;
2931 
2932    if (vk->swapchain != VK_NULL_HANDLE &&
2933          !vk->context.invalid_swapchain &&
2934          vk->context.swapchain_width == width &&
2935          vk->context.swapchain_height == height &&
2936          vk->context.swap_interval == swap_interval)
2937    {
2938       /* Do not bother creating a swapchain redundantly. */
2939 #ifdef VULKAN_DEBUG
2940       RARCH_LOG("[Vulkan]: Do not need to re-create swapchain.\n");
2941 #endif
2942       vulkan_create_wait_fences(vk);
2943 
2944       if (     vk->emulating_mailbox
2945             && vk->mailbox.swapchain == VK_NULL_HANDLE)
2946       {
2947          vulkan_emulated_mailbox_init(
2948                &vk->mailbox, vk->context.device, vk->swapchain);
2949          vk->created_new_swapchain = false;
2950          return true;
2951       }
2952       else if (
2953                !vk->emulating_mailbox
2954             &&  vk->mailbox.swapchain != VK_NULL_HANDLE)
2955       {
2956          /* We are tearing down, and entering a state
2957           * where we are supposed to have
2958           * acquired an image, so block until we have acquired. */
2959          if (!vk->context.has_acquired_swapchain)
2960          {
2961             if (vk->mailbox.swapchain == VK_NULL_HANDLE)
2962                res = VK_ERROR_OUT_OF_DATE_KHR;
2963             else
2964                res = vulkan_emulated_mailbox_acquire_next_image_blocking(
2965                      &vk->mailbox,
2966                      &vk->context.current_swapchain_index);
2967          }
2968          else
2969             res    = VK_SUCCESS;
2970 
2971          vulkan_emulated_mailbox_deinit(&vk->mailbox);
2972 
2973          if (res == VK_SUCCESS)
2974          {
2975             vk->context.has_acquired_swapchain = true;
2976             vk->created_new_swapchain          = false;
2977             return true;
2978          }
2979 
2980          /* We failed for some reason, so create a new swapchain. */
2981          vk->context.has_acquired_swapchain = false;
2982       }
2983       else
2984       {
2985          vk->created_new_swapchain = false;
2986          return true;
2987       }
2988    }
2989 
2990    vulkan_emulated_mailbox_deinit(&vk->mailbox);
2991 
2992    present_mode_count = 0;
2993    vkGetPhysicalDeviceSurfacePresentModesKHR(
2994          vk->context.gpu, vk->vk_surface,
2995          &present_mode_count, NULL);
2996    if (present_mode_count < 1 || present_mode_count > 16)
2997    {
2998       RARCH_ERR("[Vulkan]: Bogus present modes found.\n");
2999       return false;
3000    }
3001    vkGetPhysicalDeviceSurfacePresentModesKHR(
3002          vk->context.gpu, vk->vk_surface,
3003          &present_mode_count, present_modes);
3004 
3005 #ifdef VULKAN_DEBUG
3006    for (i = 0; i < present_mode_count; i++)
3007    {
3008       RARCH_LOG("[Vulkan]: Swapchain supports present mode: %u.\n",
3009             present_modes[i]);
3010    }
3011 #endif
3012 
3013    vk->context.swap_interval = swap_interval;
3014    for (i = 0; i < present_mode_count; i++)
3015    {
3016       if (!swap_interval && present_modes[i] == VK_PRESENT_MODE_MAILBOX_KHR)
3017       {
3018          swapchain_present_mode = VK_PRESENT_MODE_MAILBOX_KHR;
3019          break;
3020       }
3021       else if (!swap_interval && present_modes[i]
3022             == VK_PRESENT_MODE_IMMEDIATE_KHR)
3023       {
3024          swapchain_present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR;
3025          break;
3026       }
3027       else if (swap_interval && present_modes[i] == VK_PRESENT_MODE_FIFO_KHR)
3028       {
3029          /* Kind of tautological since FIFO must always be present. */
3030          swapchain_present_mode = VK_PRESENT_MODE_FIFO_KHR;
3031          break;
3032       }
3033    }
3034 
3035 #ifdef VULKAN_DEBUG
3036    RARCH_LOG("[Vulkan]: Creating swapchain with present mode: %u\n",
3037          (unsigned)swapchain_present_mode);
3038 #endif
3039 
3040    vkGetPhysicalDeviceSurfaceFormatsKHR(vk->context.gpu,
3041          vk->vk_surface, &format_count, NULL);
3042    vkGetPhysicalDeviceSurfaceFormatsKHR(vk->context.gpu,
3043          vk->vk_surface, &format_count, formats);
3044 
3045    format.format = VK_FORMAT_UNDEFINED;
3046    if (format_count == 1 && formats[0].format == VK_FORMAT_UNDEFINED)
3047    {
3048       format        = formats[0];
3049       format.format = VK_FORMAT_B8G8R8A8_UNORM;
3050    }
3051    else
3052    {
3053       if (format_count == 0)
3054       {
3055          RARCH_ERR("[Vulkan]: Surface has no formats.\n");
3056          return false;
3057       }
3058 
3059       for (i = 0; i < format_count; i++)
3060       {
3061          if (
3062                formats[i].format == VK_FORMAT_R8G8B8A8_UNORM ||
3063                formats[i].format == VK_FORMAT_B8G8R8A8_UNORM ||
3064                formats[i].format == VK_FORMAT_A8B8G8R8_UNORM_PACK32)
3065             format = formats[i];
3066       }
3067 
3068       if (format.format == VK_FORMAT_UNDEFINED)
3069          format = formats[0];
3070    }
3071 
3072    if (surface_properties.currentExtent.width == -1)
3073    {
3074       swapchain_size.width     = width;
3075       swapchain_size.height    = height;
3076    }
3077    else
3078       swapchain_size           = surface_properties.currentExtent;
3079 
3080 #ifdef WSI_HARDENING_TEST
3081    if (trigger_spurious_error())
3082    {
3083       surface_properties.maxImageExtent.width = 0;
3084       surface_properties.maxImageExtent.height = 0;
3085       surface_properties.minImageExtent.width = 0;
3086       surface_properties.minImageExtent.height = 0;
3087    }
3088 #endif
3089 
3090    /* Clamp swapchain size to boundaries. */
3091    if (swapchain_size.width > surface_properties.maxImageExtent.width)
3092       swapchain_size.width = surface_properties.maxImageExtent.width;
3093    if (swapchain_size.width < surface_properties.minImageExtent.width)
3094       swapchain_size.width = surface_properties.minImageExtent.width;
3095    if (swapchain_size.height > surface_properties.maxImageExtent.height)
3096       swapchain_size.height = surface_properties.maxImageExtent.height;
3097    if (swapchain_size.height < surface_properties.minImageExtent.height)
3098       swapchain_size.height = surface_properties.minImageExtent.height;
3099 
3100    if (swapchain_size.width == 0 && swapchain_size.height == 0)
3101    {
3102       /* Cannot create swapchain yet, try again later. */
3103       if (vk->swapchain != VK_NULL_HANDLE)
3104          vkDestroySwapchainKHR(vk->context.device, vk->swapchain, NULL);
3105       vk->swapchain                    = VK_NULL_HANDLE;
3106       vk->context.swapchain_width      = width;
3107       vk->context.swapchain_height     = height;
3108       vk->context.num_swapchain_images = 1;
3109 
3110       memset(vk->context.swapchain_images, 0, sizeof(vk->context.swapchain_images));
3111       RARCH_LOG("[Vulkan]: Cannot create a swapchain yet. Will try again later ...\n");
3112       return true;
3113    }
3114 
3115 #ifdef VULKAN_DEBUG
3116    RARCH_LOG("[Vulkan]: Using swapchain size %u x %u.\n",
3117          swapchain_size.width, swapchain_size.height);
3118 #endif
3119 
3120    /* Unless we have other reasons to clamp, we should prefer 3 images.
3121     * We hard sync against the swapchain, so if we have 2 images,
3122     * we would be unable to overlap CPU and GPU, which can get very slow
3123     * for GPU-rendered cores. */
3124    desired_swapchain_images = settings->uints.video_max_swapchain_images;
3125 
3126    /* Clamp images requested to what is supported by the implementation. */
3127    if (desired_swapchain_images < surface_properties.minImageCount)
3128       desired_swapchain_images = surface_properties.minImageCount;
3129 
3130    if ((surface_properties.maxImageCount > 0)
3131          && (desired_swapchain_images > surface_properties.maxImageCount))
3132       desired_swapchain_images = surface_properties.maxImageCount;
3133 
3134    if (surface_properties.supportedTransforms
3135          & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
3136       pre_transform            = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
3137    else
3138       pre_transform            = surface_properties.currentTransform;
3139 
3140    if (surface_properties.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR)
3141       composite = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
3142    else if (surface_properties.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)
3143       composite = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
3144    else if (surface_properties.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
3145       composite = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
3146    else if (surface_properties.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
3147       composite = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
3148 
3149    old_swapchain               = vk->swapchain;
3150 
3151    info.surface                = vk->vk_surface;
3152    info.minImageCount          = desired_swapchain_images;
3153    info.imageFormat            = format.format;
3154    info.imageColorSpace        = format.colorSpace;
3155    info.imageExtent.width      = swapchain_size.width;
3156    info.imageExtent.height     = swapchain_size.height;
3157    info.imageArrayLayers       = 1;
3158    info.imageSharingMode       = VK_SHARING_MODE_EXCLUSIVE;
3159    info.preTransform           = pre_transform;
3160    info.compositeAlpha         = composite;
3161    info.presentMode            = swapchain_present_mode;
3162    info.clipped                = true;
3163    info.oldSwapchain           = old_swapchain;
3164    info.imageUsage             = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
3165       | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
3166 
3167 #ifdef _WIN32
3168    /* On Windows, do not try to reuse the swapchain.
3169     * It causes a lot of issues on nVidia for some reason. */
3170    info.oldSwapchain = VK_NULL_HANDLE;
3171    if (old_swapchain != VK_NULL_HANDLE)
3172       vkDestroySwapchainKHR(vk->context.device, old_swapchain, NULL);
3173 #endif
3174 
3175    if (vkCreateSwapchainKHR(vk->context.device,
3176             &info, NULL, &vk->swapchain) != VK_SUCCESS)
3177    {
3178       RARCH_ERR("[Vulkan]: Failed to create swapchain.\n");
3179       return false;
3180    }
3181 
3182 #ifndef _WIN32
3183    if (old_swapchain != VK_NULL_HANDLE)
3184       vkDestroySwapchainKHR(vk->context.device, old_swapchain, NULL);
3185 #endif
3186 
3187    vk->context.swapchain_width  = swapchain_size.width;
3188    vk->context.swapchain_height = swapchain_size.height;
3189 
3190    /* Make sure we create a backbuffer format that is as we expect. */
3191    switch (format.format)
3192    {
3193       case VK_FORMAT_B8G8R8A8_SRGB:
3194          vk->context.swapchain_format  = VK_FORMAT_B8G8R8A8_UNORM;
3195          vk->context.swapchain_is_srgb = true;
3196          break;
3197 
3198       case VK_FORMAT_R8G8B8A8_SRGB:
3199          vk->context.swapchain_format  = VK_FORMAT_R8G8B8A8_UNORM;
3200          vk->context.swapchain_is_srgb = true;
3201          break;
3202 
3203       case VK_FORMAT_R8G8B8_SRGB:
3204          vk->context.swapchain_format  = VK_FORMAT_R8G8B8_UNORM;
3205          vk->context.swapchain_is_srgb = true;
3206          break;
3207 
3208       case VK_FORMAT_B8G8R8_SRGB:
3209          vk->context.swapchain_format  = VK_FORMAT_B8G8R8_UNORM;
3210          vk->context.swapchain_is_srgb = true;
3211          break;
3212 
3213       default:
3214          vk->context.swapchain_format  = format.format;
3215          break;
3216    }
3217 
3218    vkGetSwapchainImagesKHR(vk->context.device, vk->swapchain,
3219          &vk->context.num_swapchain_images, NULL);
3220    vkGetSwapchainImagesKHR(vk->context.device, vk->swapchain,
3221          &vk->context.num_swapchain_images, vk->context.swapchain_images);
3222 
3223 #ifdef VULKAN_DEBUG
3224    RARCH_LOG("[Vulkan]: Got %u swapchain images.\n",
3225          vk->context.num_swapchain_images);
3226 #endif
3227 
3228    /* Force driver to reset swapchain image handles. */
3229    vk->context.invalid_swapchain      = true;
3230    vk->context.has_acquired_swapchain = false;
3231    vulkan_create_wait_fences(vk);
3232 
3233    if (vk->emulating_mailbox)
3234       vulkan_emulated_mailbox_init(&vk->mailbox, vk->context.device, vk->swapchain);
3235 
3236    return true;
3237 }
3238 
vulkan_initialize_render_pass(VkDevice device,VkFormat format,VkRenderPass * render_pass)3239 void vulkan_initialize_render_pass(VkDevice device, VkFormat format,
3240       VkRenderPass *render_pass)
3241 {
3242    VkAttachmentReference color_ref;
3243    VkRenderPassCreateInfo rp_info;
3244    VkAttachmentDescription attachment;
3245    VkSubpassDescription subpass       = {0};
3246 
3247    rp_info.sType                = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
3248    rp_info.pNext                = NULL;
3249    rp_info.flags                = 0;
3250    rp_info.attachmentCount      = 1;
3251    rp_info.pAttachments         = &attachment;
3252    rp_info.subpassCount         = 1;
3253    rp_info.pSubpasses           = &subpass;
3254    rp_info.dependencyCount      = 0;
3255    rp_info.pDependencies        = NULL;
3256 
3257    color_ref.attachment         = 0;
3258    color_ref.layout             = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
3259 
3260    /* We will always write to the entire framebuffer,
3261     * so we don't really need to clear. */
3262    attachment.flags             = 0;
3263    attachment.format            = format;
3264    attachment.samples           = VK_SAMPLE_COUNT_1_BIT;
3265    attachment.loadOp            = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
3266    attachment.storeOp           = VK_ATTACHMENT_STORE_OP_STORE;
3267    attachment.stencilLoadOp     = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
3268    attachment.stencilStoreOp    = VK_ATTACHMENT_STORE_OP_DONT_CARE;
3269    attachment.initialLayout     = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
3270    attachment.finalLayout       = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
3271 
3272    subpass.pipelineBindPoint    = VK_PIPELINE_BIND_POINT_GRAPHICS;
3273    subpass.colorAttachmentCount = 1;
3274    subpass.pColorAttachments    = &color_ref;
3275 
3276    vkCreateRenderPass(device, &rp_info, NULL, render_pass);
3277 }
3278 
vulkan_set_uniform_buffer(VkDevice device,VkDescriptorSet set,unsigned binding,VkBuffer buffer,VkDeviceSize offset,VkDeviceSize range)3279 void vulkan_set_uniform_buffer(
3280       VkDevice device,
3281       VkDescriptorSet set,
3282       unsigned binding,
3283       VkBuffer buffer,
3284       VkDeviceSize offset,
3285       VkDeviceSize range)
3286 {
3287    VkWriteDescriptorSet write;
3288    VkDescriptorBufferInfo buffer_info;
3289 
3290    buffer_info.buffer         = buffer;
3291    buffer_info.offset         = offset;
3292    buffer_info.range          = range;
3293 
3294    write.sType                = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
3295    write.pNext                = NULL;
3296    write.dstSet               = set;
3297    write.dstBinding           = binding;
3298    write.dstArrayElement      = 0;
3299    write.descriptorCount      = 1;
3300    write.descriptorType       = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
3301    write.pImageInfo           = NULL;
3302    write.pBufferInfo          = &buffer_info;
3303    write.pTexelBufferView     = NULL;
3304 
3305    vkUpdateDescriptorSets(device, 1, &write, 0, NULL);
3306 }
3307 
vulkan_framebuffer_generate_mips(VkFramebuffer framebuffer,VkImage image,struct Size2D size,VkCommandBuffer cmd,unsigned levels)3308 void vulkan_framebuffer_generate_mips(
3309       VkFramebuffer framebuffer,
3310       VkImage image,
3311       struct Size2D size,
3312       VkCommandBuffer cmd,
3313       unsigned levels
3314       )
3315 {
3316    unsigned i;
3317    /* This is run every frame, so make sure
3318     * we aren't opting into the "lazy" way of doing this. :) */
3319    VkImageMemoryBarrier barriers[2] = {
3320       { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER },
3321       { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER },
3322    };
3323 
3324    /* First, transfer the input mip level to TRANSFER_SRC_OPTIMAL.
3325     * This should allow the surface to stay compressed.
3326     * All subsequent mip-layers are now transferred into DST_OPTIMAL from
3327     * UNDEFINED at this point.
3328     */
3329 
3330    /* Input */
3331    barriers[0].srcAccessMask                 = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
3332    barriers[0].dstAccessMask                 = VK_ACCESS_TRANSFER_READ_BIT;
3333    barriers[0].oldLayout                     = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
3334    barriers[0].newLayout                     = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
3335    barriers[0].srcQueueFamilyIndex           = VK_QUEUE_FAMILY_IGNORED;
3336    barriers[0].dstQueueFamilyIndex           = VK_QUEUE_FAMILY_IGNORED;
3337    barriers[0].image                         = image;
3338    barriers[0].subresourceRange.aspectMask   = VK_IMAGE_ASPECT_COLOR_BIT;
3339    barriers[0].subresourceRange.baseMipLevel = 0;
3340    barriers[0].subresourceRange.levelCount   = 1;
3341    barriers[0].subresourceRange.layerCount   = VK_REMAINING_ARRAY_LAYERS;
3342 
3343    /* The rest of the mip chain */
3344    barriers[1].srcAccessMask                 = 0;
3345    barriers[1].dstAccessMask                 = VK_ACCESS_TRANSFER_WRITE_BIT;
3346    barriers[1].oldLayout                     = VK_IMAGE_LAYOUT_UNDEFINED;
3347    barriers[1].newLayout                     = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
3348    barriers[1].srcQueueFamilyIndex           = VK_QUEUE_FAMILY_IGNORED;
3349    barriers[1].dstQueueFamilyIndex           = VK_QUEUE_FAMILY_IGNORED;
3350    barriers[1].image                         = image;
3351    barriers[1].subresourceRange.aspectMask   = VK_IMAGE_ASPECT_COLOR_BIT;
3352    barriers[1].subresourceRange.baseMipLevel = 1;
3353    barriers[1].subresourceRange.levelCount   = VK_REMAINING_MIP_LEVELS;
3354    barriers[1].subresourceRange.layerCount   = VK_REMAINING_ARRAY_LAYERS;
3355 
3356    vkCmdPipelineBarrier(cmd,
3357          VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
3358          VK_PIPELINE_STAGE_TRANSFER_BIT,
3359          false,
3360          0,
3361          NULL,
3362          0,
3363          NULL,
3364          2,
3365          barriers);
3366 
3367    for (i = 1; i < levels; i++)
3368    {
3369       unsigned src_width, src_height, target_width, target_height;
3370       VkImageBlit blit_region = {{0}};
3371 
3372       /* For subsequent passes, we have to transition
3373        * from DST_OPTIMAL to SRC_OPTIMAL,
3374        * but only do so one mip-level at a time. */
3375       if (i > 1)
3376       {
3377          barriers[0].srcAccessMask                 = VK_ACCESS_TRANSFER_WRITE_BIT;
3378          barriers[0].dstAccessMask                 = VK_ACCESS_TRANSFER_READ_BIT;
3379          barriers[0].subresourceRange.baseMipLevel = i - 1;
3380          barriers[0].subresourceRange.levelCount   = 1;
3381          barriers[0].oldLayout                     = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
3382          barriers[0].newLayout                     = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
3383 
3384          vkCmdPipelineBarrier(cmd,
3385                VK_PIPELINE_STAGE_TRANSFER_BIT,
3386                VK_PIPELINE_STAGE_TRANSFER_BIT,
3387                false,
3388                0,
3389                NULL,
3390                0,
3391                NULL,
3392                1,
3393                barriers);
3394       }
3395 
3396       src_width                                 = MAX(size.width >> (i - 1), 1u);
3397       src_height                                = MAX(size.height >> (i - 1), 1u);
3398       target_width                              = MAX(size.width >> i, 1u);
3399       target_height                             = MAX(size.height >> i, 1u);
3400 
3401       blit_region.srcSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
3402       blit_region.srcSubresource.mipLevel       = i - 1;
3403       blit_region.srcSubresource.baseArrayLayer = 0;
3404       blit_region.srcSubresource.layerCount     = 1;
3405       blit_region.dstSubresource                = blit_region.srcSubresource;
3406       blit_region.dstSubresource.mipLevel       = i;
3407       blit_region.srcOffsets[1].x               = src_width;
3408       blit_region.srcOffsets[1].y               = src_height;
3409       blit_region.srcOffsets[1].z               = 1;
3410       blit_region.dstOffsets[1].x               = target_width;
3411       blit_region.dstOffsets[1].y               = target_height;
3412       blit_region.dstOffsets[1].z               = 1;
3413 
3414       vkCmdBlitImage(cmd,
3415             image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
3416             image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
3417             1, &blit_region, VK_FILTER_LINEAR);
3418    }
3419 
3420    /* We are now done, and we have all mip-levels except
3421     * the last in TRANSFER_SRC_OPTIMAL,
3422     * and the last one still on TRANSFER_DST_OPTIMAL,
3423     * so do a final barrier which
3424     * moves everything to SHADER_READ_ONLY_OPTIMAL in
3425     * one go along with the execution barrier to next pass.
3426     * Read-to-read memory barrier, so only need execution
3427     * barrier for first transition.
3428     */
3429    barriers[0].srcAccessMask                 = VK_ACCESS_TRANSFER_READ_BIT;
3430    barriers[0].dstAccessMask                 = VK_ACCESS_SHADER_READ_BIT;
3431    barriers[0].subresourceRange.baseMipLevel = 0;
3432    barriers[0].subresourceRange.levelCount   = levels - 1;
3433    barriers[0].oldLayout                     = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
3434    barriers[0].newLayout                     = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
3435 
3436    /* This is read-after-write barrier. */
3437    barriers[1].srcAccessMask                 = VK_ACCESS_TRANSFER_WRITE_BIT;
3438    barriers[1].dstAccessMask                 = VK_ACCESS_SHADER_READ_BIT;
3439    barriers[1].subresourceRange.baseMipLevel = levels - 1;
3440    barriers[1].subresourceRange.levelCount   = 1;
3441    barriers[1].oldLayout                     = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
3442    barriers[1].newLayout                     = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
3443 
3444    vkCmdPipelineBarrier(cmd,
3445          VK_PIPELINE_STAGE_TRANSFER_BIT,
3446          VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
3447          false,
3448          0,
3449          NULL,
3450          0,
3451          NULL,
3452          2, barriers);
3453 
3454    /* Next pass will wait for ALL_GRAPHICS_BIT, and since
3455     * we have dstStage as FRAGMENT_SHADER,
3456     * the dependency chain will ensure we don't start
3457     * next pass until the mipchain is complete. */
3458 }
3459 
vulkan_framebuffer_copy(VkImage image,struct Size2D size,VkCommandBuffer cmd,VkImage src_image,VkImageLayout src_layout)3460 void vulkan_framebuffer_copy(VkImage image,
3461       struct Size2D size,
3462       VkCommandBuffer cmd,
3463       VkImage src_image, VkImageLayout src_layout)
3464 {
3465    VkImageCopy region;
3466 
3467    VULKAN_IMAGE_LAYOUT_TRANSITION_LEVELS(cmd, image,VK_REMAINING_MIP_LEVELS,
3468          VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
3469          0, VK_ACCESS_TRANSFER_WRITE_BIT,
3470          VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
3471          VK_PIPELINE_STAGE_TRANSFER_BIT,
3472          VK_QUEUE_FAMILY_IGNORED,
3473          VK_QUEUE_FAMILY_IGNORED);
3474 
3475    region.srcSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
3476    region.srcSubresource.mipLevel       = 0;
3477    region.srcSubresource.baseArrayLayer = 0;
3478    region.srcSubresource.layerCount     = 1;
3479    region.srcOffset.x                   = 0;
3480    region.srcOffset.y                   = 0;
3481    region.srcOffset.z                   = 0;
3482    region.dstSubresource                = region.srcSubresource;
3483    region.dstOffset.x                   = 0;
3484    region.dstOffset.y                   = 0;
3485    region.dstOffset.z                   = 0;
3486    region.extent.width                  = size.width;
3487    region.extent.height                 = size.height;
3488    region.extent.depth                  = 1;
3489 
3490    vkCmdCopyImage(cmd,
3491          src_image, src_layout,
3492          image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
3493          1, &region);
3494 
3495    VULKAN_IMAGE_LAYOUT_TRANSITION_LEVELS(cmd,
3496          image,
3497          VK_REMAINING_MIP_LEVELS,
3498          VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
3499          VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
3500          VK_ACCESS_TRANSFER_WRITE_BIT,
3501          VK_ACCESS_SHADER_READ_BIT,
3502          VK_PIPELINE_STAGE_TRANSFER_BIT,
3503          VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
3504          VK_QUEUE_FAMILY_IGNORED,
3505          VK_QUEUE_FAMILY_IGNORED);
3506 }
3507 
vulkan_framebuffer_clear(VkImage image,VkCommandBuffer cmd)3508 void vulkan_framebuffer_clear(VkImage image, VkCommandBuffer cmd)
3509 {
3510    VkClearColorValue color;
3511    VkImageSubresourceRange range;
3512 
3513    VULKAN_IMAGE_LAYOUT_TRANSITION_LEVELS(cmd,
3514          image,
3515          VK_REMAINING_MIP_LEVELS,
3516          VK_IMAGE_LAYOUT_UNDEFINED,
3517          VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
3518          0,
3519          VK_ACCESS_TRANSFER_WRITE_BIT,
3520          VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
3521          VK_PIPELINE_STAGE_TRANSFER_BIT,
3522          VK_QUEUE_FAMILY_IGNORED,
3523          VK_QUEUE_FAMILY_IGNORED);
3524 
3525    color.float32[0]     = 0.0f;
3526    color.float32[1]     = 0.0f;
3527    color.float32[2]     = 0.0f;
3528    color.float32[3]     = 0.0f;
3529    range.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
3530    range.baseMipLevel   = 0;
3531    range.levelCount     = 1;
3532    range.baseArrayLayer = 0;
3533    range.layerCount     = 1;
3534 
3535    vkCmdClearColorImage(cmd,
3536          image,
3537          VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
3538          &color,
3539          1,
3540          &range);
3541 
3542    VULKAN_IMAGE_LAYOUT_TRANSITION_LEVELS(cmd,
3543          image,
3544          VK_REMAINING_MIP_LEVELS,
3545          VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
3546          VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
3547          VK_ACCESS_TRANSFER_WRITE_BIT,
3548          VK_ACCESS_SHADER_READ_BIT,
3549          VK_PIPELINE_STAGE_TRANSFER_BIT,
3550          VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
3551          VK_QUEUE_FAMILY_IGNORED,
3552          VK_QUEUE_FAMILY_IGNORED);
3553 }
3554