Vulkan: Four small correctness fixes found while reviewing Common/GPU

* TransitionDepthStencilImageAuto set dstAccessMask to TRANSFER_READ_BIT for
  TRANSFER_DST_OPTIMAL. The color path and this function's own source-side switch
  both use TRANSFER_WRITE_BIT - it's a copy-paste from the TRANSFER_SRC case two
  lines up. Every depth copy and blit went through it.

* VulkanMayBeAvailable's per-device loop did anyGood = !blacklisted, overwriting
  the verdict from earlier devices, so a blacklisted GPU enumerated after a good
  one hid the Vulkan backend entirely. Hybrid-GPU machines are exactly what the
  blacklist targets.

* The instance extension scan stopped as soon as it found the platform surface
  extension, so a driver reporting that before VK_KHR_surface made us give up
  with "Platform surface extension not found". Enumeration order isn't specified.

* CreateDevice only logged when vkCreateDevice failed, then carried on to report
  success, call VulkanSetAvailable(true) and build a VMA allocator on a null
  device behind an assert that's live in release builds.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Vd8ntC2brCUtCrDJMqLbs8
This commit is contained in:
Henrik RydgårdandClaude Opus 5 committed 2026-08-28 23:27:13 +02:00
1 parent f9315e9bc1
commit 14ce62af9e
3 files changed
+12 -6

No files matched your search

+1 -1
View File
@@ -212,7 +212,7 @@ void VulkanBarrierBatch::TransitionDepthStencilImageAuto(
dstStageMask_ |= VK_PIPELINE_STAGE_TRANSFER_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
dstStageMask_ |= VK_PIPELINE_STAGE_TRANSFER_BIT;
break;
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
+6 -2
View File
@@ -907,9 +907,13 @@ VkResult VulkanContext::CreateDevice(int physical_device, const std::vector<cons
if (res != VK_SUCCESS) {
init_error_ = "Unable to create Vulkan device";
ERROR_LOG(Log::G3D, "%s", init_error_.c_str());
} else {
VulkanLoadDeviceFunctions(device_, extensionsLookup_, vulkanDeviceApiVersion_);
// Don't fall through - there's nothing below that makes sense without a device, and creating the
// VMA allocator on a null one asserts. The caller falls back to another backend on failure.
return res;
}
VulkanLoadDeviceFunctions(device_, extensionsLookup_, vulkanDeviceApiVersion_);
INFO_LOG(Log::G3D, "Vulkan Device created: %s", physicalDeviceProperties_[physical_device_].properties.deviceName);
// Since we successfully created a device (however we got here, might be interesting in debug), we force the choice to be visible in the menu.
+5 -3
View File
@@ -537,7 +537,8 @@ bool VulkanMayBeAvailable() {
INFO_LOG(Log::G3D, "VulkanMayBeAvailable: Found platform surface extension '%s'", platformSurfaceExtension);
instanceExtensions[ci.enabledExtensionCount++] = platformSurfaceExtension;
platformSurfaceExtensionFound = true;
break;
// Note: Can't stop here - the enumeration order isn't specified anywhere, so VK_KHR_surface
// may well come after the platform one, and we need both.
} else if (!strcmp(iter.extensionName, VK_KHR_SURFACE_EXTENSION_NAME)) {
instanceExtensions[ci.enabledExtensionCount++] = VK_KHR_SURFACE_EXTENSION_NAME;
surfaceExtensionFound = true;
@@ -618,8 +619,9 @@ bool VulkanMayBeAvailable() {
}
}
}
anyGood = !blacklisted;
if (anyGood) {
// Note: Must not overwrite the verdict from a previously seen device, one good one is enough.
anyGood = anyGood || !blacklisted;
if (!blacklisted) {
INFO_LOG(Log::G3D, "VulkanMayBeAvailable: Eligible device found: '%s'", props.deviceName);
} else {
INFO_LOG(Log::G3D, "VulkanMayBeAvailable: Blacklisted device found and ignored: '%s'", props.deviceName);