Commit 43e33165 by David 'Digit' Turner Committed by David Turner

[vulkan] Simplify vk::Semaphore implementation.

This CL simplifies the implementation of vk::Semaphore by getting rid of vk::Semaphore::Impl (moving its fields into vk::Semaphore itself). This requires a minor change to the vk::Semaphore constructor which now takes an allocator parameter. The latter is used to allocate the "External" instance on demand. Before the CL, said instance was 'allocated' from a fixed storage area inside the Impl class. Note that this doesn't change the external semaphore's behaviour. In particular, only one implementation can live in the source tree at the moment, while the Vulkan specification makes it clear that it should be possible to export a single VkSemaphore to several types of platform-specific handles (though this doesn't seem to be tested by the Vulkan-CTS). This last issue will be addressed in a future CL. Bug: 140421736 Change-Id: I3610d9e7e8cb8e49368b658d157408cbd23ee6db Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/39052 Kokoro-Presubmit: kokoro <noreply+kokoro@google.com> Reviewed-by: 's avatarBen Clayton <bclayton@google.com> Tested-by: 's avatarDavid Turner <digit@google.com>
parent 068dd89c
...@@ -33,68 +33,41 @@ ...@@ -33,68 +33,41 @@
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <mutex>
#include <utility> #include <utility>
namespace vk { namespace vk {
// An implementation of VkSemaphore based on Marl primitives. namespace {
class Semaphore::Impl
struct SemaphoreCreateInfo
{ {
public: bool exportSemaphore = false;
// Create a new instance. The external instance will be allocated only // Create a new instance. The external instance will be allocated only
// the pCreateInfo->pNext chain indicates it needs to be exported. // the pCreateInfo->pNext chain indicates it needs to be exported.
Impl(const VkSemaphoreCreateInfo *pCreateInfo) SemaphoreCreateInfo(const VkSemaphoreCreateInfo *pCreateInfo)
{ {
bool exportSemaphore = false;
for(const auto *nextInfo = reinterpret_cast<const VkBaseInStructure *>(pCreateInfo->pNext); for(const auto *nextInfo = reinterpret_cast<const VkBaseInStructure *>(pCreateInfo->pNext);
nextInfo != nullptr; nextInfo = nextInfo->pNext) nextInfo != nullptr; nextInfo = nextInfo->pNext)
{ {
if(nextInfo->sType == VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO) if(nextInfo->sType == VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO)
{ {
const auto *exportInfo = reinterpret_cast<const VkExportSemaphoreCreateInfo *>(nextInfo); const auto *exportInfo = reinterpret_cast<const VkExportSemaphoreCreateInfo *>(nextInfo);
if(exportInfo->handleTypes != External::kExternalSemaphoreHandleType) exportSemaphore = true;
if(exportInfo->handleTypes != Semaphore::External::kExternalSemaphoreHandleType)
{ {
UNIMPLEMENTED("exportInfo->handleTypes"); UNIMPLEMENTED("exportInfo->handleTypes");
} }
exportSemaphore = true;
break; break;
} }
} }
if(exportSemaphore)
{
allocateExternalNoInit();
external->init();
}
}
~Impl()
{
deallocateExternal();
}
// Deallocate the External semaphore if any.
void deallocateExternal()
{
if(external)
{
external->~External();
external = nullptr;
}
} }
};
// Allocate the external semaphore. } // namespace
// Note that this does not allocate the internal resource, which must be
// performed by calling external->init(), or importing one using
// a platform-specific external->importXXX(...) method.
void allocateExternalNoInit()
{
external = new(externalStorage) External();
}
void wait() void Semaphore::wait()
{ {
if(external) if(external)
{ {
if(!external->tryWait()) if(!external->tryWait())
...@@ -122,10 +95,10 @@ public: ...@@ -122,10 +95,10 @@ public:
{ {
waitInternal(); waitInternal();
} }
} }
void signal() void Semaphore::signal()
{ {
if(external) if(external)
{ {
// Assumes that signalling an external semaphore is non-blocking, // Assumes that signalling an external semaphore is non-blocking,
...@@ -136,22 +109,18 @@ public: ...@@ -136,22 +109,18 @@ public:
{ {
signalInternal(); signalInternal();
} }
} }
private:
// Necessary to make ::importXXX() and ::exportXXX() simpler.
friend Semaphore;
void waitInternal() void Semaphore::waitInternal()
{ {
// Wait on the marl condition variable only. // Wait on the marl condition variable only.
std::unique_lock<std::mutex> lock(mutex); std::unique_lock<std::mutex> lock(mutex);
condition.wait(lock, [this] { return this->signaled; }); condition.wait(lock, [this] { return this->signaled; });
signaled = false; // Vulkan requires resetting after waiting. signaled = false; // Vulkan requires resetting after waiting.
} }
void signalInternal() void Semaphore::signalInternal()
{ {
// Signal the marl condition variable only. // Signal the marl condition variable only.
std::unique_lock<std::mutex> lock(mutex); std::unique_lock<std::mutex> lock(mutex);
if(!signaled) if(!signaled)
...@@ -159,103 +128,102 @@ private: ...@@ -159,103 +128,102 @@ private:
signaled = true; signaled = true;
condition.notify_one(); condition.notify_one();
} }
} }
// Implementation of a non-external semaphore based on Marl.
std::mutex mutex;
marl::ConditionVariable condition;
bool signaled = false;
// Optional external semaphore data might be referenced and stored here.
External *external = nullptr;
// Set to true if |external| comes from a temporary import.
bool temporaryImport = false;
alignas(External) char externalStorage[sizeof(External)];
};
Semaphore::Semaphore(const VkSemaphoreCreateInfo *pCreateInfo, void *mem) Semaphore::Semaphore(const VkSemaphoreCreateInfo *pCreateInfo, void *mem, const VkAllocationCallbacks *pAllocator)
: allocator(pAllocator)
{ {
impl = new(mem) Impl(pCreateInfo); SemaphoreCreateInfo info(pCreateInfo);
if(info.exportSemaphore)
{
allocateExternal();
external->init();
}
} }
void Semaphore::destroy(const VkAllocationCallbacks *pAllocator) void Semaphore::destroy(const VkAllocationCallbacks *pAllocator)
{ {
impl->~Impl(); deallocateExternal();
vk::deallocate(impl, pAllocator);
} }
size_t Semaphore::ComputeRequiredAllocationSize(const VkSemaphoreCreateInfo *pCreateInfo) size_t Semaphore::ComputeRequiredAllocationSize(const VkSemaphoreCreateInfo *pCreateInfo)
{ {
return sizeof(Semaphore::Impl); // Semaphore::External instance is created and destroyed on demand so return 0 here.
return 0;
} }
void Semaphore::wait() void Semaphore::allocateExternal()
{ {
impl->wait(); ASSERT(external == nullptr);
external = reinterpret_cast<Semaphore::External *>(
vk::allocate(sizeof(Semaphore::External), vk::REQUIRED_MEMORY_ALIGNMENT, allocator));
new(external) Semaphore::External();
} }
void Semaphore::signal() void Semaphore::deallocateExternal()
{ {
impl->signal(); if(external)
{
vk::deallocate(external, allocator);
external = nullptr;
}
} }
#if SWIFTSHADER_EXTERNAL_SEMAPHORE_OPAQUE_FD #if SWIFTSHADER_EXTERNAL_SEMAPHORE_OPAQUE_FD
VkResult Semaphore::importFd(int fd, bool temporaryImport) VkResult Semaphore::importFd(int fd, bool tempImport)
{ {
std::unique_lock<std::mutex> lock(impl->mutex); std::unique_lock<std::mutex> lock(mutex);
if(!impl->external) if(!external)
{ {
impl->allocateExternalNoInit(); allocateExternal();
} }
VkResult result = impl->external->importFd(fd); VkResult result = external->importFd(fd);
if(result != VK_SUCCESS) if(result != VK_SUCCESS)
{ {
impl->deallocateExternal(); deallocateExternal();
} }
else else
{ {
impl->temporaryImport = temporaryImport; temporaryImport = tempImport;
} }
return result; return result;
} }
VkResult Semaphore::exportFd(int *pFd) const VkResult Semaphore::exportFd(int *pFd)
{ {
std::unique_lock<std::mutex> lock(impl->mutex); std::unique_lock<std::mutex> lock(mutex);
if(!impl->external) if(!external)
{ {
TRACE("Cannot export non-external semaphore"); TRACE("Cannot export non-external semaphore");
return VK_ERROR_INVALID_EXTERNAL_HANDLE; return VK_ERROR_INVALID_EXTERNAL_HANDLE;
} }
return impl->external->exportFd(pFd); return external->exportFd(pFd);
} }
#endif // SWIFTSHADER_EXTERNAL_SEMAPHORE_OPAQUE_FD #endif // SWIFTSHADER_EXTERNAL_SEMAPHORE_OPAQUE_FD
#if VK_USE_PLATFORM_FUCHSIA #if VK_USE_PLATFORM_FUCHSIA
VkResult Semaphore::importHandle(zx_handle_t handle, bool temporaryImport) VkResult Semaphore::importHandle(zx_handle_t handle, bool tempImport)
{ {
std::unique_lock<std::mutex> lock(impl->mutex); std::unique_lock<std::mutex> lock(mutex);
if(!impl->external) if(!external)
{ {
impl->allocateExternalNoInit(); allocateExternal();
} }
// NOTE: Imports are just moving a handle so cannot fail. // NOTE: Imports are just moving a handle so cannot fail.
impl->external->importHandle(handle); external->importHandle(handle);
impl->temporaryImport = temporaryImport; temporaryImport = tempImport;
return VK_SUCCESS; return VK_SUCCESS;
} }
VkResult Semaphore::exportHandle(zx_handle_t *pHandle) const VkResult Semaphore::exportHandle(zx_handle_t *pHandle)
{ {
std::unique_lock<std::mutex> lock(impl->mutex); std::unique_lock<std::mutex> lock(mutex);
if(!impl->external) if(!external)
{ {
TRACE("Cannot export non-external semaphore"); TRACE("Cannot export non-external semaphore");
return VK_ERROR_INVALID_EXTERNAL_HANDLE; return VK_ERROR_INVALID_EXTERNAL_HANDLE;
} }
return impl->external->exportHandle(pHandle); return external->exportHandle(pHandle);
} }
#endif // VK_USE_PLATFORM_FUCHSIA #endif // VK_USE_PLATFORM_FUCHSIA
......
...@@ -18,6 +18,9 @@ ...@@ -18,6 +18,9 @@
#include "VkConfig.h" #include "VkConfig.h"
#include "VkObject.hpp" #include "VkObject.hpp"
#include "marl/conditionvariable.h"
#include <mutex>
#if VK_USE_PLATFORM_FUCHSIA #if VK_USE_PLATFORM_FUCHSIA
# include <zircon/types.h> # include <zircon/types.h>
#endif #endif
...@@ -27,7 +30,7 @@ namespace vk { ...@@ -27,7 +30,7 @@ namespace vk {
class Semaphore : public Object<Semaphore, VkSemaphore> class Semaphore : public Object<Semaphore, VkSemaphore>
{ {
public: public:
Semaphore(const VkSemaphoreCreateInfo *pCreateInfo, void *mem); Semaphore(const VkSemaphoreCreateInfo *pCreateInfo, void *mem, const VkAllocationCallbacks *pAllocator);
void destroy(const VkAllocationCallbacks *pAllocator); void destroy(const VkAllocationCallbacks *pAllocator);
static size_t ComputeRequiredAllocationSize(const VkSemaphoreCreateInfo *pCreateInfo); static size_t ComputeRequiredAllocationSize(const VkSemaphoreCreateInfo *pCreateInfo);
...@@ -44,18 +47,30 @@ public: ...@@ -44,18 +47,30 @@ public:
#if SWIFTSHADER_EXTERNAL_SEMAPHORE_OPAQUE_FD #if SWIFTSHADER_EXTERNAL_SEMAPHORE_OPAQUE_FD
VkResult importFd(int fd, bool temporaryImport); VkResult importFd(int fd, bool temporaryImport);
VkResult exportFd(int *pFd) const; VkResult exportFd(int *pFd);
#endif #endif
#if VK_USE_PLATFORM_FUCHSIA #if VK_USE_PLATFORM_FUCHSIA
VkResult importHandle(zx_handle_t handle, bool temporaryImport); VkResult importHandle(zx_handle_t handle, bool temporaryImport);
VkResult exportHandle(zx_handle_t *pHandle) const; VkResult exportHandle(zx_handle_t *pHandle);
#endif #endif
private:
class External; class External;
class Impl;
Impl *impl = nullptr; private:
void waitInternal();
void signalInternal();
void allocateExternal();
void deallocateExternal();
const VkAllocationCallbacks *allocator = nullptr;
std::mutex mutex;
marl::ConditionVariable condition;
bool signaled = false;
External *external = nullptr;
bool temporaryImport = false;
}; };
static inline Semaphore *Cast(VkSemaphore object) static inline Semaphore *Cast(VkSemaphore object)
......
...@@ -1082,7 +1082,7 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateSemaphore(VkDevice device, const VkSemaph ...@@ -1082,7 +1082,7 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateSemaphore(VkDevice device, const VkSemaph
UNIMPLEMENTED("pCreateInfo->flags"); UNIMPLEMENTED("pCreateInfo->flags");
} }
return vk::Semaphore::Create(pAllocator, pCreateInfo, pSemaphore); return vk::Semaphore::Create(pAllocator, pCreateInfo, pSemaphore, pAllocator);
} }
VKAPI_ATTR void VKAPI_CALL vkDestroySemaphore(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks *pAllocator) VKAPI_ATTR void VKAPI_CALL vkDestroySemaphore(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks *pAllocator)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment