[vulkan] Implement VK_FUCHSIA_external_memory extension.
This implements external memory using a Zircon VMO handle
that can be transferred between Fuchsia processes easily.
Bug: b/140419396
Change-Id: I81cecec35b218eb22f3318ddec7b790b89e5ce09
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/36168
Tested-by: David Turner <digit@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Vulkan/VkDeviceMemory.cpp b/src/Vulkan/VkDeviceMemory.cpp
index 6f3ad1c..014557f 100644
--- a/src/Vulkan/VkDeviceMemory.cpp
+++ b/src/Vulkan/VkDeviceMemory.cpp
@@ -51,6 +51,13 @@
}
#endif
+#if VK_USE_PLATFORM_FUCHSIA
+ virtual VkResult exportHandle(zx_handle_t *pHandle) const
+ {
+ return VK_ERROR_INVALID_EXTERNAL_HANDLE;
+ }
+#endif
+
protected:
ExternalBase() = default;
};
@@ -219,6 +226,10 @@
# endif
#endif
+#if VK_USE_PLATFORM_FUCHSIA
+# include "VkDeviceMemoryExternalFuchsia.hpp"
+#endif
+
namespace vk {
static void findTraits(const VkMemoryAllocateInfo *pAllocateInfo,
@@ -236,6 +247,12 @@
return;
}
#endif
+#if VK_USE_PLATFORM_FUCHSIA
+ if(parseCreateInfo<zircon::VmoExternalMemory>(pAllocateInfo, pTraits))
+ {
+ return;
+ }
+#endif
if(parseCreateInfo<ExternalMemoryHost>(pAllocateInfo, pTraits))
{
return;
@@ -348,4 +365,11 @@
}
#endif
+#if VK_USE_PLATFORM_FUCHSIA
+VkResult DeviceMemory::exportHandle(zx_handle_t *pHandle) const
+{
+ return external->exportHandle(pHandle);
+}
+#endif
+
} // namespace vk
diff --git a/src/Vulkan/VkDeviceMemory.hpp b/src/Vulkan/VkDeviceMemory.hpp
index e99fa89..ea014d6 100644
--- a/src/Vulkan/VkDeviceMemory.hpp
+++ b/src/Vulkan/VkDeviceMemory.hpp
@@ -36,6 +36,10 @@
static VkResult getAhbProperties(const struct AHardwareBuffer *buffer, VkAndroidHardwareBufferPropertiesANDROID *pProperties);
#endif
+#if VK_USE_PLATFORM_FUCHSIA
+ VkResult exportHandle(zx_handle_t *pHandle) const;
+#endif
+
void destroy(const VkAllocationCallbacks *pAllocator);
VkResult allocate();
VkResult map(VkDeviceSize offset, VkDeviceSize size, void **ppData);
diff --git a/src/Vulkan/VkDeviceMemoryExternalFuchsia.hpp b/src/Vulkan/VkDeviceMemoryExternalFuchsia.hpp
new file mode 100644
index 0000000..0352046
--- /dev/null
+++ b/src/Vulkan/VkDeviceMemoryExternalFuchsia.hpp
@@ -0,0 +1,178 @@
+// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "VkStringify.hpp"
+
+#include "System/Debug.hpp"
+
+#include <zircon/process.h>
+#include <zircon/syscalls.h>
+
+namespace zircon {
+
+class VmoExternalMemory : public vk::DeviceMemory::ExternalBase
+{
+public:
+ // Helper struct to parse the VkMemoryAllocateInfo.pNext chain and
+ // extract relevant information related to the handle type supported
+ // by this DeviceMemory::ExternalBase subclass.
+ struct AllocateInfo
+ {
+ bool importHandle = false;
+ bool exportHandle = false;
+ zx_handle_t handle = ZX_HANDLE_INVALID;
+
+ AllocateInfo() = default;
+
+ // Parse the VkMemoryAllocateInfo->pNext chain to initialize a AllocateInfo.
+ AllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo)
+ {
+ const auto *extInfo = reinterpret_cast<const VkBaseInStructure *>(pAllocateInfo->pNext);
+ while(extInfo)
+ {
+ switch(extInfo->sType)
+ {
+ case VK_STRUCTURE_TYPE_TEMP_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA:
+ {
+ const auto *importInfo = reinterpret_cast<const VkImportMemoryZirconHandleInfoFUCHSIA *>(extInfo);
+
+ if(importInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA)
+ {
+ UNSUPPORTED("importInfo->handleType");
+ }
+ importHandle = true;
+ handle = importInfo->handle;
+ break;
+ }
+ case VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO:
+ {
+ const auto *exportInfo = reinterpret_cast<const VkExportMemoryAllocateInfo *>(extInfo);
+
+ if(exportInfo->handleTypes != VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA)
+ {
+ UNSUPPORTED("exportInfo->handleTypes");
+ }
+ exportHandle = true;
+ break;
+ }
+
+ default:
+ WARN("VkMemoryAllocateInfo->pNext sType = %s", vk::Stringify(extInfo->sType).c_str());
+ }
+ extInfo = extInfo->pNext;
+ }
+ }
+ };
+
+ static const VkExternalMemoryHandleTypeFlagBits typeFlagBit = VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA;
+
+ static bool supportsAllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo)
+ {
+ AllocateInfo info(pAllocateInfo);
+ return info.importHandle || info.exportHandle;
+ }
+
+ explicit VmoExternalMemory(const VkMemoryAllocateInfo *pAllocateInfo)
+ : allocateInfo(pAllocateInfo)
+ {
+ }
+
+ ~VmoExternalMemory()
+ {
+ closeVmo();
+ }
+
+ VkResult allocate(size_t size, void **pBuffer) override
+ {
+ if(allocateInfo.importHandle)
+ {
+ // NOTE: handle ownership is passed to the VkDeviceMemory.
+ vmoHandle = allocateInfo.handle;
+ }
+ else
+ {
+ ASSERT(allocateInfo.exportHandle);
+ zx_status_t status = zx_vmo_create(size, 0, &vmoHandle);
+ if(status != ZX_OK)
+ {
+ TRACE("zx_vmo_create() returned %d", status);
+ return VK_ERROR_OUT_OF_DEVICE_MEMORY;
+ }
+ }
+
+ // Now map it directly.
+ zx_vaddr_t addr = 0;
+ zx_status_t status = zx_vmar_map(zx_vmar_root_self(),
+ ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
+ 0, // vmar_offset
+ vmoHandle,
+ 0, // vmo_offset
+ size,
+ &addr);
+ if(status != ZX_OK)
+ {
+ TRACE("zx_vmar_map() failed with %d", status);
+ return VK_ERROR_MEMORY_MAP_FAILED;
+ }
+ *pBuffer = reinterpret_cast<void *>(addr);
+ return VK_SUCCESS;
+ }
+
+ void deallocate(void *buffer, size_t size) override
+ {
+ zx_status_t status = zx_vmar_unmap(zx_vmar_root_self(),
+ reinterpret_cast<zx_vaddr_t>(buffer),
+ size);
+ if(status != ZX_OK)
+ {
+ TRACE("zx_vmar_unmap() failed with %d", status);
+ }
+ closeVmo();
+ }
+
+ VkExternalMemoryHandleTypeFlagBits getFlagBit() const override
+ {
+ return typeFlagBit;
+ }
+
+ VkResult exportHandle(zx_handle_t *pHandle) const override
+ {
+ if(vmoHandle == ZX_HANDLE_INVALID)
+ {
+ return VK_ERROR_INVALID_EXTERNAL_HANDLE;
+ }
+ zx_status_t status = zx_handle_duplicate(vmoHandle, ZX_RIGHT_SAME_RIGHTS, pHandle);
+ if(status != ZX_OK)
+ {
+ TRACE("zx_handle_duplicate() returned %d", status);
+ return VK_ERROR_INVALID_EXTERNAL_HANDLE;
+ }
+ return VK_SUCCESS;
+ }
+
+private:
+ void closeVmo()
+ {
+ if(vmoHandle != ZX_HANDLE_INVALID)
+ {
+ zx_handle_close(vmoHandle);
+ vmoHandle = ZX_HANDLE_INVALID;
+ }
+ }
+
+ zx_handle_t vmoHandle = ZX_HANDLE_INVALID;
+ AllocateInfo allocateInfo;
+};
+
+} // namespace zircon
diff --git a/src/Vulkan/VkGetProcAddress.cpp b/src/Vulkan/VkGetProcAddress.cpp
index 64ac9f8..95310d3 100644
--- a/src/Vulkan/VkGetProcAddress.cpp
+++ b/src/Vulkan/VkGetProcAddress.cpp
@@ -397,6 +397,16 @@
MAKE_VULKAN_DEVICE_ENTRY(vkGetMemoryAndroidHardwareBufferANDROID),
} },
#endif
+
+#if VK_USE_PLATFORM_FUCHSIA
+ // VK_FUCHSIA_external_memory
+ {
+ VK_FUCHSIA_EXTERNAL_MEMORY_EXTENSION_NAME,
+ {
+ MAKE_VULKAN_DEVICE_ENTRY(vkGetMemoryZirconHandleFUCHSIA),
+ MAKE_VULKAN_DEVICE_ENTRY(vkGetMemoryZirconHandlePropertiesFUCHSIA),
+ } },
+#endif
};
#undef MAKE_VULKAN_DEVICE_ENTRY
diff --git a/src/Vulkan/VkPhysicalDevice.cpp b/src/Vulkan/VkPhysicalDevice.cpp
index 331187a..fcb09da 100644
--- a/src/Vulkan/VkPhysicalDevice.cpp
+++ b/src/Vulkan/VkPhysicalDevice.cpp
@@ -43,6 +43,15 @@
return;
}
#endif
+#if VK_USE_PLATFORM_FUCHSIA
+ if(handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA)
+ {
+ properties->compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA;
+ properties->exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA;
+ properties->externalMemoryFeatures = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT;
+ return;
+ }
+#endif
properties->compatibleHandleTypes = 0;
properties->exportFromImportedHandleTypes = 0;
properties->externalMemoryFeatures = 0;
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index 3e3e648..07d2889 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -348,6 +348,7 @@
#if VK_USE_PLATFORM_FUCHSIA
{ VK_FUCHSIA_EXTERNAL_SEMAPHORE_EXTENSION_NAME, VK_FUCHSIA_EXTERNAL_SEMAPHORE_SPEC_VERSION },
+ { VK_FUCHSIA_EXTERNAL_MEMORY_EXTENSION_NAME, VK_FUCHSIA_EXTERNAL_MEMORY_SPEC_VERSION },
#endif
{ VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME, VK_EXT_PROVOKING_VERTEX_SPEC_VERSION },
};
@@ -946,6 +947,10 @@
case VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID:
break;
#endif
+#if VK_USE_PLATFORM_FUCHSIA
+ case VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA:
+ break;
+#endif
default:
UNSUPPORTED("exportInfo->handleTypes %u", exportInfo->handleTypes);
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
@@ -967,6 +972,18 @@
}
break;
}
+#if VK_USE_PLATFORM_FUCHSIA
+ case VK_STRUCTURE_TYPE_TEMP_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA:
+ {
+ auto *importInfo = reinterpret_cast<const VkImportMemoryZirconHandleInfoFUCHSIA *>(allocationInfo);
+ if(importInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA)
+ {
+ UNSUPPORTED("importInfo->handleType %u", importInfo->handleType);
+ return VK_ERROR_INVALID_EXTERNAL_HANDLE;
+ }
+ break;
+ }
+#endif // VK_USE_PLATFORM_FUCHSIA
default:
LOG_TRAP("pAllocateInfo->pNext sType = %s", vk::Stringify(allocationInfo->sType).c_str());
break;
@@ -1039,6 +1056,45 @@
return VK_SUCCESS;
}
#endif // SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
+#if VK_USE_PLATFORM_FUCHSIA
+VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryZirconHandleFUCHSIA(VkDevice device, const VkMemoryGetZirconHandleInfoFUCHSIA *pGetHandleInfo, zx_handle_t *pHandle)
+{
+ TRACE("(VkDevice device = %p, const VkMemoryGetZirconHandleInfoFUCHSIA* pGetHandleInfo = %p, zx_handle_t* pHandle = %p",
+ device, pGetHandleInfo, pHandle);
+
+ if(pGetHandleInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA)
+ {
+ UNSUPPORTED("pGetHandleInfo->handleType %u", pGetHandleInfo->handleType);
+ return VK_ERROR_INVALID_EXTERNAL_HANDLE;
+ }
+ return vk::Cast(pGetHandleInfo->memory)->exportHandle(pHandle);
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryZirconHandlePropertiesFUCHSIA(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, zx_handle_t handle, VkMemoryZirconHandlePropertiesFUCHSIA *pMemoryZirconHandleProperties)
+{
+ TRACE("(VkDevice device = %p, VkExternalMemoryHandleTypeFlagBits handleType = %x, zx_handle_t handle = %d, VkMemoryZirconHandlePropertiesFUCHSIA* pMemoryZirconHandleProperties = %p)",
+ device, handleType, handle, pMemoryZirconHandleProperties);
+
+ if(handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA)
+ {
+ UNSUPPORTED("handleType %u", handleType);
+ return VK_ERROR_INVALID_EXTERNAL_HANDLE;
+ }
+
+ if(handle == ZX_HANDLE_INVALID)
+ {
+ return VK_ERROR_INVALID_EXTERNAL_HANDLE;
+ }
+
+ const VkPhysicalDeviceMemoryProperties &memoryProperties =
+ vk::Cast(device)->getPhysicalDevice()->getMemoryProperties();
+
+ // All SwiftShader memory types support this!
+ pMemoryZirconHandleProperties->memoryTypeBits = (1U << memoryProperties.memoryTypeCount) - 1U;
+
+ return VK_SUCCESS;
+}
+#endif // VK_USE_PLATFORM_FUCHSIA
VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryHostPointerPropertiesEXT(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, const void *pHostPointer, VkMemoryHostPointerPropertiesEXT *pMemoryHostPointerProperties)
{