@@ -1933,6 +1933,12 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
19331933 bool vsync = settings -> bools .video_vsync ;
19341934 bool adaptive_vsync = settings -> bools .video_adaptive_vsync ;
19351935
1936+ /* Bounds for safe copies into context arrays (minimal change). */
1937+ const uint32_t ctx_present_modes_cap =
1938+ (uint32_t )(sizeof (vk -> context .present_modes ) / sizeof (vk -> context .present_modes [0 ]));
1939+ const uint32_t ctx_swap_images_cap =
1940+ (uint32_t )(sizeof (vk -> context .swapchain_images ) / sizeof (vk -> context .swapchain_images [0 ]));
1941+
19361942 format .format = VK_FORMAT_UNDEFINED ;
19371943 format .colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR ;
19381944
@@ -1945,7 +1951,19 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
19451951 /* Skip creation when window is minimized */
19461952 if ( !surface_properties .currentExtent .width
19471953 && !surface_properties .currentExtent .height )
1948- return false;
1954+ {
1955+ /* tear down existing swapchain and report handled. */
1956+ if (vk -> swapchain != VK_NULL_HANDLE )
1957+ vkDestroySwapchainKHR (vk -> context .device , vk -> swapchain , NULL );
1958+ vk -> swapchain = VK_NULL_HANDLE ;
1959+ vk -> context .swapchain_width = width ;
1960+ vk -> context .swapchain_height = height ;
1961+ vk -> context .num_swapchain_images = 0 ;
1962+ memset (vk -> context .swapchain_images , 0 , sizeof (vk -> context .swapchain_images ));
1963+ vk -> context .flags &= ~VK_CTX_FLAG_HAS_ACQUIRED_SWAPCHAIN ;
1964+ RARCH_DBG ("[Vulkan] Window minimized; postponed swapchain creation.\n" );
1965+ return true;
1966+ }
19491967
19501968 if ( (swap_interval == 0 )
19511969 && (vk -> flags & VK_DATA_FLAG_EMULATE_MAILBOX )
@@ -2028,8 +2046,14 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
20282046
20292047 vk -> context .swap_interval = swap_interval ;
20302048
2031- for (i = 0 ; i < present_mode_count ; i ++ )
2032- vk -> context .present_modes [i ] = present_modes [i ];
2049+ /* copy only what fits in context array. */
2050+ {
2051+ uint32_t copy_count = present_mode_count ;
2052+ if (copy_count > ctx_present_modes_cap )
2053+ copy_count = ctx_present_modes_cap ;
2054+ for (i = 0 ; i < copy_count ; i ++ )
2055+ vk -> context .present_modes [i ] = present_modes [i ];
2056+ }
20332057
20342058 /* Prefer IMMEDIATE without vsync */
20352059 for (i = 0 ; i < present_mode_count ; i ++ )
@@ -2107,10 +2131,23 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
21072131 }
21082132 }
21092133
2110- vkGetPhysicalDeviceSurfaceFormatsKHR (vk -> context .gpu ,
2111- vk -> vk_surface , & format_count , NULL );
2112- vkGetPhysicalDeviceSurfaceFormatsKHR (vk -> context .gpu ,
2113- vk -> vk_surface , & format_count , formats );
2134+ {
2135+ VkResult r ;
2136+ r = vkGetPhysicalDeviceSurfaceFormatsKHR (vk -> context .gpu ,
2137+ vk -> vk_surface , & format_count , NULL );
2138+ if (r != VK_SUCCESS || format_count == 0 )
2139+ {
2140+ RARCH_ERR ("[Vulkan] Surface has no formats (r=%d, count=%u).\n" , r , format_count );
2141+ return false;
2142+ }
2143+ r = vkGetPhysicalDeviceSurfaceFormatsKHR (vk -> context .gpu ,
2144+ vk -> vk_surface , & format_count , formats );
2145+ if (r != VK_SUCCESS )
2146+ {
2147+ RARCH_ERR ("[Vulkan] Failed to get surface formats: %d\n" , r );
2148+ return false;
2149+ }
2150+ }
21142151
21152152 format .format = VK_FORMAT_UNDEFINED ;
21162153 if ( format_count == 1
@@ -2213,9 +2250,9 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
22132250 vk -> swapchain = VK_NULL_HANDLE ;
22142251 vk -> context .swapchain_width = width ;
22152252 vk -> context .swapchain_height = height ;
2216- vk -> context .num_swapchain_images = 1 ;
2217-
2253+ vk -> context .num_swapchain_images = 0 ;
22182254 memset (vk -> context .swapchain_images , 0 , sizeof (vk -> context .swapchain_images ));
2255+ vk -> context .flags &= ~VK_CTX_FLAG_HAS_ACQUIRED_SWAPCHAIN ;
22192256 RARCH_DBG ("[Vulkan] Cannot create a swapchain yet. Will try again later...\n" );
22202257 return true;
22212258 }
@@ -2226,11 +2263,9 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
22262263 * for GPU-rendered cores. */
22272264 desired_swapchain_images = settings -> uints .video_max_swapchain_images ;
22282265
2229- /* We don't clamp the number of images requested to what is reported
2230- * as supported by the implementation in surface_properties.minImageCount,
2231- * because MESA always reports a minImageCount of 4, but 3 and 2 work
2232- * perfectly well, even if it's out of spec. */
2233-
2266+ /* Ensure desired image count respects min/max. */
2267+ if (desired_swapchain_images < surface_properties .minImageCount )
2268+ desired_swapchain_images = surface_properties .minImageCount ;
22342269 if ( (surface_properties .maxImageCount > 0 )
22352270 && (desired_swapchain_images > surface_properties .maxImageCount ))
22362271 desired_swapchain_images = surface_properties .maxImageCount ;
@@ -2262,25 +2297,35 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
22622297 info .imageExtent .width = swapchain_size .width ;
22632298 info .imageExtent .height = swapchain_size .height ;
22642299 info .imageArrayLayers = 1 ;
2265- info .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
2266- | VK_IMAGE_USAGE_TRANSFER_SRC_BIT
2267- | VK_IMAGE_USAGE_TRANSFER_DST_BIT
2268- | VK_IMAGE_USAGE_SAMPLED_BIT ;
2300+
2301+ /* Validate usage bits against supportedUsageFlags, but keep essential bit. */
2302+ {
2303+ VkImageUsageFlags desired_usage =
2304+ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
2305+ | VK_IMAGE_USAGE_TRANSFER_SRC_BIT
2306+ | VK_IMAGE_USAGE_TRANSFER_DST_BIT
2307+ | VK_IMAGE_USAGE_SAMPLED_BIT ;
2308+ VkImageUsageFlags supported = surface_properties .supportedUsageFlags ;
2309+ VkImageUsageFlags final_usage = desired_usage & supported ;
2310+
2311+ if (!(supported & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ))
2312+ {
2313+ RARCH_ERR ("[Vulkan] Surface does not support COLOR_ATTACHMENT usage.\n" );
2314+ return false;
2315+ }
2316+
2317+ final_usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ;
2318+ info .imageUsage = final_usage ;
2319+ }
2320+
22692321 info .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE ;
22702322 info .queueFamilyIndexCount = 0 ;
22712323 info .pQueueFamilyIndices = NULL ;
22722324 info .preTransform = pre_transform ;
22732325 info .compositeAlpha = composite ;
22742326 info .presentMode = swapchain_present_mode ;
22752327 info .clipped = VK_TRUE ;
2276- info .oldSwapchain = old_swapchain ;
2277-
2278- /* Only destroy old swapchain before creation on non-Android. */
2279- #ifndef ANDROID
2280- info .oldSwapchain = VK_NULL_HANDLE ;
2281- if (old_swapchain != VK_NULL_HANDLE )
2282- vkDestroySwapchainKHR (vk -> context .device , old_swapchain , NULL );
2283- #endif
2328+ info .oldSwapchain = old_swapchain ; /* keep old alive until after creation */
22842329
22852330 if (vkCreateSwapchainKHR (vk -> context .device ,
22862331 & info , NULL , & vk -> swapchain ) != VK_SUCCESS )
@@ -2289,11 +2334,9 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
22892334 return false;
22902335 }
22912336
2292- /* On Android, now that creation succeeded, destroy the old swapchain. */
2293- #ifdef ANDROID
2337+ /* Now safe to destroy the old one. */
22942338 if (old_swapchain != VK_NULL_HANDLE )
22952339 vkDestroySwapchainKHR (vk -> context .device , old_swapchain , NULL );
2296- #endif
22972340
22982341 vk -> context .swapchain_width = swapchain_size .width ;
22992342 vk -> context .swapchain_height = swapchain_size .height ;
@@ -2326,13 +2369,31 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
23262369
23272370 default :
23282371 vk -> context .swapchain_format = format .format ;
2372+ vk -> context .flags &= ~VK_CTX_FLAG_SWAPCHAIN_IS_SRGB ;
23292373 break ;
23302374 }
23312375
2332- vkGetSwapchainImagesKHR (vk -> context .device , vk -> swapchain ,
2333- & vk -> context .num_swapchain_images , NULL );
2334- vkGetSwapchainImagesKHR (vk -> context .device , vk -> swapchain ,
2335- & vk -> context .num_swapchain_images , vk -> context .swapchain_images );
2376+ /* Get image count first, clamp to capacity, then fetch. */
2377+ {
2378+ VkResult r ;
2379+ uint32_t count = 0 ;
2380+ r = vkGetSwapchainImagesKHR (vk -> context .device , vk -> swapchain , & count , NULL );
2381+ if (r != VK_SUCCESS || count == 0 )
2382+ {
2383+ RARCH_ERR ("[Vulkan] Failed to query swapchain images: %d (count=%u)\n" , r , count );
2384+ return false;
2385+ }
2386+ if (count > ctx_swap_images_cap )
2387+ count = ctx_swap_images_cap ;
2388+ r = vkGetSwapchainImagesKHR (vk -> context .device , vk -> swapchain ,
2389+ & count , vk -> context .swapchain_images );
2390+ if (r != VK_SUCCESS )
2391+ {
2392+ RARCH_ERR ("[Vulkan] Failed to get swapchain images: %d\n" , r );
2393+ return false;
2394+ }
2395+ vk -> context .num_swapchain_images = count ;
2396+ }
23362397
23372398 if (old_swapchain == VK_NULL_HANDLE )
23382399 RARCH_LOG ("[Vulkan] Got %u swapchain images.\n" ,
@@ -2346,9 +2407,11 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
23462407 if (vk -> flags & VK_DATA_FLAG_EMULATING_MAILBOX )
23472408 vulkan_emulated_mailbox_init (& vk -> mailbox , vk -> context .device , vk -> swapchain );
23482409
2410+ vk -> flags &= ~VK_DATA_FLAG_CREATED_NEW_SWAPCHAIN ;
23492411 return true;
23502412}
23512413
2414+
23522415bool vulkan_context_init (gfx_ctx_vulkan_data_t * vk ,
23532416 enum vulkan_wsi_type type )
23542417{
0 commit comments