gfxstream: Add Vulkan external memory resource import implementation for host.
Developed for QNX use-case, but applies generally to any
platform that supports external memory for import but not for
export.
Some robustness around VK_QNX_external_memory_screen_buffer API
usage added with the updateExternalMemoryInfo() function.
BUG=319510663
TEST=compile && launch_cvd --gpu_mode=gfxstream_guest_angle
Change-Id: I7b10b70da024df60881c8b27ea29bd44101b95f6
diff --git a/host/vulkan/VkCommonOperations.cpp b/host/vulkan/VkCommonOperations.cpp
index 3a9fc12..a48d4e2 100644
--- a/host/vulkan/VkCommonOperations.cpp
+++ b/host/vulkan/VkCommonOperations.cpp
@@ -96,6 +96,7 @@
static android::base::StaticLock sVkEmulationLock;
+#if !defined(__QNX__)
VK_EXT_MEMORY_HANDLE dupExternalMemory(VK_EXT_MEMORY_HANDLE h) {
#ifdef _WIN32
auto myProcessHandle = GetCurrentProcess();
@@ -109,6 +110,7 @@
return dup(h);
#endif
}
+#endif
bool getStagingMemoryTypeIndex(VulkanDispatch* vk, VkDevice device,
const VkPhysicalDeviceMemoryProperties* memProps,
@@ -545,6 +547,8 @@
VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME,
#ifdef _WIN32
VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME,
+#elif defined(__QNX__)
+ VK_QNX_EXTERNAL_MEMORY_SCREEN_BUFFER_EXTENSION_NAME,
#else
VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,
#endif
@@ -767,12 +771,18 @@
ivk->vkEnumerateDeviceExtensionProperties(physdevs[i], nullptr, &deviceExtensionCount,
deviceExts.data());
- deviceInfos[i].supportsExternalMemory = false;
+ deviceInfos[i].supportsExternalMemoryImport = false;
+ deviceInfos[i].supportsExternalMemoryExport = false;
deviceInfos[i].glInteropSupported = 0; // set later
if (sVkEmulation->instanceSupportsExternalMemoryCapabilities) {
- deviceInfos[i].supportsExternalMemory =
- extensionsSupported(deviceExts, externalMemoryDeviceExtNames);
+ deviceInfos[i].supportsExternalMemoryExport =
+ deviceInfos[i].supportsExternalMemoryImport =
+ extensionsSupported(deviceExts, externalMemoryDeviceExtNames);
+#if defined(__QNX__)
+ // External memory export not supported on QNX
+ deviceInfos[i].supportsExternalMemoryExport = false;
+#endif
deviceInfos[i].supportsIdProperties =
sVkEmulation->getPhysicalDeviceProperties2Func != nullptr;
deviceInfos[i].supportsDriverProperties =
@@ -847,10 +857,23 @@
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES,
};
vk_append_struct(&features2Chain, &samplerYcbcrConversionFeatures);
+#if defined(__QNX__)
+ VkPhysicalDeviceExternalMemoryScreenBufferFeaturesQNX extMemScreenBufferFeatures = {
+ .sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_SCREEN_BUFFER_FEATURES_QNX,
+ };
+ vk_append_struct(&features2Chain, &extMemScreenBufferFeatures);
+#endif
sVkEmulation->getPhysicalDeviceFeatures2Func(physdevs[i], &features2);
deviceInfos[i].supportsSamplerYcbcrConversion =
samplerYcbcrConversionFeatures.samplerYcbcrConversion == VK_TRUE;
+#if defined(__QNX__)
+ deviceInfos[i].supportsExternalMemoryImport =
+ extMemScreenBufferFeatures.screenBufferImport == VK_TRUE;
+ } else {
+ deviceInfos[i].supportsExternalMemoryImport = false;
+#endif
}
uint32_t queueFamilyCount = 0;
@@ -911,7 +934,9 @@
for (uint32_t i = 0; i < physdevCount; ++i) {
uint32_t deviceScore = 0;
if (deviceInfos[i].hasGraphicsQueueFamily) deviceScore += 10000;
- if (deviceInfos[i].supportsExternalMemory) deviceScore += 1000;
+ if (deviceInfos[i].supportsExternalMemoryImport ||
+ deviceInfos[i].supportsExternalMemoryExport)
+ deviceScore += 1000;
if (deviceInfos[i].physdevProps.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU ||
deviceInfos[i].physdevProps.deviceType == VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU) {
deviceScore += 100;
@@ -987,7 +1012,8 @@
std::unordered_set<const char*> selectedDeviceExtensionNames_;
- if (sVkEmulation->deviceInfo.supportsExternalMemory) {
+ if (sVkEmulation->deviceInfo.supportsExternalMemoryImport ||
+ sVkEmulation->deviceInfo.supportsExternalMemoryExport) {
for (auto extension : externalMemoryDeviceExtNames) {
selectedDeviceExtensionNames_.emplace(extension);
}
@@ -1027,6 +1053,20 @@
});
vk_append_struct(&deviceCiChain, samplerYcbcrConversionFeatures.get());
}
+#if defined(__QNX__)
+ std::unique_ptr<VkPhysicalDeviceExternalMemoryScreenBufferFeaturesQNX>
+ extMemScreenBufferFeaturesQNX = nullptr;
+ if (sVkEmulation->deviceInfo.supportsExternalMemoryImport) {
+ extMemScreenBufferFeaturesQNX = std::make_unique<
+ VkPhysicalDeviceExternalMemoryScreenBufferFeaturesQNX>(
+ VkPhysicalDeviceExternalMemoryScreenBufferFeaturesQNX{
+ .sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_SCREEN_BUFFER_FEATURES_QNX,
+ .screenBufferImport = VK_TRUE,
+ });
+ vk_append_struct(&deviceCiChain, extMemScreenBufferFeaturesQNX.get());
+ }
+#endif
ivk->vkCreateDevice(sVkEmulation->physdev, &dCi, nullptr, &sVkEmulation->device);
@@ -1051,7 +1091,7 @@
}
}
- if (sVkEmulation->deviceInfo.supportsExternalMemory) {
+ if (sVkEmulation->deviceInfo.supportsExternalMemoryImport) {
sVkEmulation->deviceInfo.getImageMemoryRequirements2Func =
reinterpret_cast<PFN_vkGetImageMemoryRequirements2KHR>(
dvk->vkGetDeviceProcAddr(sVkEmulation->device, "vkGetImageMemoryRequirements2KHR"));
@@ -1066,6 +1106,8 @@
VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(ABORT_REASON_OTHER,
"Cannot find vkGetBufferMemoryRequirements2KHR");
}
+ }
+ if (sVkEmulation->deviceInfo.supportsExternalMemoryExport) {
#ifdef _WIN32
sVkEmulation->deviceInfo.getMemoryHandleFunc =
reinterpret_cast<PFN_vkGetMemoryWin32HandleKHR>(
@@ -1359,7 +1401,7 @@
auto allocInfoChain = vk_make_chain_iterator(&allocInfo);
- if (sVkEmulation->deviceInfo.supportsExternalMemory && actuallyExternal) {
+ if (sVkEmulation->deviceInfo.supportsExternalMemoryExport && actuallyExternal) {
vk_append_struct(&allocInfoChain, &exportAi);
}
@@ -1441,10 +1483,11 @@
return false;
}
- if (!sVkEmulation->deviceInfo.supportsExternalMemory || !actuallyExternal) {
+ if (!sVkEmulation->deviceInfo.supportsExternalMemoryExport || !actuallyExternal) {
return true;
}
+ VkResult exportRes = VK_SUCCESS;
#ifdef _WIN32
VkMemoryGetWin32HandleInfoKHR getWin32HandleInfo = {
VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR,
@@ -1452,28 +1495,26 @@
info->memory,
VK_EXT_MEMORY_HANDLE_TYPE_BIT,
};
- VkResult exportRes = sVkEmulation->deviceInfo.getMemoryHandleFunc(
- sVkEmulation->device, &getWin32HandleInfo, &info->exportedHandle);
-#else
+ exportRes = sVkEmulation->deviceInfo.getMemoryHandleFunc(
+ sVkEmulation->device, &getWin32HandleInfo, &info->externalHandle);
+#elif !defined(__QNX__)
VkMemoryGetFdInfoKHR getFdInfo = {
VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
0,
info->memory,
VK_EXT_MEMORY_HANDLE_TYPE_BIT,
};
- VkResult exportRes = sVkEmulation->deviceInfo.getMemoryHandleFunc(
- sVkEmulation->device, &getFdInfo, &info->exportedHandle);
+ exportRes = sVkEmulation->deviceInfo.getMemoryHandleFunc(sVkEmulation->device, &getFdInfo,
+ &info->externalHandle);
#endif
- if (exportRes != VK_SUCCESS) {
+ if (exportRes != VK_SUCCESS || VK_EXT_MEMORY_HANDLE_INVALID == info->externalHandle) {
// LOG(VERBOSE) << "allocExternalMemory: Failed to get external memory "
// "native handle: "
// << exportRes;
return false;
}
- info->actuallyExternal = true;
-
return true;
}
@@ -1497,13 +1538,13 @@
info->memory = VK_NULL_HANDLE;
- if (info->exportedHandle != VK_EXT_MEMORY_HANDLE_INVALID) {
+ if (info->externalHandle != VK_EXT_MEMORY_HANDLE_INVALID) {
#ifdef _WIN32
- CloseHandle(info->exportedHandle);
-#else
- close(info->exportedHandle);
+ CloseHandle(info->externalHandle);
+#elif !defined(__QNX__)
+ close(info->externalHandle);
#endif
- info->exportedHandle = VK_EXT_MEMORY_HANDLE_INVALID;
+ info->externalHandle = VK_EXT_MEMORY_HANDLE_INVALID;
}
}
@@ -1514,15 +1555,20 @@
VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR,
0,
VK_EXT_MEMORY_HANDLE_TYPE_BIT,
- info->exportedHandle,
+ info->externalHandle,
0,
};
+#elif defined(__QNX__)
+ VkImportScreenBufferInfoQNX importInfo = {
+ VK_STRUCTURE_TYPE_IMPORT_SCREEN_BUFFER_INFO_QNX,
+ info->externalHandle,
+ };
#else
VkImportMemoryFdInfoKHR importInfo = {
VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
0,
VK_EXT_MEMORY_HANDLE_TYPE_BIT,
- dupExternalMemory(info->exportedHandle),
+ dupExternalMemory(info->externalHandle),
};
#endif
VkMemoryAllocateInfo allocInfo = {
@@ -1557,15 +1603,21 @@
VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR,
&dedicatedInfo,
VK_EXT_MEMORY_HANDLE_TYPE_BIT,
- info->exportedHandle,
+ info->externalHandle,
0,
};
+#elif defined(__QNX__)
+ VkImportScreenBufferInfoQNX importInfo = {
+ VK_STRUCTURE_TYPE_IMPORT_SCREEN_BUFFER_INFO_QNX,
+ &dedicatedInfo,
+ info->externalHandle,
+ };
#else
VkImportMemoryFdInfoKHR importInfo = {
VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
&dedicatedInfo,
VK_EXT_MEMORY_HANDLE_TYPE_BIT,
- info->exportedHandle,
+ info->externalHandle,
};
#endif
VkMemoryAllocateInfo allocInfo = {
@@ -1794,6 +1846,43 @@
return generateColorBufferVkImageCreateInfo_locked(format, width, height, tiling);
}
+static bool updateExternalMemoryInfo(VK_EXT_MEMORY_HANDLE extMemHandle,
+ const VkMemoryRequirements* pMemReqs,
+ VkEmulation::ExternalMemoryInfo* pInfo) {
+ // Set externalHandle on the output info
+ pInfo->externalHandle = extMemHandle;
+
+#if defined(__QNX__)
+ VkScreenBufferPropertiesQNX screenBufferProps = {
+ VK_STRUCTURE_TYPE_SCREEN_BUFFER_PROPERTIES_QNX,
+ 0,
+ };
+ auto vk = sVkEmulation->dvk;
+ VkResult queryRes =
+ vk->vkGetScreenBufferPropertiesQNX(sVkEmulation->device, extMemHandle, &screenBufferProps);
+ if (VK_SUCCESS != queryRes) {
+ VK_COMMON_ERROR("Failed to get QNX Screen Buffer properties, VK error: %d", queryRes);
+ return false;
+ }
+ if (!((1 << pInfo->typeIndex) & screenBufferProps.memoryTypeBits)) {
+ VK_COMMON_ERROR("QNX Screen buffer can not be imported to memory (typeIndex=%d): %d",
+ pInfo->typeIndex);
+ return false;
+ }
+ if (screenBufferProps.allocationSize < pMemReqs->size) {
+ VK_COMMON_ERROR(
+ "QNX Screen buffer allocationSize (0x%lx) is not large enough for ColorBuffer image "
+ "size requirements (0x%lx)",
+ screenBufferProps.allocationSize, pMemReqs->size);
+ return false;
+ }
+ // Use the actual allocationSize for VkDeviceMemory object creation
+ pInfo->size = screenBufferProps.allocationSize;
+#endif
+
+ return true;
+}
+
// TODO(liyl): Currently we can only specify required memoryProperty
// for a color buffer.
//
@@ -1810,27 +1899,37 @@
// buffers of one type index for image and one type index for buffer
// to begin with, via filtering from the host.
-bool setupVkColorBufferLocked(uint32_t width, uint32_t height, GLenum internalFormat,
- FrameworkFormat frameworkFormat, uint32_t colorBufferHandle,
- bool vulkanOnly, uint32_t memoryProperty) {
- if (!isFormatVulkanCompatible(internalFormat)) {
- VK_COMMON_VERBOSE("Failed to create Vk ColorBuffer: format:%d not compatible.",
- internalFormat);
+bool initializeVkColorBufferLocked(
+ uint32_t colorBufferHandle, VK_EXT_MEMORY_HANDLE extMemHandle = VK_EXT_MEMORY_HANDLE_INVALID) {
+ auto infoPtr = android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
+ // Not initialized
+ if (!infoPtr) {
return false;
}
-
- auto infoPtr = android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
-
- // Already setup
- if (infoPtr) {
+ // Already initialized Vulkan memory and other related Vulkan objects
+ if (infoPtr->initialized) {
return true;
}
+ if (!isFormatVulkanCompatible(infoPtr->internalFormat)) {
+ VK_COMMON_VERBOSE("Failed to create Vk ColorBuffer: format:%d not compatible.",
+ infoPtr->internalFormat);
+ return false;
+ }
+
+ if ((VK_EXT_MEMORY_HANDLE_INVALID != extMemHandle) &&
+ (!sVkEmulation->deviceInfo.supportsExternalMemoryImport)) {
+ VK_COMMON_ERROR(
+ "Failed to initialize Vk ColorBuffer -- extMemHandle provided, but device does "
+ "not support externalMemoryImport");
+ return false;
+ }
+
VkFormat vkFormat;
- bool glCompatible = (frameworkFormat == FRAMEWORK_FORMAT_GL_COMPATIBLE);
- switch (frameworkFormat) {
+ bool glCompatible = (infoPtr->frameworkFormat == FRAMEWORK_FORMAT_GL_COMPATIBLE);
+ switch (infoPtr->frameworkFormat) {
case FrameworkFormat::FRAMEWORK_FORMAT_GL_COMPATIBLE:
- vkFormat = glFormat2VkFormat(internalFormat);
+ vkFormat = glFormat2VkFormat(infoPtr->internalFormat);
break;
case FrameworkFormat::FRAMEWORK_FORMAT_NV12:
vkFormat = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
@@ -1843,24 +1942,16 @@
vkFormat = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
break;
default:
- VK_COMMON_ERROR("WARNING: unhandled framework format %d\n", frameworkFormat);
- vkFormat = glFormat2VkFormat(internalFormat);
+ VK_COMMON_ERROR("WARNING: unhandled framework format %d\n", infoPtr->frameworkFormat);
+ vkFormat = glFormat2VkFormat(infoPtr->internalFormat);
break;
}
- VkEmulation::ColorBufferInfo res;
-
- res.handle = colorBufferHandle;
-
- // TODO
- res.frameworkFormat = frameworkFormat;
- res.frameworkStride = 0;
-
- VkImageTiling tiling = (memoryProperty & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
+ VkImageTiling tiling = (infoPtr->memoryProperty & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
? VK_IMAGE_TILING_LINEAR
: VK_IMAGE_TILING_OPTIMAL;
- std::unique_ptr<VkImageCreateInfo> imageCi =
- generateColorBufferVkImageCreateInfo_locked(vkFormat, width, height, tiling);
+ std::unique_ptr<VkImageCreateInfo> imageCi = generateColorBufferVkImageCreateInfo_locked(
+ vkFormat, infoPtr->width, infoPtr->height, tiling);
// pNext will be filled later.
if (imageCi == nullptr) {
// it can happen if the format is not supported
@@ -1880,7 +1971,8 @@
VkExternalMemoryImageCreateInfo* extImageCiPtr = nullptr;
- if (sVkEmulation->deviceInfo.supportsExternalMemory) {
+ if (sVkEmulation->deviceInfo.supportsExternalMemoryImport ||
+ sVkEmulation->deviceInfo.supportsExternalMemoryExport) {
extImageCiPtr = &extImageCi;
}
@@ -1889,18 +1981,19 @@
auto vk = sVkEmulation->dvk;
VkResult createRes =
- vk->vkCreateImage(sVkEmulation->device, imageCi.get(), nullptr, &res.image);
+ vk->vkCreateImage(sVkEmulation->device, imageCi.get(), nullptr, &infoPtr->image);
if (createRes != VK_SUCCESS) {
// LOG(VERBOSE) << "Failed to create Vulkan image for ColorBuffer "
// << colorBufferHandle;
return false;
}
- bool useDedicated = sVkEmulation->useDedicatedAllocations;
+ bool useDedicated =
+ sVkEmulation->useDedicatedAllocations || (VK_EXT_MEMORY_HANDLE_INVALID != extMemHandle);
- res.imageCreateInfoShallow = vk_make_orphan_copy(*imageCi);
- res.currentLayout = res.imageCreateInfoShallow.initialLayout;
- res.currentQueueFamilyIndex = sVkEmulation->queueFamilyIndex;
+ infoPtr->imageCreateInfoShallow = vk_make_orphan_copy(*imageCi);
+ infoPtr->currentLayout = infoPtr->imageCreateInfoShallow.initialLayout;
+ infoPtr->currentQueueFamilyIndex = sVkEmulation->queueFamilyIndex;
if (!useDedicated && vk->vkGetImageMemoryRequirements2KHR) {
VkMemoryDedicatedRequirements dedicated_reqs{
@@ -1908,28 +2001,28 @@
VkMemoryRequirements2 reqs{VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, &dedicated_reqs};
VkImageMemoryRequirementsInfo2 info{VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2,
- nullptr, res.image};
+ nullptr, infoPtr->image};
vk->vkGetImageMemoryRequirements2KHR(sVkEmulation->device, &info, &reqs);
useDedicated = dedicated_reqs.requiresDedicatedAllocation;
- res.memReqs = reqs.memoryRequirements;
+ infoPtr->memReqs = reqs.memoryRequirements;
} else {
- vk->vkGetImageMemoryRequirements(sVkEmulation->device, res.image, &res.memReqs);
+ vk->vkGetImageMemoryRequirements(sVkEmulation->device, infoPtr->image, &infoPtr->memReqs);
}
// Currently we only care about two memory properties: DEVICE_LOCAL
// and HOST_VISIBLE; other memory properties specified in
// rcSetColorBufferVulkanMode2() call will be ignored for now.
- memoryProperty = memoryProperty &
- (VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
+ infoPtr->memoryProperty = infoPtr->memoryProperty & (VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
- res.memory.size = res.memReqs.size;
+ infoPtr->memory.size = infoPtr->memReqs.size;
// Determine memory type.
- if (memoryProperty) {
- res.memory.typeIndex =
- lastGoodTypeIndexWithMemoryProperties(res.memReqs.memoryTypeBits, memoryProperty);
+ if (infoPtr->memoryProperty) {
+ infoPtr->memory.typeIndex = lastGoodTypeIndexWithMemoryProperties(
+ infoPtr->memReqs.memoryTypeBits, infoPtr->memoryProperty);
} else {
- res.memory.typeIndex = lastGoodTypeIndex(res.memReqs.memoryTypeBits);
+ infoPtr->memory.typeIndex = lastGoodTypeIndex(infoPtr->memReqs.memoryTypeBits);
}
// LOG(VERBOSE) << "ColorBuffer " << colorBufferHandle
@@ -1941,23 +2034,39 @@
// .propertyFlags
// << ", requested memory property: " << memoryProperty;
- bool isHostVisible = memoryProperty & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
- Optional<uint64_t> deviceAlignment =
- isHostVisible ? Optional<uint64_t>(res.memReqs.alignment) : kNullopt;
- Optional<VkImage> dedicatedImage = useDedicated ? Optional<VkImage>(res.image) : kNullopt;
- bool allocRes = allocExternalMemory(vk, &res.memory, true /*actuallyExternal*/, deviceAlignment,
- kNullopt, dedicatedImage);
-
- if (!allocRes) {
- // LOG(VERBOSE) << "Failed to allocate ColorBuffer with Vulkan backing.";
- return false;
+ Optional<VkImage> dedicatedImage = useDedicated ? Optional<VkImage>(infoPtr->image) : kNullopt;
+ if (VK_EXT_MEMORY_HANDLE_INVALID != extMemHandle) {
+ if (!updateExternalMemoryInfo(extMemHandle, &infoPtr->memReqs, &infoPtr->memory)) {
+ VK_COMMON_ERROR(
+ "Failed to update external memory info for ColorBuffer: %d\n",
+ colorBufferHandle);
+ return false;
+ }
+ if (!importExternalMemoryDedicatedImage(vk, sVkEmulation->device, &infoPtr->memory,
+ *dedicatedImage, &infoPtr->memory.memory)) {
+ VK_COMMON_ERROR(
+ "Failed to import external memory with dedicated Image for colorBuffer: %d\n",
+ colorBufferHandle);
+ return false;
+ }
+ } else {
+ bool isHostVisible = infoPtr->memoryProperty & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
+ Optional<uint64_t> deviceAlignment =
+ isHostVisible ? Optional<uint64_t>(infoPtr->memReqs.alignment) : kNullopt;
+ bool allocRes = allocExternalMemory(vk, &infoPtr->memory, true /*actuallyExternal*/,
+ deviceAlignment, kNullopt, dedicatedImage);
+ if (!allocRes) {
+ // LOG(VERBOSE) << "Failed to allocate ColorBuffer with Vulkan backing.";
+ return false;
+ }
}
- res.memory.pageOffset = reinterpret_cast<uint64_t>(res.memory.mappedPtr) % kPageSize;
- res.memory.bindOffset = res.memory.pageOffset ? kPageSize - res.memory.pageOffset : 0u;
+ infoPtr->memory.pageOffset = reinterpret_cast<uint64_t>(infoPtr->memory.mappedPtr) % kPageSize;
+ infoPtr->memory.bindOffset =
+ infoPtr->memory.pageOffset ? kPageSize - infoPtr->memory.pageOffset : 0u;
- VkResult bindImageMemoryRes = vk->vkBindImageMemory(sVkEmulation->device, res.image,
- res.memory.memory, res.memory.bindOffset);
+ VkResult bindImageMemoryRes = vk->vkBindImageMemory(
+ sVkEmulation->device, infoPtr->image, infoPtr->memory.memory, infoPtr->memory.bindOffset);
if (bindImageMemoryRes != VK_SUCCESS) {
fprintf(stderr, "%s: Failed to bind image memory. %d\n", __func__, bindImageMemoryRes);
@@ -1968,9 +2077,9 @@
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
- .image = res.image,
+ .image = infoPtr->image,
.viewType = VK_IMAGE_VIEW_TYPE_2D,
- .format = res.imageCreateInfoShallow.format,
+ .format = infoPtr->imageCreateInfoShallow.format,
.components =
{
.r = VK_COMPONENT_SWIZZLE_IDENTITY,
@@ -1987,7 +2096,8 @@
.layerCount = 1,
},
};
- createRes = vk->vkCreateImageView(sVkEmulation->device, &imageViewCi, nullptr, &res.imageView);
+ createRes =
+ vk->vkCreateImageView(sVkEmulation->device, &imageViewCi, nullptr, &infoPtr->imageView);
if (createRes != VK_SUCCESS) {
// LOG(VERBOSE) << "Failed to create Vulkan image for ColorBuffer "
// << colorBufferHandle;
@@ -1996,15 +2106,39 @@
#if defined(VK_MVK_moltenvk) && defined(__APPLE__)
if (sVkEmulation->instanceSupportsMoltenVK) {
- sVkEmulation->getMTLTextureFunc(res.image, &res.mtlTexture);
- if (!res.mtlTexture) {
+ sVkEmulation->getMTLTextureFunc(infoPtr->image, &infoPtr->mtlTexture);
+ if (!infoPtr->mtlTexture) {
fprintf(stderr, "%s: Failed to get MTLTexture.\n", __func__);
}
- CFRetain(res.mtlTexture);
+ CFRetain(infoPtr->mtlTexture);
}
#endif
+ infoPtr->initialized = true;
+
+ return true;
+}
+
+bool createVkColorBufferLocked(uint32_t width, uint32_t height, GLenum internalFormat,
+ FrameworkFormat frameworkFormat, uint32_t colorBufferHandle,
+ bool vulkanOnly, uint32_t memoryProperty) {
+ auto infoPtr = android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
+ // Already initialized
+ if (infoPtr) {
+ return true;
+ }
+
+ VkEmulation::ColorBufferInfo res;
+
+ res.handle = colorBufferHandle;
+ res.width = width;
+ res.height = height;
+ res.memoryProperty = memoryProperty;
+ res.internalFormat = internalFormat;
+ res.frameworkFormat = frameworkFormat;
+ res.frameworkStride = 0;
+
if (vulkanOnly) {
res.vulkanMode = VkEmulation::VulkanMode::VulkanOnly;
}
@@ -2013,16 +2147,30 @@
return true;
}
-bool setupVkColorBuffer(uint32_t width, uint32_t height, GLenum internalFormat,
- FrameworkFormat frameworkFormat, uint32_t colorBufferHandle,
- bool vulkanOnly, uint32_t memoryProperty) {
+bool createVkColorBuffer(uint32_t width, uint32_t height, GLenum internalFormat,
+ FrameworkFormat frameworkFormat, uint32_t colorBufferHandle,
+ bool vulkanOnly, uint32_t memoryProperty) {
if (!sVkEmulation || !sVkEmulation->live) {
GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "VkEmulation not available.";
}
AutoLock lock(sVkEmulationLock);
- return setupVkColorBufferLocked(width, height, internalFormat, frameworkFormat,
- colorBufferHandle, vulkanOnly, memoryProperty);
+ if (!createVkColorBufferLocked(width, height, internalFormat, frameworkFormat,
+ colorBufferHandle, vulkanOnly, memoryProperty)) {
+ return false;
+ }
+
+ const auto& deviceInfo = sVkEmulation->deviceInfo;
+ if (!deviceInfo.supportsExternalMemoryExport && deviceInfo.supportsExternalMemoryImport) {
+ /* Returns, deferring initialization of the Vulkan components themselves.
+ * Platforms that support import but not export of external memory must
+ * use importExtMemoryHandleToVkColorBuffer(). Otherwise, the colorBuffer
+ * memory can not be externalized.
+ */
+ return true;
+ }
+
+ return initializeVkColorBufferLocked(colorBufferHandle);
}
std::optional<VkColorBufferMemoryExport> exportColorBufferMemory(uint32_t colorBufferHandle) {
@@ -2033,7 +2181,8 @@
AutoLock lock(sVkEmulationLock);
const auto& deviceInfo = sVkEmulation->deviceInfo;
- if (!deviceInfo.supportsExternalMemory || !deviceInfo.glInteropSupported) {
+ if ((!(deviceInfo.supportsExternalMemoryExport || !deviceInfo.supportsExternalMemoryImport)) ||
+ (!deviceInfo.glInteropSupported)) {
return std::nullopt;
}
@@ -2046,7 +2195,8 @@
return std::nullopt;
}
- ManagedDescriptor descriptor(dupExternalMemory(info->memory.exportedHandle));
+#if !defined(__QNX__)
+ ManagedDescriptor descriptor(dupExternalMemory(info->memory.externalHandle));
info->glExported = true;
@@ -2056,6 +2206,9 @@
.linearTiling = info->imageCreateInfoShallow.tiling == VK_IMAGE_TILING_LINEAR,
.dedicatedAllocation = info->memory.dedicatedAllocation,
};
+#else
+ return std::nullopt;
+#endif
}
bool teardownVkColorBufferLocked(uint32_t colorBufferHandle) {
@@ -2067,20 +2220,22 @@
if (!infoPtr) return false;
- auto& info = *infoPtr;
- {
- android::base::AutoLock lock(*sVkEmulation->queueLock);
- VK_CHECK(vk->vkQueueWaitIdle(sVkEmulation->queue));
- }
- vk->vkDestroyImageView(sVkEmulation->device, info.imageView, nullptr);
- vk->vkDestroyImage(sVkEmulation->device, info.image, nullptr);
- freeExternalMemoryLocked(vk, &info.memory);
+ if (infoPtr->initialized) {
+ auto& info = *infoPtr;
+ {
+ android::base::AutoLock lock(*sVkEmulation->queueLock);
+ VK_CHECK(vk->vkQueueWaitIdle(sVkEmulation->queue));
+ }
+ vk->vkDestroyImageView(sVkEmulation->device, info.imageView, nullptr);
+ vk->vkDestroyImage(sVkEmulation->device, info.image, nullptr);
+ freeExternalMemoryLocked(vk, &info.memory);
#ifdef __APPLE__
- if (info.mtlTexture) {
- CFRelease(info.mtlTexture);
- }
+ if (info.mtlTexture) {
+ CFRelease(info.mtlTexture);
+ }
#endif
+ }
sVkEmulation->colorBuffers.erase(colorBufferHandle);
@@ -2094,6 +2249,21 @@
return teardownVkColorBufferLocked(colorBufferHandle);
}
+bool importExtMemoryHandleToVkColorBuffer(uint32_t colorBufferHandle, uint32_t type,
+ VK_EXT_MEMORY_HANDLE extMemHandle) {
+ if (!sVkEmulation || !sVkEmulation->live) {
+ GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "VkEmulation not available.";
+ }
+ if (VK_EXT_MEMORY_HANDLE_INVALID == extMemHandle) {
+ return false;
+ }
+
+ AutoLock lock(sVkEmulationLock);
+ // Initialize the colorBuffer with the external memory handle
+ // Note that this will fail if the colorBuffer memory was previously initialized.
+ return initializeVkColorBufferLocked(colorBufferHandle, extMemHandle);
+}
+
VkEmulation::ColorBufferInfo getColorBufferInfo(uint32_t colorBufferHandle) {
VkEmulation::ColorBufferInfo res;
@@ -2528,7 +2698,7 @@
return VK_EXT_MEMORY_HANDLE_INVALID;
}
- return infoPtr->memory.exportedHandle;
+ return infoPtr->memory.externalHandle;
}
bool setColorBufferVulkanMode(uint32_t colorBuffer, uint32_t vulkanMode) {
@@ -2684,7 +2854,8 @@
};
VkExternalMemoryBufferCreateInfo* extBufferCiPtr = nullptr;
- if (sVkEmulation->deviceInfo.supportsExternalMemory) {
+ if (sVkEmulation->deviceInfo.supportsExternalMemoryImport ||
+ sVkEmulation->deviceInfo.supportsExternalMemoryExport) {
extBufferCiPtr = &extBufferCi;
}
@@ -2818,7 +2989,7 @@
return VK_EXT_MEMORY_HANDLE_INVALID;
}
- return infoPtr->memory.exportedHandle;
+ return infoPtr->memory.externalHandle;
}
bool readBufferToBytes(uint32_t bufferHandle, uint64_t offset, uint64_t size, void* outBytes) {
@@ -3021,6 +3192,15 @@
res &= ~VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA;
res |= VK_EXT_MEMORY_HANDLE_TYPE_BIT;
}
+
+#if defined(__QNX__)
+ // QNX only: Replace DMA_BUF_BIT_EXT with SCREEN_BUFFER_BIT_QNX for host calls
+ if (bits & VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT) {
+ res &= ~VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
+ res |= VK_EXT_MEMORY_HANDLE_TYPE_BIT;
+ }
+#endif
+
return res;
}
@@ -3316,12 +3496,16 @@
constexpr const uint32_t kArbitraryWidth = 64;
constexpr const uint32_t kArbitraryHeight = 64;
constexpr const uint32_t kArbitraryHandle = std::numeric_limits<uint32_t>::max();
- if (!setupVkColorBufferLocked(kArbitraryWidth, kArbitraryHeight, GL_RGBA8,
- FrameworkFormat::FRAMEWORK_FORMAT_GL_COMPATIBLE, kArbitraryHandle,
- true, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) {
+ if (!createVkColorBufferLocked(kArbitraryWidth, kArbitraryHeight, GL_RGBA8,
+ FrameworkFormat::FRAMEWORK_FORMAT_GL_COMPATIBLE,
+ kArbitraryHandle, true, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) {
ERR("Failed to setup memory type index test ColorBuffer.");
return std::nullopt;
}
+ if (!initializeVkColorBufferLocked(kArbitraryHandle)) {
+ ERR("Failed to initialize memory type index test ColorBuffer.");
+ return std::nullopt;
+ }
uint32_t memoryTypeIndex = 0;
if (!getColorBufferAllocationInfoLocked(kArbitraryHandle, nullptr, &memoryTypeIndex, nullptr,