[vulkan] Implement external semaphore support for Fuchsia
This corresponds to the VK_FUCHSIA_external_semaphore extension
which uses a Zircon event object to communicate across processes.
Bug: b/140421726
Change-Id: I47b235d4ff7d787491738422bda6fdf853803ab7
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/35969
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Tested-by: David Turner <digit@google.com>
diff --git a/src/Vulkan/BUILD.gn b/src/Vulkan/BUILD.gn
index 067e32e..c42388d 100644
--- a/src/Vulkan/BUILD.gn
+++ b/src/Vulkan/BUILD.gn
@@ -92,6 +92,10 @@
sources += [
"VkSemaphoreExternalLinux.hpp",
]
+ } else if (is_fuchsia) {
+ sources += [
+ "VkSemaphoreExternalFuchsia.hpp",
+ ]
} else {
sources += [
"VkSemaphoreExternalNone.hpp",
diff --git a/src/Vulkan/VkConfig.h b/src/Vulkan/VkConfig.h
index 9badfd8..ddb8d89 100644
--- a/src/Vulkan/VkConfig.h
+++ b/src/Vulkan/VkConfig.h
@@ -88,4 +88,8 @@
#define SWIFTSHADER_EXTERNAL_SEMAPHORE_LINUX_MEMFD 1
#endif
+#if VK_USE_PLATFORM_FUCHSIA
+#define SWIFTSHADER_EXTERNAL_SEMAPHORE_ZIRCON_EVENT 1
+#endif
+
#endif // VK_CONFIG_HPP_
diff --git a/src/Vulkan/VkGetProcAddress.cpp b/src/Vulkan/VkGetProcAddress.cpp
index eecfff8..4cc6a2d 100644
--- a/src/Vulkan/VkGetProcAddress.cpp
+++ b/src/Vulkan/VkGetProcAddress.cpp
@@ -346,6 +346,17 @@
}
},
#endif
+
+#if SWIFTSHADER_EXTERNAL_SEMAPHORE_ZIRCON_EVENT
+ // VK_FUCHSIA_external_semaphore
+ {
+ VK_FUCHSIA_EXTERNAL_SEMAPHORE_EXTENSION_NAME,
+ {
+ MAKE_VULKAN_DEVICE_ENTRY(vkGetSemaphoreZirconHandleFUCHSIA),
+ MAKE_VULKAN_DEVICE_ENTRY(vkImportSemaphoreZirconHandleFUCHSIA),
+ }
+ },
+#endif
};
#undef MAKE_VULKAN_DEVICE_ENTRY
diff --git a/src/Vulkan/VkPhysicalDevice.cpp b/src/Vulkan/VkPhysicalDevice.cpp
index 187c4bb..044ab15 100644
--- a/src/Vulkan/VkPhysicalDevice.cpp
+++ b/src/Vulkan/VkPhysicalDevice.cpp
@@ -381,6 +381,15 @@
return;
}
#endif
+#if SWIFTSHADER_EXTERNAL_SEMAPHORE_ZIRCON_EVENT
+ if (pExternalSemaphoreInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TEMP_ZIRCON_EVENT_BIT_FUCHSIA)
+ {
+ pExternalSemaphoreProperties->compatibleHandleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TEMP_ZIRCON_EVENT_BIT_FUCHSIA;
+ pExternalSemaphoreProperties->exportFromImportedHandleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TEMP_ZIRCON_EVENT_BIT_FUCHSIA;
+ pExternalSemaphoreProperties->externalSemaphoreFeatures = VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT | VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT;
+ return;
+ }
+#endif
pExternalSemaphoreProperties->compatibleHandleTypes = 0;
pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
pExternalSemaphoreProperties->externalSemaphoreFeatures = 0;
diff --git a/src/Vulkan/VkSemaphore.cpp b/src/Vulkan/VkSemaphore.cpp
index 62ff418..b495ebb 100644
--- a/src/Vulkan/VkSemaphore.cpp
+++ b/src/Vulkan/VkSemaphore.cpp
@@ -18,6 +18,8 @@
#if SWIFTSHADER_EXTERNAL_SEMAPHORE_LINUX_MEMFD
#include "VkSemaphoreExternalLinux.hpp"
+#elif SWIFTSHADER_EXTERNAL_SEMAPHORE_ZIRCON_EVENT
+#include "VkSemaphoreExternalFuchsia.hpp"
#else
#include "VkSemaphoreExternalNone.hpp"
#endif
@@ -226,4 +228,30 @@
}
#endif // SWIFTSHADER_EXTERNAL_SEMAPHORE_LINUX_MEMFD
+#if SWIFTSHADER_EXTERNAL_SEMAPHORE_ZIRCON_EVENT
+VkResult Semaphore::importHandle(zx_handle_t handle, bool temporaryImport)
+{
+ std::unique_lock<std::mutex> lock(impl->mutex);
+ if (!impl->external)
+ {
+ impl->allocateExternalNoInit();
+ }
+ // NOTE: Imports are just moving a handle so cannot fail.
+ impl->external->importHandle(handle);
+ impl->temporaryImport = temporaryImport;
+ return VK_SUCCESS;
+}
+
+VkResult Semaphore::exportHandle(zx_handle_t *pHandle) const
+{
+ std::unique_lock<std::mutex> lock(impl->mutex);
+ if (!impl->external)
+ {
+ TRACE("Cannot export non-external semaphore");
+ return VK_ERROR_INVALID_EXTERNAL_HANDLE;
+ }
+ return impl->external->exportHandle(pHandle);
+}
+#endif // SWIFTSHADER_EXTERNAL_SEMAPHORE_ZIRCON_EVENT
+
} // namespace vk
diff --git a/src/Vulkan/VkSemaphore.hpp b/src/Vulkan/VkSemaphore.hpp
index d691c41..c0a8b04 100644
--- a/src/Vulkan/VkSemaphore.hpp
+++ b/src/Vulkan/VkSemaphore.hpp
@@ -18,6 +18,10 @@
#include "VkConfig.h"
#include "VkObject.hpp"
+#if SWIFTSHADER_EXTERNAL_SEMAPHORE_ZIRCON_EVENT
+#include <zircon/types.h>
+#endif
+
namespace vk
{
@@ -44,6 +48,11 @@
VkResult exportFd(int* pFd) const;
#endif
+#if SWIFTSHADER_EXTERNAL_SEMAPHORE_ZIRCON_EVENT
+ VkResult importHandle(zx_handle_t handle, bool temporaryImport);
+ VkResult exportHandle(zx_handle_t *pHandle) const;
+#endif
+
private:
class External;
class Impl;
diff --git a/src/Vulkan/VkSemaphoreExternalFuchsia.hpp b/src/Vulkan/VkSemaphoreExternalFuchsia.hpp
new file mode 100644
index 0000000..9e3e23b
--- /dev/null
+++ b/src/Vulkan/VkSemaphoreExternalFuchsia.hpp
@@ -0,0 +1,131 @@
+// 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.
+
+#ifndef VK_SEMAPHORE_EXTERNAL_FUCHSIA_H_
+#define VK_SEMAPHORE_EXTERNAL_FUCHSIA_H_
+
+#include "VkDebug.hpp"
+
+#include <zircon/syscalls.h>
+
+// An external semaphore implementation for the Zircon kernel using a simple
+// Zircon event handle. This matches
+// VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TEMP_ZIRCON_EVENT_BIT_FUCHSIA
+// which is not official yet but used by Fuchsia at the moment.
+
+namespace vk
+{
+
+class Semaphore::External {
+public:
+ // The type of external semaphore handle types supported by this implementation.
+ static const VkExternalSemaphoreHandleTypeFlags kExternalSemaphoreHandleType =
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TEMP_ZIRCON_EVENT_BIT_FUCHSIA;
+
+ // Default constructor. Note that one should call either init() or
+ // importFd() before any call to wait() or signal().
+ External() = default;
+
+ ~External()
+ {
+ zx_handle_close(handle);
+ }
+
+ void init()
+ {
+ zx_status_t status = zx_event_create(0, &handle);
+ if (status != ZX_OK)
+ {
+ ABORT("zx_event_create() returned %d", status);
+ }
+ }
+
+ void importHandle(zx_handle_t new_handle)
+ {
+ zx_handle_close(handle);
+ handle = new_handle;
+ }
+
+ VkResult exportHandle(zx_handle_t* pHandle) const
+ {
+ zx_handle_t new_handle = ZX_HANDLE_INVALID;
+ zx_status_t status = zx_handle_duplicate(handle, ZX_RIGHT_SAME_RIGHTS, &new_handle);
+ if (status != ZX_OK)
+ {
+ TRACE("zx_handle_duplicate() returned %d", status);
+ return VK_ERROR_INVALID_EXTERNAL_HANDLE;
+ }
+ *pHandle = new_handle;
+ return VK_SUCCESS;
+ }
+
+ void wait()
+ {
+ zx_signals_t observed = 0;
+ zx_status_t status = zx_object_wait_one(
+ handle, ZX_EVENT_SIGNALED, ZX_TIME_INFINITE, &observed);
+ if (status != ZX_OK)
+ {
+ ABORT("zx_object_wait_one() returned %d", status);
+ }
+ if (observed != ZX_EVENT_SIGNALED)
+ {
+ ABORT("zx_object_wait_one() returned observed %x (%x expected)", observed, ZX_EVENT_SIGNALED);
+ }
+ // Need to unsignal the event now, as required by the Vulkan spec.
+ status = zx_object_signal(handle, ZX_EVENT_SIGNALED, 0);
+ if (status != ZX_OK)
+ {
+ ABORT("zx_object_signal() returned %d", status);
+ }
+ }
+
+ bool tryWait()
+ {
+ zx_signals_t observed = 0;
+ zx_status_t status = zx_object_wait_one(
+ handle, ZX_EVENT_SIGNALED, zx_clock_get_monotonic(), &observed);
+ if (status != ZX_OK)
+ {
+ ABORT("zx_object_wait_one() returned %d", status);
+ }
+ if (observed != ZX_EVENT_SIGNALED)
+ {
+ return false;
+ }
+ // Need to unsignal the event now, as required by the Vulkan spec.
+ status = zx_object_signal(handle, ZX_EVENT_SIGNALED, 0);
+ if (status != ZX_OK)
+ {
+ ABORT("zx_object_signal() returned %d", status);
+ }
+ return true;
+ }
+
+ void signal()
+ {
+ zx_status_t status = zx_object_signal(handle, 0, ZX_EVENT_SIGNALED);
+ if (status != ZX_OK)
+ {
+ ABORT("zx_object_signal() returned %d", status);
+ }
+ }
+
+private:
+ zx_handle_t handle = ZX_HANDLE_INVALID;
+};
+
+} // namespace vk
+
+#endif // VK_SEMAPHORE_EXTERNAL_FUCHSIA_H_
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index b7a9b1a..ebb2aed 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -233,6 +233,9 @@
#if SWIFTSHADER_EXTERNAL_SEMAPHORE_LINUX_MEMFD
{ VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, VK_KHR_EXTERNAL_SEMAPHORE_FD_SPEC_VERSION },
#endif
+#if SWIFTSHADER_EXTERNAL_SEMAPHORE_ZIRCON_EVENT
+ { VK_FUCHSIA_EXTERNAL_SEMAPHORE_EXTENSION_NAME, VK_FUCHSIA_EXTERNAL_SEMAPHORE_SPEC_VERSION },
+#endif
{ VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME, VK_EXT_PROVOKING_VERTEX_SPEC_VERSION },
};
@@ -1022,6 +1025,42 @@
}
#endif // SWIFTSHADER_EXTERNAL_SEMAPHORE_LINUX_MEMFD
+#if SWIFTSHADER_EXTERNAL_SEMAPHORE_ZIRCON_EVENT
+VKAPI_ATTR VkResult VKAPI_CALL vkImportSemaphoreZirconHandleFUCHSIA(
+ VkDevice device,
+ const VkImportSemaphoreZirconHandleInfoFUCHSIA* pImportSemaphoreZirconHandleInfo)
+{
+ TRACE("(VkDevice device = %p, const VkImportSemaphoreZirconHandleInfoFUCHSIA* pImportSemaphoreZirconHandleInfo = %p)",
+ device, pImportSemaphoreZirconHandleInfo);
+
+ if (pImportSemaphoreZirconHandleInfo->handleType != VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TEMP_ZIRCON_EVENT_BIT_FUCHSIA)
+ {
+ UNIMPLEMENTED("pImportSemaphoreZirconHandleInfo->handleType");
+ }
+ bool temporaryImport = (pImportSemaphoreZirconHandleInfo->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT) != 0;
+
+ return vk::Cast(pImportSemaphoreZirconHandleInfo->semaphore)->importHandle(
+ pImportSemaphoreZirconHandleInfo->handle,
+ temporaryImport);
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreZirconHandleFUCHSIA(
+ VkDevice device,
+ const VkSemaphoreGetZirconHandleInfoFUCHSIA* pGetZirconHandleInfo,
+ zx_handle_t* pZirconHandle)
+{
+ TRACE("(VkDevice device = %p, const VkSemaphoreGetZirconHandleInfoFUCHSIA* pGetZirconHandleInfo = %p, zx_handle_t* pZirconHandle = %p)",
+ device, static_cast<const void*>(pGetZirconHandleInfo), static_cast<void*>(pZirconHandle));
+
+ if (pGetZirconHandleInfo->handleType != VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TEMP_ZIRCON_EVENT_BIT_FUCHSIA)
+ {
+ UNIMPLEMENTED("pGetZirconHandleInfo->handleType");
+ }
+
+ return vk::Cast(pGetZirconHandleInfo->semaphore)->exportHandle(pZirconHandle);
+}
+#endif // SWIFTSHADER_EXTERNAL_SEMAPHORE_ZIRCON_EVENT
+
VKAPI_ATTR VkResult VKAPI_CALL vkCreateEvent(VkDevice device, const VkEventCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkEvent* pEvent)
{
TRACE("(VkDevice device = %p, const VkEventCreateInfo* pCreateInfo = %p, const VkAllocationCallbacks* pAllocator = %p, VkEvent* pEvent = %p)",