[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/BUILD.gn b/src/Vulkan/BUILD.gn
index 8c6141b..8e19658 100644
--- a/src/Vulkan/BUILD.gn
+++ b/src/Vulkan/BUILD.gn
@@ -113,6 +113,7 @@
     "VkQueue.cpp",
     "VkRenderPass.cpp",
     "VkSampler.cpp",
+    "VkSemaphore.cpp",
     "VkShaderModule.cpp",
     "Vulkan.rc",
     "libVulkan.cpp",
diff --git a/src/Vulkan/VkSemaphore.cpp b/src/Vulkan/VkSemaphore.cpp
new file mode 100644
index 0000000..04a1c26
--- /dev/null
+++ b/src/Vulkan/VkSemaphore.cpp
@@ -0,0 +1,78 @@
+// 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 "VkSemaphore.hpp"
+
+#include "marl/conditionvariable.h"
+#include <mutex>
+
+namespace vk
+{
+
+// An implementation of VkSemaphore based on Marl primitives.
+class Semaphore::Impl
+{
+public:
+	Impl() = default;
+
+	void wait()
+	{
+		std::unique_lock<std::mutex> lock(mutex);
+		condition.wait(lock, [this]{ return this->signaled; });
+		signaled = false;  // Vulkan requires resetting after waiting.
+	}
+
+	void signal()
+	{
+		std::unique_lock<std::mutex> lock(mutex);
+		if (!signaled)
+		{
+			signaled = true;
+			condition.notify_one();
+		}
+	}
+
+private:
+	std::mutex mutex;
+	marl::ConditionVariable condition;
+	bool signaled = false;
+};
+
+Semaphore::Semaphore(const VkSemaphoreCreateInfo* pCreateInfo, void* mem)
+{
+	impl = new (mem) Impl();
+}
+
+void Semaphore::destroy(const VkAllocationCallbacks* pAllocator)
+{
+	impl->~Impl();
+	vk::deallocate(impl, pAllocator);
+}
+
+size_t Semaphore::ComputeRequiredAllocationSize(const VkSemaphoreCreateInfo* pCreateInfo)
+{
+	return sizeof(Semaphore::Impl);
+}
+
+void Semaphore::wait()
+{
+	impl->wait();
+}
+
+void Semaphore::signal()
+{
+	impl->signal();
+}
+
+}  // namespace vk
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)