Implement metal_objects for MoltenVK
Using metal_objects extension for MoltenVK
to avoid using the deprecated and unsafe old API
and fix AHB and external memory related issues.
Bug: 333460957
Test: build and run with -use-host-vulkan, with VVL disabled
Change-Id: If1269359a7b4a7f8a4746c8ca698eb8838aebb9a
diff --git a/host/vulkan/VkAndroidNativeBuffer.cpp b/host/vulkan/VkAndroidNativeBuffer.cpp
index 0b74d00..a3601c1 100644
--- a/host/vulkan/VkAndroidNativeBuffer.cpp
+++ b/host/vulkan/VkAndroidNativeBuffer.cpp
@@ -183,6 +183,26 @@
VK_EXT_MEMORY_HANDLE_TYPE_BIT,
};
+#if defined(__APPLE__)
+ VkImportMetalTextureInfoEXT metalImageImport = {
+ VK_STRUCTURE_TYPE_IMPORT_METAL_TEXTURE_INFO_EXT};
+
+ if (emu->instanceSupportsMoltenVK) {
+ // Change handle type requested to mtltexture
+ extImageCi.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_KHR;
+
+ if (out->colorBufferHandle) {
+ // TODO(b/333460957): External memory is not properly supported on MoltenVK
+ // and although this works fine, it's not valid and causing validation layer issues
+ metalImageImport.plane = VK_IMAGE_ASPECT_PLANE_0_BIT;
+ metalImageImport.mtlTexture = getColorBufferMTLTexture(out->colorBufferHandle);
+
+ // Insert metalImageImport to the chain
+ vk_insert_struct(createImageCi, metalImageImport);
+ }
+ }
+#endif
+
vk_insert_struct(createImageCi, extImageCi);
VkResult createResult = vk->vkCreateImage(device, &createImageCi, pAllocator, &out->image);
diff --git a/host/vulkan/VkCommonOperations.cpp b/host/vulkan/VkCommonOperations.cpp
index aad921f..f8c48cf 100644
--- a/host/vulkan/VkCommonOperations.cpp
+++ b/host/vulkan/VkCommonOperations.cpp
@@ -312,6 +312,12 @@
0,
VK_EXT_MEMORY_HANDLE_TYPE_BIT,
};
+#if defined(__APPLE__)
+ if (sVkEmulation->instanceSupportsMoltenVK) {
+ // Using a different handle type when in MoltenVK mode
+ extInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_KHR;
+ }
+#endif
VkPhysicalDeviceImageFormatInfo2 formatInfo2 = {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
@@ -347,6 +353,12 @@
if (res != VK_SUCCESS) {
if (res == VK_ERROR_FORMAT_NOT_SUPPORTED) {
+ VK_COMMON_VERBOSE("Not Supported: %s %s %s %s",
+ string_VkFormat(info->format),
+ string_VkImageType(info->type),
+ string_VkImageTiling(info->tiling),
+ string_VkImageUsageFlagBits((VkImageUsageFlagBits)info->usageFlags));
+
info->supported = false;
return true;
} else {
@@ -372,7 +384,15 @@
VkExternalMemoryHandleTypeFlags compatibleHandleTypes =
outExternalProps.externalMemoryProperties.compatibleHandleTypes;
- info->supportsExternalMemory = (VK_EXT_MEMORY_HANDLE_TYPE_BIT & compatibleHandleTypes) &&
+ VkExternalMemoryHandleTypeFlagBits handleTypeNeeded = VK_EXT_MEMORY_HANDLE_TYPE_BIT;
+#if defined(__APPLE__)
+ if (sVkEmulation->instanceSupportsMoltenVK) {
+ // Using a different handle type when in MoltenVK mode
+ handleTypeNeeded = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_KHR;
+ }
+#endif
+
+ info->supportsExternalMemory = (handleTypeNeeded & compatibleHandleTypes) &&
(VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT & featureFlags) &&
(VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT & featureFlags);
@@ -551,6 +571,9 @@
#elif defined(__QNX__)
VK_QNX_EXTERNAL_MEMORY_SCREEN_BUFFER_EXTENSION_NAME,
VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME,
+#elif defined(__APPLE__)
+ // VK_EXT_metal_objects will be added if host MoltenVK is enabled,
+ // otherwise VK_KHR_external_memory_fd will be used
#else
VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,
#endif
@@ -585,17 +608,11 @@
extensionsSupported(instanceExts, externalMemoryInstanceExtNames);
bool externalSemaphoreCapabilitiesSupported =
extensionsSupported(instanceExts, externalSemaphoreInstanceExtNames);
- bool surfaceSupported =
- extensionsSupported(instanceExts, surfaceInstanceExtNames);
+ bool surfaceSupported = extensionsSupported(instanceExts, surfaceInstanceExtNames);
#if defined(__APPLE__) && defined(VK_MVK_moltenvk)
bool moltenVKSupported = (vk->vkGetMTLTextureMVK != nullptr) &&
(vk->vkSetMTLTextureMVK != nullptr) &&
extensionsSupported(instanceExts, moltenVkInstanceExtNames);
- if (moltenVKSupported) {
- // We don't need both moltenVK and external memory. Disable
- // external memory if moltenVK is supported.
- externalMemoryCapabilitiesSupported = false;
- }
#endif
VkInstanceCreateInfo instCi = {
@@ -635,6 +652,7 @@
#if defined(__APPLE__) && defined(VK_MVK_moltenvk)
if (moltenVKSupported) {
+ VK_COMMON_LOG("MoltenVK is supported, enabling Vulkan portability.");
instCi.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
for (auto extension : moltenVkInstanceExtNames) {
selectedInstanceExtensionNames.emplace(extension);
@@ -642,7 +660,8 @@
}
#endif
- std::vector<const char*> selectedInstanceExtensionNames_(selectedInstanceExtensionNames.begin(), selectedInstanceExtensionNames.end());
+ std::vector<const char*> selectedInstanceExtensionNames_(selectedInstanceExtensionNames.begin(),
+ selectedInstanceExtensionNames.end());
instCi.enabledExtensionCount = static_cast<uint32_t>(selectedInstanceExtensionNames_.size());
instCi.ppEnabledExtensionNames = selectedInstanceExtensionNames_.data();
@@ -755,7 +774,13 @@
VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(ABORT_REASON_OTHER,
"Cannot find vkGetMTLTextureMVK.");
}
- VK_COMMON_LOG("Instance supports VK_MVK_moltenvk.");
+
+ // Using metal_objects extension on MacOS when moltenVK is used.
+ externalMemoryDeviceExtNames.push_back(VK_EXT_METAL_OBJECTS_EXTENSION_NAME);
+ }
+ else {
+ // When MoltenVK is not used(e.g. SwiftShader), use memory fd extension for external memory.
+ externalMemoryDeviceExtNames.push_back(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME);
}
#endif
@@ -775,7 +800,8 @@
for (int i = 0; i < physdevCount; ++i) {
ivk->vkGetPhysicalDeviceProperties(physdevs[i], &deviceInfos[i].physdevProps);
- VK_COMMON_VERBOSE("Considering Vulkan physical device %d : %s", i, deviceInfos[i].physdevProps.deviceName);
+ VK_COMMON_VERBOSE("Considering Vulkan physical device %d : %s", i,
+ deviceInfos[i].physdevProps.deviceName);
// It's easier to figure out the staging buffer along with
// external memories if we have the memory properties on hand.
@@ -793,7 +819,7 @@
deviceInfos[i].supportsExternalMemoryExport = false;
deviceInfos[i].glInteropSupported = 0; // set later
-#if defined(__APPLE__) && defined(VK_MVK_moltenvk)
+#if defined(__APPLE__)
if (moltenVKSupported && !extensionsSupported(deviceExts, moltenVkDeviceExtNames)) {
VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(
ABORT_REASON_OTHER,
@@ -1070,7 +1096,7 @@
selectedDeviceExtensionNames_.emplace(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
}
-#if defined(__APPLE__) && defined(VK_MVK_moltenvk)
+#if defined(__APPLE__)
if (moltenVKSupported) {
for (auto extension : moltenVkDeviceExtNames) {
selectedDeviceExtensionNames_.emplace(extension);
@@ -1163,17 +1189,32 @@
}
if (sVkEmulation->deviceInfo.supportsExternalMemoryExport) {
#ifdef _WIN32
+ // Use vkGetMemoryWin32HandleKHR
sVkEmulation->deviceInfo.getMemoryHandleFunc =
reinterpret_cast<PFN_vkGetMemoryWin32HandleKHR>(
dvk->vkGetDeviceProcAddr(sVkEmulation->device, "vkGetMemoryWin32HandleKHR"));
-#else
- sVkEmulation->deviceInfo.getMemoryHandleFunc = reinterpret_cast<PFN_vkGetMemoryFdKHR>(
- dvk->vkGetDeviceProcAddr(sVkEmulation->device, "vkGetMemoryFdKHR"));
-#endif
if (!sVkEmulation->deviceInfo.getMemoryHandleFunc) {
VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(ABORT_REASON_OTHER,
- "Cannot find vkGetMemory(Fd|Win32Handle)KHR");
+ "Cannot find vkGetMemoryWin32HandleKHR");
}
+#else
+ if (sVkEmulation->instanceSupportsMoltenVK) {
+ // vkExportMetalObjectsEXT will be used directly
+ sVkEmulation->deviceInfo.getMemoryHandleFunc = nullptr;
+ if (!dvk->vkGetDeviceProcAddr(sVkEmulation->device, "vkExportMetalObjectsEXT")) {
+ VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(ABORT_REASON_OTHER,
+ "Cannot find vkExportMetalObjectsEXT");
+ }
+ } else {
+ // Use vkGetMemoryFdKHR
+ sVkEmulation->deviceInfo.getMemoryHandleFunc = reinterpret_cast<PFN_vkGetMemoryFdKHR>(
+ dvk->vkGetDeviceProcAddr(sVkEmulation->device, "vkGetMemoryFdKHR"));
+ if (!sVkEmulation->deviceInfo.getMemoryHandleFunc) {
+ VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(ABORT_REASON_OTHER,
+ "Cannot find vkGetMemoryFdKHR");
+ }
+ }
+#endif
}
VK_COMMON_VERBOSE("Vulkan logical device created and extension functions obtained.");
@@ -1440,6 +1481,34 @@
return std::make_unique<gfxstream::DisplaySurface>(width, height, std::move(surfaceVk));
}
+#ifdef __APPLE__
+static MTLBufferRef getMtlBufferFromVkDeviceMemory(VulkanDispatch* vk, VkDeviceMemory memory) {
+ VkExportMetalBufferInfoEXT exportMetalBufferInfo = {
+ VK_STRUCTURE_TYPE_EXPORT_METAL_BUFFER_INFO_EXT, nullptr, memory, VK_NULL_HANDLE};
+ VkExportMetalObjectsInfoEXT metalObjectsInfo = {VK_STRUCTURE_TYPE_EXPORT_METAL_OBJECTS_INFO_EXT,
+ &exportMetalBufferInfo};
+ vk->vkExportMetalObjectsEXT(sVkEmulation->device, &metalObjectsInfo);
+
+ return exportMetalBufferInfo.mtlBuffer;
+}
+
+static MTLTextureRef getMtlTextureFromVkImage(VulkanDispatch* vk, VkImage image) {
+ VkExportMetalTextureInfoEXT exportMetalTextureInfo = {
+ VK_STRUCTURE_TYPE_EXPORT_METAL_TEXTURE_INFO_EXT,
+ nullptr,
+ image,
+ VK_NULL_HANDLE,
+ VK_NULL_HANDLE,
+ VK_IMAGE_ASPECT_PLANE_0_BIT,
+ VK_NULL_HANDLE};
+ VkExportMetalObjectsInfoEXT metalObjectsInfo = {VK_STRUCTURE_TYPE_EXPORT_METAL_OBJECTS_INFO_EXT,
+ &exportMetalTextureInfo};
+ vk->vkExportMetalObjectsEXT(sVkEmulation->device, &metalObjectsInfo);
+
+ return exportMetalTextureInfo.mtlTexture;
+}
+#endif
+
// Precondition: sVkEmulation has valid device support info
bool allocExternalMemory(VulkanDispatch* vk, VkEmulation::ExternalMemoryInfo* info,
bool actuallyExternal, Optional<uint64_t> deviceAlignment,
@@ -1467,7 +1536,26 @@
auto allocInfoChain = vk_make_chain_iterator(&allocInfo);
+#ifdef __APPLE__
+ // On MoltenVK, use metal objects to export metal handles
+ VkExportMetalObjectCreateInfoEXT metalBufferExport = {
+ VK_STRUCTURE_TYPE_EXPORT_METAL_OBJECT_CREATE_INFO_EXT,
+ nullptr,
+ VK_EXPORT_METAL_OBJECT_TYPE_METAL_BUFFER_BIT_EXT
+ };
+#endif
+
if (sVkEmulation->deviceInfo.supportsExternalMemoryExport && actuallyExternal) {
+#ifdef __APPLE__
+ if (sVkEmulation->instanceSupportsMoltenVK) {
+ // Change handle type to metal buffers
+ exportAi.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_KHR;
+
+ // Append metal buffer export for getting metal handles for the allocation
+ vk_append_struct(&allocInfoChain, &metalBufferExport);
+ }
+#endif
+
vk_append_struct(&allocInfoChain, &exportAi);
}
@@ -1548,6 +1636,7 @@
}
VkResult exportRes = VK_SUCCESS;
+ bool validHandle = false;
#ifdef _WIN32
VkMemoryGetWin32HandleInfoKHR getWin32HandleInfo = {
VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR,
@@ -1557,19 +1646,35 @@
};
exportRes = sVkEmulation->deviceInfo.getMemoryHandleFunc(
sVkEmulation->device, &getWin32HandleInfo, &info->externalHandle);
+ validHandle = (VK_EXT_MEMORY_HANDLE_INVALID != info->externalHandle);
#elif !defined(__QNX__)
- VkMemoryGetFdInfoKHR getFdInfo = {
- VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
- 0,
- info->memory,
- VK_EXT_MEMORY_HANDLE_TYPE_BIT,
- };
- exportRes = sVkEmulation->deviceInfo.getMemoryHandleFunc(sVkEmulation->device, &getFdInfo,
- &info->externalHandle);
+#ifdef __APPLE__
+ if (sVkEmulation->instanceSupportsMoltenVK) {
+ info->externalMetalHandle = getMtlBufferFromVkDeviceMemory(vk, info->memory);
+ validHandle = (nullptr != info->externalMetalHandle);
+ if (validHandle) {
+ CFRetain(info->externalMetalHandle);
+ exportRes = VK_SUCCESS;
+ } else {
+ exportRes = VK_ERROR_INVALID_EXTERNAL_HANDLE;
+ }
+ } else
+#endif
+ {
+ VkMemoryGetFdInfoKHR getFdInfo = {
+ VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
+ 0,
+ info->memory,
+ VK_EXT_MEMORY_HANDLE_TYPE_BIT,
+ };
+ exportRes = sVkEmulation->deviceInfo.getMemoryHandleFunc(sVkEmulation->device, &getFdInfo,
+ &info->externalHandle);
+ validHandle = (VK_EXT_MEMORY_HANDLE_INVALID != info->externalHandle);
+ }
#endif
- if (exportRes != VK_SUCCESS || VK_EXT_MEMORY_HANDLE_INVALID == info->externalHandle) {
- VK_COMMON_VERBOSE("allocExternalMemory: Failed to get external memory, native handle: %s", string_VkResult(exportRes));
+ if (exportRes != VK_SUCCESS || !validHandle) {
+ VK_COMMON_VERBOSE("allocExternalMemory: Failed to get external memory, result: %s", string_VkResult(exportRes));
return false;
}
@@ -1606,10 +1711,17 @@
#endif
info->externalHandle = VK_EXT_MEMORY_HANDLE_INVALID;
}
+
+#if defined(__APPLE__)
+ if (info->externalMetalHandle) {
+ CFRelease(info->externalMetalHandle);
+ }
+#endif
}
bool importExternalMemory(VulkanDispatch* vk, VkDevice targetDevice,
const VkEmulation::ExternalMemoryInfo* info, VkDeviceMemory* out) {
+ const void* importInfoPtr = nullptr;
#ifdef _WIN32
VkImportMemoryWin32HandleInfoKHR importInfo = {
VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR,
@@ -1618,23 +1730,41 @@
info->externalHandle,
0,
};
+ importInfoPtr = &importInfo;
#elif defined(__QNX__)
VkImportScreenBufferInfoQNX importInfo = {
VK_STRUCTURE_TYPE_IMPORT_SCREEN_BUFFER_INFO_QNX,
NULL,
info->externalHandle,
};
+ importInfoPtr = &importInfo;
#else
- VkImportMemoryFdInfoKHR importInfo = {
+ VkImportMemoryFdInfoKHR importInfoFd = {
VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
0,
VK_EXT_MEMORY_HANDLE_TYPE_BIT,
- dupExternalMemory(info->externalHandle),
+ VK_EXT_MEMORY_HANDLE_INVALID,
};
+
+#ifdef __APPLE__
+ VkImportMetalBufferInfoEXT importInfoMetalBuffer = {
+ VK_STRUCTURE_TYPE_IMPORT_METAL_BUFFER_INFO_EXT,
+ 0,
+ nullptr,
+ };
+ if (sVkEmulation->instanceSupportsMoltenVK) {
+ importInfoMetalBuffer.mtlBuffer = info->externalMetalHandle;
+ importInfoPtr = &importInfoMetalBuffer;
+ } else
+#endif
+ {
+ importInfoFd.fd = dupExternalMemory(info->externalHandle);
+ importInfoPtr = &importInfoFd;
+ }
#endif
VkMemoryAllocateInfo allocInfo = {
VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
- &importInfo,
+ importInfoPtr,
info->size,
info->typeIndex,
};
@@ -1659,6 +1789,7 @@
VK_NULL_HANDLE,
};
+ const void *importInfoPtr = nullptr;
#ifdef _WIN32
VkImportMemoryWin32HandleInfoKHR importInfo = {
VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR,
@@ -1667,23 +1798,41 @@
info->externalHandle,
0,
};
+ importInfoPtr = &importInfo;
#elif defined(__QNX__)
VkImportScreenBufferInfoQNX importInfo = {
VK_STRUCTURE_TYPE_IMPORT_SCREEN_BUFFER_INFO_QNX,
&dedicatedInfo,
info->externalHandle,
};
+ importInfoPtr = &importInfo;
#else
- VkImportMemoryFdInfoKHR importInfo = {
+ VkImportMemoryFdInfoKHR importInfoFd = {
VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
&dedicatedInfo,
VK_EXT_MEMORY_HANDLE_TYPE_BIT,
- dupExternalMemory(info->externalHandle),
+ -1,
};
+
+#ifdef __APPLE__
+ VkImportMetalBufferInfoEXT importInfoMetalBuffer = {
+ VK_STRUCTURE_TYPE_IMPORT_METAL_BUFFER_INFO_EXT,
+ &dedicatedInfo,
+ nullptr,
+ };
+ if (sVkEmulation->instanceSupportsMoltenVK) {
+ importInfoMetalBuffer.mtlBuffer = info->externalMetalHandle;
+ importInfoPtr = &importInfoMetalBuffer;
+ } else
+#endif
+ {
+ importInfoFd.fd = dupExternalMemory(info->externalHandle);
+ importInfoPtr = &importInfoFd;
+ }
#endif
VkMemoryAllocateInfo allocInfo = {
VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
- &importInfo,
+ importInfoPtr,
info->size,
info->typeIndex,
};
@@ -2055,6 +2204,18 @@
0,
VK_EXT_MEMORY_HANDLE_TYPE_BIT,
};
+#if defined(__APPLE__)
+ VkExportMetalObjectCreateInfoEXT metalImageExportCI = {
+ VK_STRUCTURE_TYPE_EXPORT_METAL_OBJECT_CREATE_INFO_EXT, nullptr,
+ VK_EXPORT_METAL_OBJECT_TYPE_METAL_TEXTURE_BIT_EXT};
+
+ if (sVkEmulation->instanceSupportsMoltenVK) {
+ // Using a different handle type when in MoltenVK mode
+ extImageCi.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_KHR;
+
+ extImageCi.pNext = &metalImageExportCI;
+ }
+#endif
VkExternalMemoryImageCreateInfo* extImageCiPtr = nullptr;
@@ -2194,13 +2355,10 @@
return false;
}
-#if defined(VK_MVK_moltenvk) && defined(__APPLE__)
+#if defined(__APPLE__)
if (sVkEmulation->instanceSupportsMoltenVK) {
- sVkEmulation->getMTLTextureFunc(infoPtr->image, &infoPtr->mtlTexture);
- if (!infoPtr->mtlTexture) {
- VK_COMMON_ERROR("Failed to get MTLTexture for Vulkan image %p.", infoPtr->image);
- }
-
+ // Retrieve metal texture for this image
+ infoPtr->mtlTexture = getMtlTextureFromVkImage(vk, infoPtr->image);
CFRetain(infoPtr->mtlTexture);
}
#endif
@@ -2880,8 +3038,57 @@
return infoPtr->memory.externalHandle;
}
+#ifdef __APPLE__
+MTLBufferRef getColorBufferMetalMemoryHandle(uint32_t colorBuffer) {
+ if (!sVkEmulation || !sVkEmulation->live) return nullptr;
+
+ AutoLock lock(sVkEmulationLock);
+
+ auto infoPtr = android::base::find(sVkEmulation->colorBuffers, colorBuffer);
+
+ if (!infoPtr) {
+ // Color buffer not found; this is usually OK.
+ return nullptr;
+ }
+
+ return infoPtr->memory.externalMetalHandle;
+}
+
+MTLTextureRef getColorBufferMTLTexture(uint32_t colorBufferHandle) {
+ if (!sVkEmulation || !sVkEmulation->live) return nullptr;
+
+ AutoLock lock(sVkEmulationLock);
+
+ auto infoPtr = android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
+
+ if (!infoPtr) {
+ // Color buffer not found; this is usually OK.
+ return nullptr;
+ }
+
+ CFRetain(infoPtr->mtlTexture);
+ return infoPtr->mtlTexture;
+}
+
+// TODO(b/333460957): Temporary function for MoltenVK
+VkImage getColorBufferVkImage(uint32_t colorBufferHandle) {
+ if (!sVkEmulation || !sVkEmulation->live) return nullptr;
+
+ AutoLock lock(sVkEmulationLock);
+
+ auto infoPtr = android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
+
+ if (!infoPtr) {
+ // Color buffer not found; this is usually OK.
+ return nullptr;
+ }
+
+ return infoPtr->image;
+}
+#endif // __APPLE__
+
bool setColorBufferVulkanMode(uint32_t colorBuffer, uint32_t vulkanMode) {
- if (!sVkEmulation || !sVkEmulation->live) return VK_EXT_MEMORY_HANDLE_INVALID;
+ if (!sVkEmulation || !sVkEmulation->live) return false;
AutoLock lock(sVkEmulationLock);
@@ -2896,24 +3103,6 @@
return true;
}
-MTLTextureRef getColorBufferMTLTexture(uint32_t colorBuffer) {
- if (!sVkEmulation || !sVkEmulation->live) return nullptr;
-
- AutoLock lock(sVkEmulationLock);
-
- auto infoPtr = android::base::find(sVkEmulation->colorBuffers, colorBuffer);
-
- if (!infoPtr) {
- // Color buffer not found; this is usually OK.
- return nullptr;
- }
-
-#ifdef __APPLE__
- CFRetain(infoPtr->mtlTexture);
-#endif
- return infoPtr->mtlTexture;
-}
-
int32_t mapGpaToBufferHandle(uint32_t bufferHandle, uint64_t gpa, uint64_t size) {
if (!sVkEmulation || !sVkEmulation->live) return VK_ERROR_DEVICE_LOST;
@@ -3031,8 +3220,7 @@
0,
VK_EXT_MEMORY_HANDLE_TYPE_BIT,
};
-
- VkExternalMemoryBufferCreateInfo* extBufferCiPtr = nullptr;
+ void* extBufferCiPtr = nullptr;
if (sVkEmulation->deviceInfo.supportsExternalMemoryImport ||
sVkEmulation->deviceInfo.supportsExternalMemoryExport) {
extBufferCiPtr = &extBufferCi;
@@ -3169,6 +3357,22 @@
return infoPtr->memory.externalHandle;
}
+#ifdef __APPLE__
+MTLBufferRef getBufferMetalMemoryHandle(uint32_t bufferHandle) {
+ if (!sVkEmulation || !sVkEmulation->live) return nullptr;
+
+ AutoLock lock(sVkEmulationLock);
+
+ auto infoPtr = android::base::find(sVkEmulation->buffers, bufferHandle);
+ if (!infoPtr) {
+ // Color buffer not found; this is usually OK.
+ return nullptr;
+ }
+
+ return infoPtr->memory.externalMetalHandle;
+}
+#endif
+
bool readBufferToBytes(uint32_t bufferHandle, uint64_t offset, uint64_t size, void* outBytes) {
if (!sVkEmulation || !sVkEmulation->live) {
VK_COMMON_ERROR("VkEmulation not available.");
@@ -3367,7 +3571,15 @@
if (bits & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID) {
res &= ~VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
- res |= VK_EXT_MEMORY_HANDLE_TYPE_BIT;
+
+ VkExternalMemoryHandleTypeFlagBits handleTypeNeeded = VK_EXT_MEMORY_HANDLE_TYPE_BIT;
+#if defined(__APPLE__)
+ if (sVkEmulation->instanceSupportsMoltenVK) {
+ // Using a different handle type when in MoltenVK mode
+ handleTypeNeeded = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_KHR;
+ }
+#endif
+ res |= handleTypeNeeded;
}
if (bits & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA) {
@@ -3391,8 +3603,15 @@
VkExternalMemoryHandleTypeFlags wantedGuestHandleType) {
VkExternalMemoryHandleTypeFlags res = hostBits;
- if (res & VK_EXT_MEMORY_HANDLE_TYPE_BIT) {
- res &= ~VK_EXT_MEMORY_HANDLE_TYPE_BIT;
+ VkExternalMemoryHandleTypeFlagBits handleTypeUsed = VK_EXT_MEMORY_HANDLE_TYPE_BIT;
+#if defined(__APPLE__)
+ if (sVkEmulation->instanceSupportsMoltenVK) {
+ // Using a different handle type when in MoltenVK mode
+ handleTypeUsed = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_KHR;
+ }
+#endif
+ if ((res & handleTypeUsed) == handleTypeUsed) {
+ res &= ~handleTypeUsed;
res |= wantedGuestHandleType;
}
diff --git a/host/vulkan/VkCommonOperations.h b/host/vulkan/VkCommonOperations.h
index 25e228c..2038e33 100644
--- a/host/vulkan/VkCommonOperations.h
+++ b/host/vulkan/VkCommonOperations.h
@@ -84,7 +84,6 @@
const VkPhysicalDeviceMemoryProperties* memProps,
uint32_t* typeIndex);
-
VK_EXT_MEMORY_HANDLE dupExternalMemory(VK_EXT_MEMORY_HANDLE);
enum class AstcEmulationMode {
@@ -247,12 +246,16 @@
uint32_t pageOffset = 0u;
// the offset set in |vkBindImageMemory| or |vkBindBufferMemory|.
uint32_t bindOffset = 0u;
- // the size of all the pages the mmeory uses.
+ // the size of all the pages the memory uses.
size_t sizeToPage = 0u;
// guest physical address.
uintptr_t gpa = 0u;
VK_EXT_MEMORY_HANDLE externalHandle = VK_EXT_MEMORY_HANDLE_INVALID;
+#ifdef __APPLE__
+ // This is used as an external handle when MoltenVK is enabled
+ MTLBufferRef externalMetalHandle = nullptr;
+#endif
bool dedicatedAllocation = false;
};
@@ -334,7 +337,9 @@
VulkanMode vulkanMode = VulkanMode::Default;
+#if defined(__APPLE__)
MTLTextureRef mtlTexture = nullptr;
+#endif
std::optional<DeviceOpWaitable> latestUse;
DeviceOpTrackerPtr latestUseTracker = nullptr;
@@ -354,7 +359,6 @@
bool glExported = false;
VulkanMode vulkanMode = VulkanMode::Default;
- MTLBufferRef mtlBuffer = nullptr;
};
// Track what is supported on whatever device was selected.
@@ -490,6 +494,11 @@
VkEmulation::ColorBufferInfo getColorBufferInfo(uint32_t colorBufferHandle);
VK_EXT_MEMORY_HANDLE getColorBufferExtMemoryHandle(uint32_t colorBufferHandle);
+#ifdef __APPLE__
+MTLBufferRef getColorBufferMetalMemoryHandle(uint32_t colorBufferHandle);
+MTLTextureRef getColorBufferMTLTexture(uint32_t colorBufferHandle);
+VkImage getColorBufferVkImage(uint32_t colorBufferHandle);
+#endif
struct VkColorBufferMemoryExport {
android::base::ManagedDescriptor descriptor;
@@ -499,7 +508,6 @@
};
std::optional<VkColorBufferMemoryExport> exportColorBufferMemory(uint32_t colorBufferHandle);
-MTLTextureRef getColorBufferMTLTexture(uint32_t colorBufferHandle);
bool setColorBufferVulkanMode(uint32_t colorBufferHandle, uint32_t vulkanMode);
int32_t mapGpaToBufferHandle(uint32_t bufferHandle, uint64_t gpa, uint64_t size = 0);
@@ -523,6 +531,9 @@
uint32_t memoryProperty = 0);
bool teardownVkBuffer(uint32_t bufferHandle);
VK_EXT_MEMORY_HANDLE getBufferExtMemoryHandle(uint32_t bufferHandle);
+#ifdef __APPLE__
+MTLBufferRef getBufferMetalMemoryHandle(uint32_t bufferHandle);
+#endif
bool readBufferToBytes(uint32_t bufferHandle, uint64_t offset, uint64_t size, void* outBytes);
bool updateBufferFromBytes(uint32_t bufferHandle, uint64_t offset, uint64_t size,
diff --git a/host/vulkan/VkDecoderGlobalState.cpp b/host/vulkan/VkDecoderGlobalState.cpp
index 33692a6..732c051 100644
--- a/host/vulkan/VkDecoderGlobalState.cpp
+++ b/host/vulkan/VkDecoderGlobalState.cpp
@@ -2132,6 +2132,24 @@
const VkNativeBufferANDROID* nativeBufferANDROID =
vk_find_struct<VkNativeBufferANDROID>(pCreateInfo);
+#if defined(__APPLE__)
+ VkExportMetalObjectCreateInfoEXT metalImageExportCI = {
+ VK_STRUCTURE_TYPE_EXPORT_METAL_OBJECT_CREATE_INFO_EXT, nullptr,
+ VK_EXPORT_METAL_OBJECT_TYPE_METAL_TEXTURE_BIT_EXT};
+
+ // Add VkExportMetalObjectCreateInfoEXT on MoltenVK
+ if (m_emu->instanceSupportsMoltenVK) {
+ const VkExternalMemoryImageCreateInfo* externalMemCI =
+ vk_find_struct<VkExternalMemoryImageCreateInfo>(pCreateInfo);
+ if (externalMemCI) {
+ // Insert metalImageExportCI to the chain
+ metalImageExportCI.pNext = externalMemCI->pNext;
+ const_cast<VkExternalMemoryImageCreateInfo*>(externalMemCI)->pNext =
+ &metalImageExportCI;
+ }
+ }
+#endif
+
VkResult createRes = VK_SUCCESS;
if (nativeBufferANDROID) {
@@ -2282,16 +2300,6 @@
auto* memoryInfo = android::base::find(mMemoryInfo, memory);
if (!memoryInfo) return VK_ERROR_OUT_OF_HOST_MEMORY;
-#if defined(__APPLE__) && defined(VK_MVK_moltenvk)
- if (memoryInfo->mtlTexture) {
- result = m_vk->vkSetMTLTextureMVK(image, memoryInfo->mtlTexture);
- if (result != VK_SUCCESS) {
- fprintf(stderr, "vkSetMTLTexture failed\n");
- return VK_ERROR_OUT_OF_HOST_MEMORY;
- }
- }
-#endif
-
auto* imageInfo = android::base::find(mImageInfo, image);
if (!imageInfo) return VK_ERROR_OUT_OF_HOST_MEMORY;
imageInfo->boundColorBuffer = memoryInfo->boundColorBuffer;
@@ -4354,6 +4362,14 @@
};
#endif
+#if defined(__APPLE__)
+ VkImportMetalBufferInfoEXT importInfoMetalBuffer = {
+ VK_STRUCTURE_TYPE_IMPORT_METAL_BUFFER_INFO_EXT,
+ 0,
+ nullptr,
+ };
+#endif
+
void* mappedPtr = nullptr;
ManagedDescriptor externalMemoryHandle;
if (importCbInfoPtr) {
@@ -4378,7 +4394,37 @@
}
}
- if (m_emu->instanceSupportsExternalMemoryCapabilities) {
+#if defined(__APPLE__)
+ // Use metal object extension on MoltenVK mode for color buffer import,
+ // non-moltenVK path on MacOS will use FD handles
+ if (m_emu->instanceSupportsMoltenVK) {
+ // TODO(b/333460957): This is a temporary fix to get MoltenVK image memory binding
+ // checks working as expected based on dedicated memory checks. It's not a valid usage
+ // of Vulkan as the device of the image is different than what's being used here
+ localDedicatedAllocInfo = {
+ .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
+ .pNext = nullptr,
+ .image = getColorBufferVkImage(importCbInfoPtr->colorBuffer),
+ .buffer = VK_NULL_HANDLE,
+ };
+ shouldUseDedicatedAllocInfo = true;
+
+ MTLBufferRef cbExtMemoryHandle =
+ getColorBufferMetalMemoryHandle(importCbInfoPtr->colorBuffer);
+
+ if (cbExtMemoryHandle == nullptr) {
+ fprintf(stderr,
+ "%s: VK_ERROR_OUT_OF_DEVICE_MEMORY: "
+ "colorBuffer 0x%x does not have Vulkan external memory backing\n",
+ __func__, importCbInfoPtr->colorBuffer);
+ return VK_ERROR_OUT_OF_DEVICE_MEMORY;
+ }
+
+ importInfoMetalBuffer.mtlBuffer = cbExtMemoryHandle;
+ vk_append_struct(&structChainIter, &importInfoMetalBuffer);
+ } else
+#endif
+ if (m_emu->deviceInfo.supportsExternalMemoryImport) {
VK_EXT_MEMORY_HANDLE cbExtMemoryHandle =
getColorBufferExtMemoryHandle(importCbInfoPtr->colorBuffer);
@@ -4416,7 +4462,25 @@
shouldUseDedicatedAllocInfo &= bufferMemoryUsesDedicatedAlloc;
- if (m_emu->instanceSupportsExternalMemoryCapabilities) {
+#ifdef __APPLE__
+ if (m_emu->instanceSupportsMoltenVK) {
+ MTLBufferRef bufferMetalMemoryHandle =
+ getBufferMetalMemoryHandle(importBufferInfoPtr->buffer);
+
+ if (bufferMetalMemoryHandle == nullptr) {
+ fprintf(stderr,
+ "%s: VK_ERROR_OUT_OF_DEVICE_MEMORY: "
+ "buffer 0x%x does not have Vulkan external memory "
+ "backing\n",
+ __func__, importBufferInfoPtr->buffer);
+ return VK_ERROR_OUT_OF_DEVICE_MEMORY;
+ }
+
+ importInfoMetalBuffer.mtlBuffer = bufferMetalMemoryHandle;
+ vk_append_struct(&structChainIter, &importInfoMetalBuffer);
+ } else
+#endif
+ if (m_emu->deviceInfo.supportsExternalMemoryImport) {
VK_EXT_MEMORY_HANDLE bufferExtMemoryHandle =
getBufferExtMemoryHandle(importBufferInfoPtr->buffer);
@@ -4497,6 +4561,13 @@
exportAllocate.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
#endif
+#if defined(__APPLE__)
+ if (m_emu->instanceSupportsMoltenVK) {
+ // Using a different handle type when in MoltenVK mode
+ exportAllocate.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_KHR;
+ }
+#endif
+
bool hostVisible = memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
if (hostVisible && m_emu->features.ExternalBlob.enabled) {
vk_append_struct(&structChainIter, &exportAllocate);
@@ -4617,11 +4688,6 @@
memoryInfo.size = localAllocInfo.allocationSize;
memoryInfo.device = device;
memoryInfo.memoryIndex = localAllocInfo.memoryTypeIndex;
-#if defined(__APPLE__) && defined(VK_MVK_moltenvk)
- if (importCbInfoPtr && m_emu->instanceSupportsMoltenVK) {
- memoryInfo.mtlTexture = getColorBufferMTLTexture(importCbInfoPtr->colorBuffer);
- }
-#endif
if (importCbInfoPtr) {
memoryInfo.boundColorBuffer = importCbInfoPtr->colorBuffer;
@@ -4640,8 +4706,6 @@
memoryInfo.caching = MAP_CACHE_WC;
}
- VkInstance* instance = deviceToInstanceLocked(device);
- InstanceInfo* instanceInfo = android::base::find(mInstanceInfo, *instance);
auto* deviceInfo = android::base::find(mDeviceInfo, device);
if (!deviceInfo) return VK_ERROR_OUT_OF_HOST_MEMORY;
@@ -4691,13 +4755,6 @@
auto* info = android::base::find(mMemoryInfo, memory);
if (!info) return; // Invalid usage.
-#ifdef __APPLE__
- if (info->mtlTexture) {
- CFRelease(info->mtlTexture);
- info->mtlTexture = nullptr;
- }
-#endif
-
if (info->directMapped) {
// if direct mapped, we leave it up to the guest address space driver
// to control the unmapping of kvm slot on the host side
@@ -5073,6 +5130,13 @@
}
#endif
+#ifdef __APPLE__
+ if (m_emu->instanceSupportsMoltenVK) {
+ GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
+ << "ExternalBlob feature is not supported with MoltenVK";
+ }
+#endif
+
ManagedDescriptor managedHandle(handle);
BlobManager::get()->addDescriptorInfo(ctx_id, hostBlobId, std::move(managedHandle),
handleType, info->caching,
diff --git a/host/vulkan/VkDecoderInternalStructs.h b/host/vulkan/VkDecoderInternalStructs.h
index 1b51a5a..fc0d514 100644
--- a/host/vulkan/VkDecoderInternalStructs.h
+++ b/host/vulkan/VkDecoderInternalStructs.h
@@ -156,7 +156,6 @@
uint64_t sizeToPage = 0;
uint64_t hostmemId = 0;
VkDevice device = VK_NULL_HANDLE;
- MTLTextureRef mtlTexture = nullptr;
uint32_t memoryIndex = 0;
// Set if the memory is backed by shared memory.
std::optional<android::base::SharedMemory> sharedMemory;