[vulkan]: Implement VkSemaphore using Marl primitives.

Proper implementation of a VkSemaphore using an std::mutex
and a marl::ConditionVariable. This should make the implementation
compatible with both fibers and threads at the same time.

A future CL will add platform-specific implementations to cover
external semaphores as well. Which explains why the implementation
details are hidden from VkSemaphore.hpp.

Bug: b/140421726
Change-Id: I1db55493a41db0eb60ce9181fe864253db09f4f8
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/35933
Tested-by: David Turner <digit@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/src/Vulkan/VkSemaphore.hpp b/src/Vulkan/VkSemaphore.hpp
index d3ecae4..1f9b160 100644
--- a/src/Vulkan/VkSemaphore.hpp
+++ b/src/Vulkan/VkSemaphore.hpp
@@ -23,31 +23,24 @@
 class Semaphore : public Object<Semaphore, VkSemaphore>
 {
 public:
-	Semaphore(const VkSemaphoreCreateInfo* pCreateInfo, void* mem) {}
+	Semaphore(const VkSemaphoreCreateInfo* pCreateInfo, void* mem);
+	void destroy(const VkAllocationCallbacks* pAllocator);
 
-	static size_t ComputeRequiredAllocationSize(const VkSemaphoreCreateInfo* pCreateInfo)
-	{
-		return 0;
-	}
+	static size_t ComputeRequiredAllocationSize(const VkSemaphoreCreateInfo* pCreateInfo);
 
-	void wait()
-	{
-		// Semaphores are noop for now
-	}
+	void wait();
 
 	void wait(const VkPipelineStageFlags& flag)
 	{
-		// VkPipelineStageFlags is the pipeline stage at which the semaphore wait will occur
-
-		// Semaphores are noop for now
+		// NOTE: not sure what else to do here?
+		wait();
 	}
 
-	void signal()
-	{
-		// Semaphores are noop for now
-	}
+	void signal();
 
 private:
+	class Impl;
+	Impl* impl = nullptr;
 };
 
 static inline Semaphore* Cast(VkSemaphore object)