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/ColorBuffer.cpp b/host/ColorBuffer.cpp index 06f2969..6a8f58d 100644 --- a/host/ColorBuffer.cpp +++ b/host/ColorBuffer.cpp
@@ -375,6 +375,30 @@ return true; } +bool ColorBuffer::importNativeResource(void* nativeResource, uint32_t type, bool preserveContent) { + switch (type) { + case RESOURCE_TYPE_VK_EXT_MEMORY_HANDLE: { + if (mColorBufferGl) { + GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) + << "Native resource import type %s is invalid when GL emulation is active. " + << "Use RESOURCE_TYPE_EGL_NATIVE_PIXMAP of RESOURCE_TYPE_EGL_IMAGE imports " + "instead."; + return false; + } else if (!mColorBufferVk) { + GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) + << "Vulkan emulation must be available for RESOURCE_TYPE_VK_EXT_MEMORY_HANDLE " + "import."; + return false; + } + return mColorBufferVk->importExtMemoryHandle(nativeResource, type, preserveContent); + } + default: + GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) + << "Unrecognized type for ColorBuffer::importNativeResource."; + return false; + } +} + bool ColorBuffer::glOpBlitFromCurrentReadBuffer() { if (!mColorBufferGl) { GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "ColorBufferGl not available.";
diff --git a/host/ColorBuffer.h b/host/ColorBuffer.h index 47bf96c..f519fe7 100644 --- a/host/ColorBuffer.h +++ b/host/ColorBuffer.h
@@ -84,6 +84,7 @@ bool flushFromVkBytes(const void* bytes, size_t bytesSize); bool invalidateForGl(); bool invalidateForVk(); + bool importNativeResource(void* nativeResource, uint32_t type, bool preserveContent); GLuint glOpGetTexture(); bool glOpBlitFromCurrentReadBuffer();
diff --git a/host/FrameBuffer.cpp b/host/FrameBuffer.cpp index d69b7e6..f7f0016 100644 --- a/host/FrameBuffer.cpp +++ b/host/FrameBuffer.cpp
@@ -3465,6 +3465,11 @@ return colorBuffer->glOpImportEglNativePixmap(resource, preserveContent); case RESOURCE_TYPE_EGL_IMAGE: return colorBuffer->glOpImportEglImage(resource, preserveContent); + + // Note: Additional non-EGL resource-types can be added here, and will + // be propagated through color-buffer import functionality + case RESOURCE_TYPE_VK_EXT_MEMORY_HANDLE: + return colorBuffer->importNativeResource(resource, type, preserveContent); default: ERR("Error: unsupported resource type: %u", type); return false;
diff --git a/host/include/gfxstream/virtio-gpu-gfxstream-renderer-unstable.h b/host/include/gfxstream/virtio-gpu-gfxstream-renderer-unstable.h index 4276f15..429bfa5 100644 --- a/host/include/gfxstream/virtio-gpu-gfxstream-renderer-unstable.h +++ b/host/include/gfxstream/virtio-gpu-gfxstream-renderer-unstable.h
@@ -75,6 +75,7 @@ // types #define STREAM_RENDERER_PLATFORM_RESOURCE_TYPE_EGL_NATIVE_PIXMAP 0x01 #define STREAM_RENDERER_PLATFORM_RESOURCE_TYPE_EGL_IMAGE 0x02 +#define STREAM_RENDERER_PLATFORM_RESOURCE_TYPE_VK_EXT_MEMORY_HANDLE 0x03 // uses #define STREAM_RENDERER_PLATFORM_RESOURCE_USE_PRESERVE 0x10
diff --git a/host/tests/Vulkan_unittest.cpp b/host/tests/Vulkan_unittest.cpp index 23d392a..b3cf5f7 100644 --- a/host/tests/Vulkan_unittest.cpp +++ b/host/tests/Vulkan_unittest.cpp
@@ -472,10 +472,10 @@ TEST_F(VulkanFrameBufferTest, VkColorBufferWithoutMemoryProperties) { // Create a color buffer without any memory properties restriction. - EXPECT_TRUE(setupVkColorBuffer(mWidth, mHeight, GL_RGBA, FRAMEWORK_FORMAT_GL_COMPATIBLE, - kArbitraryColorBufferHandle, true, /* vulkanOnly */ - 0 /* memoryProperty */ - )); + EXPECT_TRUE(createVkColorBuffer(mWidth, mHeight, GL_RGBA, FRAMEWORK_FORMAT_GL_COMPATIBLE, + kArbitraryColorBufferHandle, true, /* vulkanOnly */ + 0 /* memoryProperty */ + )); EXPECT_TRUE(teardownVkColorBuffer(kArbitraryColorBufferHandle)); } @@ -537,9 +537,9 @@ } // Create a color buffer with the target memory property flags. - EXPECT_TRUE(setupVkColorBuffer(mWidth, mHeight, GL_RGBA, FRAMEWORK_FORMAT_GL_COMPATIBLE, - kArbitraryColorBufferHandle, true, /* vulkanOnly */ - static_cast<uint32_t>(kTargetMemoryPropertyFlags))); + EXPECT_TRUE(createVkColorBuffer(mWidth, mHeight, GL_RGBA, FRAMEWORK_FORMAT_GL_COMPATIBLE, + kArbitraryColorBufferHandle, true, /* vulkanOnly */ + static_cast<uint32_t>(kTargetMemoryPropertyFlags))); uint32_t allocatedTypeIndex = 0u; EXPECT_TRUE(getColorBufferAllocationInfo(kArbitraryColorBufferHandle, nullptr,
diff --git a/host/vulkan/ColorBufferVk.cpp b/host/vulkan/ColorBufferVk.cpp index 72860c4..0d569b3 100644 --- a/host/vulkan/ColorBufferVk.cpp +++ b/host/vulkan/ColorBufferVk.cpp
@@ -24,8 +24,8 @@ uint32_t height, GLenum format, FrameworkFormat frameworkFormat, bool vulkanOnly, uint32_t memoryProperty) { - if (!setupVkColorBuffer(width, height, format, frameworkFormat, handle, vulkanOnly, - memoryProperty)) { + if (!createVkColorBuffer(width, height, format, frameworkFormat, handle, vulkanOnly, + memoryProperty)) { GL_LOG("Failed to create ColorBufferVk:%d", handle); return nullptr; } @@ -58,5 +58,14 @@ return updateColorBufferFromBytes(mHandle, x, y, w, h, bytes); } +bool ColorBufferVk::importExtMemoryHandle(void* nativeResource, uint32_t type, + bool preserveContent) { + // TODO: Any need to support preserveContent? + assert(!preserveContent); + VK_EXT_MEMORY_HANDLE extMemoryHandle = + *reinterpret_cast<VK_EXT_MEMORY_HANDLE*>(&nativeResource); + return importExtMemoryHandleToVkColorBuffer(mHandle, type, extMemoryHandle); +} + } // namespace vk } // namespace gfxstream
diff --git a/host/vulkan/ColorBufferVk.h b/host/vulkan/ColorBufferVk.h index c049bf3..8364c93 100644 --- a/host/vulkan/ColorBufferVk.h +++ b/host/vulkan/ColorBufferVk.h
@@ -36,6 +36,8 @@ bool updateFromBytes(const std::vector<uint8_t>& bytes); bool updateFromBytes(uint32_t x, uint32_t y, uint32_t w, uint32_t h, const void* bytes); + bool importExtMemoryHandle(void* nativeResource, uint32_t type, bool preserveContent); + private: ColorBufferVk(uint32_t handle);
diff --git a/host/vulkan/VkAndroidNativeBuffer.cpp b/host/vulkan/VkAndroidNativeBuffer.cpp index 26435d1..095d387 100644 --- a/host/vulkan/VkAndroidNativeBuffer.cpp +++ b/host/vulkan/VkAndroidNativeBuffer.cpp
@@ -141,7 +141,8 @@ auto emu = getGlobalVkEmulation(); if (emu && emu->live) { - externalMemoryCompatible = emu->deviceInfo.supportsExternalMemory; + externalMemoryCompatible = emu->deviceInfo.supportsExternalMemoryImport && + emu->deviceInfo.supportsExternalMemoryExport; } bool colorBufferExportedToGl = false;
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,
diff --git a/host/vulkan/VkCommonOperations.h b/host/vulkan/VkCommonOperations.h index 958a57f..ae81350 100644 --- a/host/vulkan/VkCommonOperations.h +++ b/host/vulkan/VkCommonOperations.h
@@ -52,13 +52,20 @@ typedef void* HANDLE; #endif -// External memory objects are HANDLE on Windows and fd's on POSIX systems. -#ifdef _WIN32 +#if defined(_WIN32) +// External memory objects are HANDLE on Windows typedef HANDLE VK_EXT_MEMORY_HANDLE; // corresponds to INVALID_HANDLE_VALUE #define VK_EXT_MEMORY_HANDLE_INVALID (VK_EXT_MEMORY_HANDLE)(uintptr_t)(-1) #define VK_EXT_MEMORY_HANDLE_TYPE_BIT VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT +#elif defined(__QNX__) +#include <screen/screen.h> +// External memory objects are screen_buffer_t handles on QNX +typedef screen_buffer_t VK_EXT_MEMORY_HANDLE; +#define VK_EXT_MEMORY_HANDLE_INVALID (VK_EXT_MEMORY_HANDLE) nullptr +#define VK_EXT_MEMORY_HANDLE_TYPE_BIT VK_EXTERNAL_MEMORY_HANDLE_TYPE_SCREEN_BUFFER_BIT_QNX #else +// External memory objects are fd's on other POSIX systems typedef int VK_EXT_MEMORY_HANDLE; #define VK_EXT_MEMORY_HANDLE_INVALID (-1) #define VK_EXT_MEMORY_HANDLE_TYPE_BIT VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT @@ -174,7 +181,8 @@ struct DeviceSupportInfo { bool hasGraphicsQueueFamily = false; bool hasComputeQueueFamily = false; - bool supportsExternalMemory = false; + bool supportsExternalMemoryImport = false; + bool supportsExternalMemoryExport = false; bool supportsIdProperties = false; bool supportsDriverProperties = false; bool hasSamplerYcbcrConversionExtension = false; @@ -226,8 +234,8 @@ // guest physical address. uintptr_t gpa = 0u; - VK_EXT_MEMORY_HANDLE exportedHandle = VK_EXT_MEMORY_HANDLE_INVALID; - bool actuallyExternal = false; + VK_EXT_MEMORY_HANDLE externalHandle = VK_EXT_MEMORY_HANDLE_INVALID; + bool dedicatedAllocation = false; }; @@ -286,8 +294,14 @@ uint32_t handle; + /* Set in create(), before initialize() */ + uint32_t width; + uint32_t height; + GLenum internalFormat; + uint32_t memoryProperty; int frameworkFormat; int frameworkStride; + bool initialized = false; VkImage image = VK_NULL_HANDLE; VkImageView imageView = VK_NULL_HANDLE; @@ -435,12 +449,15 @@ uint32_t height, VkImageTiling tiling); -bool setupVkColorBuffer(uint32_t width, uint32_t height, GLenum format, - FrameworkFormat frameworkFormat, uint32_t colorBufferHandle, - bool vulkanOnly, uint32_t memoryProperty); +bool createVkColorBuffer(uint32_t width, uint32_t height, GLenum format, + FrameworkFormat frameworkFormat, uint32_t colorBufferHandle, + bool vulkanOnly, uint32_t memoryProperty); bool teardownVkColorBuffer(uint32_t colorBufferHandle); +bool importExtMemoryHandleToVkColorBuffer(uint32_t colorBufferHandle, uint32_t type, + VK_EXT_MEMORY_HANDLE extMemHandle); + VkEmulation::ColorBufferInfo getColorBufferInfo(uint32_t colorBufferHandle); VK_EXT_MEMORY_HANDLE getColorBufferExtMemoryHandle(uint32_t colorBufferHandle);
diff --git a/host/vulkan/VkDecoderGlobalState.cpp b/host/vulkan/VkDecoderGlobalState.cpp index 065c9b6..765e17b 100644 --- a/host/vulkan/VkDecoderGlobalState.cpp +++ b/host/vulkan/VkDecoderGlobalState.cpp
@@ -127,6 +127,31 @@ } } +#if defined(_WIN32) +// External sync objects are HANDLE on Windows +typedef HANDLE VK_EXT_SYNC_HANDLE; +// corresponds to INVALID_HANDLE_VALUE +#define VK_EXT_SYNC_HANDLE_INVALID (VK_EXT_SYNC_HANDLE)(uintptr_t)(-1) +#else +// External sync objects are fd's on other POSIX systems +typedef int VK_EXT_SYNC_HANDLE; +#define VK_EXT_SYNC_HANDLE_INVALID (-1) +#endif + +VK_EXT_SYNC_HANDLE dupExternalSync(VK_EXT_SYNC_HANDLE h) { +#ifdef _WIN32 + auto myProcessHandle = GetCurrentProcess(); + VK_EXT_SYNC_HANDLE res; + DuplicateHandle(myProcessHandle, h, // source process and handle + myProcessHandle, &res, // target process and pointer to handle + 0 /* desired access (ignored) */, true /* inherit */, + DUPLICATE_SAME_ACCESS /* same access option */); + return res; +#else + return dup(h); +#endif +} + // A list of device extensions that should not be passed to the host driver. // These will mainly include Vulkan features that we emulate ourselves. static constexpr const char* const kEmulatedDeviceExtensions[] = { @@ -142,6 +167,10 @@ VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME, VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME, VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, +#if defined(__QNX__) + VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, + VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME, +#endif }; // A list of instance extensions that should not be passed to the host driver. @@ -2086,7 +2115,7 @@ return VK_ERROR_INVALID_EXTERNAL_HANDLE; } - VK_EXT_MEMORY_HANDLE handle = dupExternalMemory(infoPtr->externalHandle); + VK_EXT_SYNC_HANDLE handle = dupExternalSync(infoPtr->externalHandle); VkImportSemaphoreWin32HandleInfoKHR win32ImportInfo = { VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR, @@ -2117,7 +2146,7 @@ pGetFdInfo->semaphore, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT, }; - VK_EXT_MEMORY_HANDLE handle; + VK_EXT_SYNC_HANDLE handle; VkResult result = vk->vkGetSemaphoreWin32HandleKHR(device, &getWin32, &handle); if (result != VK_SUCCESS) { return result; @@ -2146,7 +2175,7 @@ #ifndef _WIN32 const auto& ite = mSemaphoreInfo.find(semaphore); if (ite != mSemaphoreInfo.end() && - (ite->second.externalHandle != VK_EXT_MEMORY_HANDLE_INVALID)) { + (ite->second.externalHandle != VK_EXT_SYNC_HANDLE_INVALID)) { close(ite->second.externalHandle); } #endif @@ -3409,6 +3438,12 @@ VK_EXT_MEMORY_HANDLE_INVALID, L"", }; +#elif defined(__QNX__) + VkImportScreenBufferInfoQNX importInfo{ + VK_STRUCTURE_TYPE_IMPORT_SCREEN_BUFFER_INFO_QNX, + 0, + VK_EXT_MEMORY_HANDLE_INVALID, + }; #else VkImportMemoryFdInfoKHR importInfo{ VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR, @@ -3454,6 +3489,9 @@ return VK_ERROR_OUT_OF_DEVICE_MEMORY; } +#if defined(__QNX__) + importInfo.buffer = cbExtMemoryHandle; +#else externalMemoryHandle = ManagedDescriptor(dupExternalMemory(cbExtMemoryHandle)); #ifdef _WIN32 @@ -3461,6 +3499,7 @@ #else importInfo.fd = externalMemoryHandle.get().value_or(-1); #endif +#endif vk_append_struct(&structChainIter, &importInfo); } } @@ -3489,6 +3528,9 @@ return VK_ERROR_OUT_OF_DEVICE_MEMORY; } +#if defined(__QNX__) + importInfo.buffer = bufferExtMemoryHandle; +#else bufferExtMemoryHandle = dupExternalMemory(bufferExtMemoryHandle); #ifdef _WIN32 @@ -3496,6 +3538,7 @@ #else importInfo.fd = bufferExtMemoryHandle; #endif +#endif vk_append_struct(&structChainIter, &importInfo); } } @@ -3577,7 +3620,7 @@ ERR("Failed vkAllocateMemory: missing descriptor info."); return VK_ERROR_OUT_OF_DEVICE_MEMORY; } -#if defined(__linux__) || defined(__QNX__) +#if defined(__linux__) importInfo.fd = rawDescriptor; #endif @@ -3832,7 +3875,6 @@ const auto& props = emu->deviceInfo.physdevProps; res.supportsVulkan1_1 = props.apiVersion >= VK_API_VERSION_1_1; - res.supportsExternalMemory = emu->deviceInfo.supportsExternalMemory; res.useDeferredCommands = emu->useDeferredCommands; res.useCreateResourcesWithRequirements = emu->useCreateResourcesWithRequirements; @@ -5795,6 +5837,12 @@ if (hasDeviceExtension(properties, VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME)) { res.push_back(VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME); } +#elif defined(__QNX__) + // Note: VK_QNX_external_memory_screen_buffer is not supported in API translation, + // decoding, etc. However, push name to indicate external memory support to guest + if (hasDeviceExtension(properties, VK_QNX_EXTERNAL_MEMORY_SCREEN_BUFFER_EXTENSION_NAME)) { + res.push_back(VK_QNX_EXTERNAL_MEMORY_SCREEN_BUFFER_EXTENSION_NAME); + } #elif __unix__ if (hasDeviceExtension(properties, VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME)) { res.push_back(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME); @@ -6532,7 +6580,7 @@ struct SemaphoreInfo { VkDevice device; int externalHandleId = 0; - VK_EXT_MEMORY_HANDLE externalHandle = VK_EXT_MEMORY_HANDLE_INVALID; + VK_EXT_SYNC_HANDLE externalHandle = VK_EXT_SYNC_HANDLE_INVALID; }; struct DescriptorSetLayoutInfo {
diff --git a/host/vulkan/VkDecoderGlobalState.h b/host/vulkan/VkDecoderGlobalState.h index b8cb5be..4b2d0dc 100644 --- a/host/vulkan/VkDecoderGlobalState.h +++ b/host/vulkan/VkDecoderGlobalState.h
@@ -406,7 +406,6 @@ struct HostFeatureSupport { bool supportsVulkan = false; bool supportsVulkan1_1 = false; - bool supportsExternalMemory = false; bool useDeferredCommands = false; bool useCreateResourcesWithRequirements = false; uint32_t apiVersion = 0;
diff --git a/host/vulkan/cereal/common/vk_struct_id.h b/host/vulkan/cereal/common/vk_struct_id.h index fc321ec..0953a43 100644 --- a/host/vulkan/cereal/common/vk_struct_id.h +++ b/host/vulkan/cereal/common/vk_struct_id.h
@@ -71,4 +71,10 @@ REGISTER_VK_STRUCT_ID(VkMemoryOpaqueCaptureAddressAllocateInfo, VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO); REGISTER_VK_STRUCT_ID(VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT) +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +REGISTER_VK_STRUCT_ID(VkPhysicalDeviceExternalMemoryScreenBufferFeaturesQNX, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_SCREEN_BUFFER_FEATURES_QNX); +REGISTER_VK_STRUCT_ID(VkImportScreenBufferInfoQNX, VK_STRUCTURE_TYPE_IMPORT_SCREEN_BUFFER_INFO_QNX); +#endif + #undef REGISTER_VK_STRUCT_ID
diff --git a/host/vulkan/cereal/meson.build b/host/vulkan/cereal/meson.build index d9f917d..b59d839 100644 --- a/host/vulkan/cereal/meson.build +++ b/host/vulkan/cereal/meson.build
@@ -15,6 +15,10 @@ '-DVK_GOOGLE_address_space', ] +if host_machine.system() == 'qnx' + cereal_cpp_args += '-DVK_USE_PLATFORM_SCREEN_QNX' +endif + lib_vulkan_cereal = static_library( 'cereal', files_lib_cereal,