Vulkan dispatchable objects

Vulkan has a few dispatchable objects: Instance, Device, Physical Device,
Command Buffer and Queue. These objects, when loaded through an ICD, are
constrained to have a bit of memory allocated at the beginning of these
objects to contain loader data.

In order to do this, a wrapper class, DispatchableObject, was created to handle
pointing directly to the loader data when casting to the associated VK handle
and similarly back to a pointer to the internal object. Note that Queue, being
allocated within another object, and not directly through the API, simply have
the loader data at the beginning of the class, without requiring a wrapper class.

Also, since all these object are allocated through a custom placement new
operator, they have to be deallocated through an associated destroy() function,
so the DispatchableObject destructor is deleted, in order to prevent these
objects from being released any other way.

Bug b/116336664

Change-Id: Iac749f6adcba0eaf7557f0df876ac0474081d9cc
Reviewed-on: https://swiftshader-review.googlesource.com/c/20948
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Vulkan/VkCommandBuffer.cpp b/src/Vulkan/VkCommandBuffer.cpp
new file mode 100644
index 0000000..8b2f36c
--- /dev/null
+++ b/src/Vulkan/VkCommandBuffer.cpp
@@ -0,0 +1,26 @@
+// Copyright 2018 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 "VkCommandBuffer.hpp"
+
+namespace vk
+{
+
+CommandBuffer::CommandBuffer(VkCommandBufferLevel pLevel) : level(pLevel)
+{
+	pipelines[VK_PIPELINE_BIND_POINT_GRAPHICS] = VK_NULL_HANDLE;
+	pipelines[VK_PIPELINE_BIND_POINT_COMPUTE] = VK_NULL_HANDLE;
+}
+
+} // namespace vk
\ No newline at end of file
diff --git a/src/Vulkan/VkCommandBuffer.hpp b/src/Vulkan/VkCommandBuffer.hpp
new file mode 100644
index 0000000..0044437
--- /dev/null
+++ b/src/Vulkan/VkCommandBuffer.hpp
@@ -0,0 +1,45 @@
+// Copyright 2018 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_COMMAND_BUFFER_HPP_
+#define VK_COMMAND_BUFFER_HPP_
+
+#include "VkConfig.h"
+#include "VkObject.hpp"
+
+namespace vk
+{
+
+class CommandBuffer
+{
+public:
+	static constexpr VkSystemAllocationScope GetAllocationScope() { return VK_SYSTEM_ALLOCATION_SCOPE_OBJECT; }
+
+	CommandBuffer(VkCommandBufferLevel pLevel);
+
+private:
+	VkCommandBufferLevel level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+	VkPipeline pipelines[VK_PIPELINE_BIND_POINT_RANGE_SIZE];
+};
+
+using DispatchableCommandBuffer = DispatchableObject<CommandBuffer, VkCommandBuffer>;
+
+static inline CommandBuffer* Cast(VkCommandBuffer object)
+{
+	return DispatchableCommandBuffer::Cast(object);
+}
+
+} // namespace vk
+
+#endif // VK_COMMAND_BUFFER_HPP_
diff --git a/src/Vulkan/VkConfig.h b/src/Vulkan/VkConfig.h
new file mode 100644
index 0000000..f68a688
--- /dev/null
+++ b/src/Vulkan/VkConfig.h
@@ -0,0 +1,54 @@
+// Copyright 2018 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_CONFIG_HPP_
+#define VK_CONFIG_HPP_
+
+namespace vk
+{
+
+// Note: Constant array initialization requires a string literal.
+//       constexpr char* or char[] does not work for that purpose.
+#define SWIFTSHADER_DEVICE_NAME "SwiftShader Device" // Max length: VK_MAX_PHYSICAL_DEVICE_NAME_SIZE
+#define SWIFTSHADER_UUID "SwiftShaderUUID" // Max length: VK_UUID_SIZE
+
+enum
+{
+	DRIVER_VERSION = 1,
+	VENDOR_ID = 0x1AE0, // Google
+	DEVICE_ID = 0xC0DE, // SwiftShader
+};
+
+enum
+{
+	REQUIRED_MEMORY_ALIGNMENT = 8, // For 64 bit formats on ARM64
+	REQUIRED_MEMORY_TYPE_BITS = 1,
+};
+
+enum
+{
+	MAX_IMAGE_LEVELS_1D = 14,
+	MAX_IMAGE_LEVELS_2D = 14,
+	MAX_IMAGE_LEVELS_3D = 11,
+	MAX_IMAGE_LEVELS_CUBE = 14,
+	MAX_IMAGE_ARRAY_LAYERS = 11,
+};
+
+enum {
+	MaxVertexInputBindings = 16,
+};
+
+}
+
+#endif // VK_CONFIG_HPP_
diff --git a/src/Vulkan/VkDevice.cpp b/src/Vulkan/VkDevice.cpp
new file mode 100644
index 0000000..62040db
--- /dev/null
+++ b/src/Vulkan/VkDevice.cpp
@@ -0,0 +1,68 @@
+// Copyright 2018 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 "VkConfig.h"
+#include "VkDebug.hpp"
+#include "VkDevice.hpp"
+#include <new> // Must #include this to use "placement new"
+
+namespace vk
+{
+
+Device::Device(const Device::CreateInfo* info, void* mem)
+	: physicalDevice(info->pPhysicalDevice), queues(reinterpret_cast<Queue*>(mem))
+{
+	const auto* pCreateInfo = info->pCreateInfo;
+	for(uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++)
+	{
+		const VkDeviceQueueCreateInfo& queueCreateInfo = pCreateInfo->pQueueCreateInfos[i];
+		queueCount += info->pCreateInfo->pQueueCreateInfos[i].queueCount;
+	}
+
+	uint32_t queueID = 0;
+	for(uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++)
+	{
+		const VkDeviceQueueCreateInfo& queueCreateInfo = pCreateInfo->pQueueCreateInfos[i];
+
+		for(uint32_t j = 0; j < queueCreateInfo.queueCount; j++, queueID++)
+		{
+			new (queues + queueID) Queue(queueCreateInfo.queueFamilyIndex, queueCreateInfo.pQueuePriorities[j]);
+		}
+	}
+}
+
+void Device::destroy(const VkAllocationCallbacks* pAllocator)
+{
+	vk::deallocate(queues, pAllocator);
+}
+
+size_t Device::ComputeRequiredAllocationSize(const Device::CreateInfo* info)
+{
+	uint32_t queueCount = 0;
+	for(uint32_t i = 0; i < info->pCreateInfo->queueCreateInfoCount; i++)
+	{
+		queueCount += info->pCreateInfo->pQueueCreateInfos[i].queueCount;
+	}
+
+	return sizeof(Queue) * queueCount;
+}
+
+VkQueue Device::getQueue(uint32_t queueFamilyIndex, uint32_t queueIndex) const
+{
+	ASSERT(queueFamilyIndex == 0);
+
+	return queues[queueIndex];
+}
+
+} // namespace vk
diff --git a/src/Vulkan/VkDevice.hpp b/src/Vulkan/VkDevice.hpp
new file mode 100644
index 0000000..d2188a4
--- /dev/null
+++ b/src/Vulkan/VkDevice.hpp
@@ -0,0 +1,57 @@
+// Copyright 2018 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_DEVICE_HPP_
+#define VK_DEVICE_HPP_
+
+#include "VkObject.hpp"
+#include "VkQueue.hpp"
+
+namespace vk
+{
+
+class Device
+{
+public:
+	struct CreateInfo
+	{
+		const VkDeviceCreateInfo* pCreateInfo;
+		VkPhysicalDevice pPhysicalDevice;
+	};
+
+	static constexpr VkSystemAllocationScope GetAllocationScope() { return VK_SYSTEM_ALLOCATION_SCOPE_DEVICE; }
+
+	Device(const CreateInfo* info, void* mem);
+	void destroy(const VkAllocationCallbacks* pAllocator);
+
+	static size_t ComputeRequiredAllocationSize(const CreateInfo* info);
+
+	VkQueue getQueue(uint32_t queueFamilyIndex, uint32_t queueIndex) const;
+
+private:
+	VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
+	Queue* queues = nullptr;
+	uint32_t queueCount = 0;
+};
+
+using DispatchableDevice = DispatchableObject<Device, VkDevice>;
+
+static inline Device* Cast(VkDevice object)
+{
+	return DispatchableDevice::Cast(object);
+}
+
+} // namespace vk
+
+#endif // VK_DEVICE_HPP_
diff --git a/src/Vulkan/VkInstance.cpp b/src/Vulkan/VkInstance.cpp
new file mode 100644
index 0000000..1848064
--- /dev/null
+++ b/src/Vulkan/VkInstance.cpp
@@ -0,0 +1,61 @@
+// Copyright 2018 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 "VkInstance.hpp"
+
+namespace vk
+{
+
+Instance::Instance(const CreateInfo* pCreateInfo, void* mem)
+{
+	if(pCreateInfo->pPhysicalDevice)
+	{
+		physicalDevice = pCreateInfo->pPhysicalDevice;
+		physicalDeviceCount = 1;
+	}
+}
+
+void Instance::destroy(const VkAllocationCallbacks* pAllocator)
+{
+	vk::destroy(physicalDevice, pAllocator);
+}
+
+uint32_t Instance::getPhysicalDeviceCount() const
+{
+	return physicalDeviceCount;
+}
+
+void Instance::getPhysicalDevices(uint32_t pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices) const
+{
+	ASSERT(pPhysicalDeviceCount == 1);
+
+	*pPhysicalDevices = physicalDevice;
+}
+
+uint32_t Instance::getPhysicalDeviceGroupCount() const
+{
+	return physicalDeviceGroupCount;
+}
+
+void Instance::getPhysicalDeviceGroups(uint32_t pPhysicalDeviceGroupCount,
+                                       VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties) const
+{
+	ASSERT(pPhysicalDeviceGroupCount == 1);
+
+	pPhysicalDeviceGroupProperties->physicalDeviceCount = physicalDeviceCount;
+	pPhysicalDeviceGroupProperties->physicalDevices[0] = physicalDevice;
+	pPhysicalDeviceGroupProperties->subsetAllocation = VK_FALSE;
+}
+
+} // namespace vk
diff --git a/src/Vulkan/VkInstance.hpp b/src/Vulkan/VkInstance.hpp
new file mode 100644
index 0000000..d5385ae
--- /dev/null
+++ b/src/Vulkan/VkInstance.hpp
@@ -0,0 +1,59 @@
+// Copyright 2018 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_INSTANCE_HPP_
+#define VK_INSTANCE_HPP_
+
+#include "VkPhysicalDevice.hpp"
+
+namespace vk
+{
+
+class Instance
+{
+public:
+	struct CreateInfo
+	{
+		const VkInstanceCreateInfo* pCreateInfo;
+		VkPhysicalDevice pPhysicalDevice;
+	};
+
+	static constexpr VkSystemAllocationScope GetAllocationScope() { return VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE; }
+
+	Instance(const CreateInfo* pCreateInfo, void* mem);
+	void destroy(const VkAllocationCallbacks* pAllocator);
+
+	static size_t ComputeRequiredAllocationSize(const CreateInfo*) { return 0; }
+
+	uint32_t getPhysicalDeviceCount() const;
+	void getPhysicalDevices(uint32_t pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices) const;
+	uint32_t getPhysicalDeviceGroupCount() const;
+	void getPhysicalDeviceGroups(uint32_t pPhysicalDeviceGroupCount,
+                                 VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties) const;
+private:
+	uint32_t physicalDeviceCount = 0;
+	VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
+	uint32_t physicalDeviceGroupCount = 1;
+};
+
+using DispatchableInstance = DispatchableObject<Instance, VkInstance>;
+
+static inline Instance* Cast(VkInstance object)
+{
+	return DispatchableInstance::Cast(object);
+}
+
+} // namespace vk
+
+#endif // VK_INSTANCE_HPP_
diff --git a/src/Vulkan/VkMemory.cpp b/src/Vulkan/VkMemory.cpp
new file mode 100644
index 0000000..f24be3c
--- /dev/null
+++ b/src/Vulkan/VkMemory.cpp
@@ -0,0 +1,38 @@
+// Copyright 2018 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_OBJECT_HPP_
+#define VK_OBJECT_HPP_
+
+#include "VkConfig.h"
+#include "VkMemory.h"
+
+namespace vk
+{
+
+void* allocate(size_t count, size_t alignment, const VkAllocationCallbacks* pAllocator, VkSystemAllocationScope allocationScope)
+{
+	return pAllocator ?
+		pAllocator->pfnAllocation(pAllocator->pUserData, count, alignment, allocationScope) :
+		sw::allocate(count, alignment);
+}
+
+void deallocate(void* ptr, const VkAllocationCallbacks* pAllocator)
+{
+	pAllocator ? pAllocator->pfnFree(pAllocator->pUserData, ptr) : sw::deallocate(ptr);
+}
+
+} // namespace vk
+
+#endif // VK_OBJECT_HPP_
diff --git a/src/Vulkan/VkMemory.h b/src/Vulkan/VkMemory.h
new file mode 100644
index 0000000..4178209
--- /dev/null
+++ b/src/Vulkan/VkMemory.h
@@ -0,0 +1,57 @@
+// Copyright 2018 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_MEMORY_HPP_
+#define VK_MEMORY_HPP_
+
+#include "System/Memory.hpp"
+#include <vulkan/vulkan.h>
+
+namespace vk
+{
+
+void* allocate(size_t count, size_t alignment, const VkAllocationCallbacks* pAllocator,
+	           VkSystemAllocationScope allocationScope = VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+void deallocate(void* ptr, const VkAllocationCallbacks* pAllocator);
+
+template <typename T>
+T* allocate(size_t count, const VkAllocationCallbacks* pAllocator)
+{
+	return reinterpret_cast<T*>(allocate(count, alignof(T), pAllocator, T::GetAllocationScope()));
+}
+
+// Because Vulkan uses optional allocation callbacks, we use them in a custom
+// placement new operator in the VkObjectBase class for simplicity.
+// Unfortunately, since we use a placement new to allocate VkObjectBase derived
+// classes objects, the corresponding deletion operator is a placement delete,
+// which does nothing. In order to properly dispose of these objects' memory,
+// we use this function, which calls the proper T:destroy() function
+// prior to releasing the object (by default, VkObjectBase::destroy does nothing).
+template<typename VkT>
+inline void destroy(VkT vkObject, const VkAllocationCallbacks* pAllocator)
+{
+	auto object = Cast(vkObject);
+	if(object)
+	{
+		object->destroy(pAllocator);
+		// object may not point to the same pointer as vkObject, for dispatchable objects,
+		// for example, so make sure to deallocate based on the vkObject pointer, which
+		// should always point to the beginning of the allocated memory
+		vk::deallocate(vkObject, pAllocator);
+	}
+}
+
+} // namespace vk
+
+#endif // VK_MEMORY_HPP_
\ No newline at end of file
diff --git a/src/Vulkan/VkObject.hpp b/src/Vulkan/VkObject.hpp
new file mode 100644
index 0000000..84349da
--- /dev/null
+++ b/src/Vulkan/VkObject.hpp
@@ -0,0 +1,156 @@
+// Copyright 2018 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_OBJECT_HPP_
+#define VK_OBJECT_HPP_
+
+#include "VkDebug.hpp"
+#include "VkMemory.h"
+#include <vulkan/vulkan.h>
+#include <vulkan/vk_icd.h>
+
+namespace vk
+{
+// For use in the placement new to make it verbose that we're allocating an object using device memory
+static constexpr VkAllocationCallbacks* DEVICE_MEMORY = nullptr;
+
+template<typename T, typename VkT, typename CreateInfo>
+static VkResult Create(const VkAllocationCallbacks* pAllocator, const CreateInfo* pCreateInfo, VkT* outObject)
+{
+	*outObject = VK_NULL_HANDLE;
+
+	size_t size = T::ComputeRequiredAllocationSize(pCreateInfo);
+	void* memory = nullptr;
+	if(size)
+	{
+		memory = vk::allocate(size, REQUIRED_MEMORY_ALIGNMENT, pAllocator, T::GetAllocationScope());
+		if(!memory)
+		{
+			return VK_ERROR_OUT_OF_HOST_MEMORY;
+		}
+	}
+
+	auto object = new (pAllocator) T(pCreateInfo, memory);
+
+	if(!object)
+	{
+		vk::deallocate(memory, pAllocator);
+		return VK_ERROR_OUT_OF_HOST_MEMORY;
+	}
+
+	*outObject = *object;
+
+	return VK_SUCCESS;
+}
+
+template<typename T, typename VkT>
+class ObjectBase
+{
+public:
+	using VkType = VkT;
+
+	void destroy(const VkAllocationCallbacks* pAllocator) {} // Method defined by objects to delete their content, if necessary
+
+	void* operator new(size_t count, const VkAllocationCallbacks* pAllocator)
+	{
+		return vk::allocate(count, alignof(T), pAllocator, T::GetAllocationScope());
+	}
+
+	void operator delete(void* ptr, const VkAllocationCallbacks* pAllocator)
+	{
+		// Should never happen
+		ASSERT(false);
+	}
+
+	template<typename CreateInfo>
+	static VkResult Create(const VkAllocationCallbacks* pAllocator, const CreateInfo* pCreateInfo, VkT* outObject)
+	{
+		return vk::Create<T, VkT, CreateInfo>(pAllocator, pCreateInfo, outObject);
+	}
+
+	static constexpr VkSystemAllocationScope GetAllocationScope() { return VK_SYSTEM_ALLOCATION_SCOPE_OBJECT; }
+
+protected:
+	// All derived classes should have deleted destructors
+	~ObjectBase() {}
+};
+
+template<typename T, typename VkT>
+class Object : public ObjectBase<T, VkT>
+{
+public:
+	operator VkT()
+	{
+		return reinterpret_cast<VkT>(this);
+	}
+};
+
+template<typename T, typename VkT>
+class DispatchableObject
+{
+	VK_LOADER_DATA loaderData = { ICD_LOADER_MAGIC };
+
+	T object;
+public:
+	static constexpr VkSystemAllocationScope GetAllocationScope() { return T::GetAllocationScope(); }
+
+	template<typename ...Args>
+	DispatchableObject(Args... args) : object(args...)
+	{
+	}
+
+	~DispatchableObject() = delete;
+
+	void destroy(const VkAllocationCallbacks* pAllocator)
+	{
+		object.destroy(pAllocator);
+	}
+
+	void* operator new(size_t count, const VkAllocationCallbacks* pAllocator)
+	{
+		return vk::allocate(count, alignof(T), pAllocator, T::GetAllocationScope());
+	}
+
+	void operator delete(void* ptr, const VkAllocationCallbacks* pAllocator)
+	{
+		// Should never happen
+		ASSERT(false);
+	}
+
+	template<typename CreateInfo>
+	static VkResult Create(const VkAllocationCallbacks* pAllocator, const CreateInfo* pCreateInfo, VkT* outObject)
+	{
+		return vk::Create<DispatchableObject<T, VkT>, VkT, CreateInfo>(pAllocator, pCreateInfo, outObject);
+	}
+
+	template<typename CreateInfo>
+	static size_t ComputeRequiredAllocationSize(const CreateInfo* pCreateInfo)
+	{
+		return T::ComputeRequiredAllocationSize(pCreateInfo);
+	}
+
+	static inline T* Cast(VkT vkObject)
+	{
+		return &(reinterpret_cast<DispatchableObject<T, VkT>*>(vkObject)->object);
+	}
+
+	operator VkT()
+	{
+		return reinterpret_cast<VkT>(this);
+	}
+};
+
+} // namespace vk
+
+#endif // VK_OBJECT_HPP_
diff --git a/src/Vulkan/VkPhysicalDevice.cpp b/src/Vulkan/VkPhysicalDevice.cpp
new file mode 100644
index 0000000..88b0570
--- /dev/null
+++ b/src/Vulkan/VkPhysicalDevice.cpp
@@ -0,0 +1,385 @@
+// Copyright 2018 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 "VkPhysicalDevice.hpp"
+#include "VkConfig.h"
+#include <memory.h>
+
+namespace vk
+{
+
+PhysicalDevice::PhysicalDevice(const void*, void* mem)
+{
+}
+
+const VkPhysicalDeviceFeatures& PhysicalDevice::getFeatures() const
+{
+	static const VkPhysicalDeviceFeatures features
+	{
+		true, // robustBufferAccess
+		false, // fullDrawIndexUint32
+		false, // imageCubeArray
+		false, // independentBlend
+		false, // geometryShader
+		false, // tessellationShader
+		false, // sampleRateShading
+		false, // dualSrcBlend
+		false, // logicOp
+		false, // multiDrawIndirect
+		false, // drawIndirectFirstInstance
+		false, // depthClamp
+		false, // depthBiasClamp
+		false, // fillModeNonSolid
+		false, // depthBounds
+		false, // wideLines
+		false, // largePoints
+		false, // alphaToOne
+		false, // multiViewport
+		false, // samplerAnisotropy
+		false, // textureCompressionETC2
+		false, // textureCompressionASTC_LDR
+		false, // textureCompressionBC
+		false, // occlusionQueryPrecise
+		false, // pipelineStatisticsQuery
+		false, // vertexPipelineStoresAndAtomics
+		false, // fragmentStoresAndAtomics
+		false, // shaderTessellationAndGeometryPointSize
+		false, // shaderImageGatherExtended
+		false, // shaderStorageImageExtendedFormats
+		false, // shaderStorageImageMultisample
+		false, // shaderStorageImageReadWithoutFormat
+		false, // shaderStorageImageWriteWithoutFormat
+		false, // shaderUniformBufferArrayDynamicIndexing
+		false, // shaderSampledImageArrayDynamicIndexing
+		false, // shaderStorageBufferArrayDynamicIndexing
+		false, // shaderStorageImageArrayDynamicIndexing
+		false, // shaderClipDistance
+		false, // shaderCullDistance
+		false, // shaderFloat64
+		false, // shaderInt64
+		false, // shaderInt16
+		false, // shaderResourceResidency
+		false, // shaderResourceMinLod
+		false, // sparseBinding
+		false, // sparseResidencyBuffer
+		false, // sparseResidencyImage2D
+		false, // sparseResidencyImage3D
+		false, // sparseResidency2Samples
+		false, // sparseResidency4Samples
+		false, // sparseResidency8Samples
+		false, // sparseResidency16Samples
+		false, // sparseResidencyAliased
+		false, // variableMultisampleRate
+		false, // inheritedQueries
+	};
+
+	return features;
+}
+
+VkSampleCountFlags PhysicalDevice::getSampleCounts() const
+{
+	return VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT;
+}
+
+const VkPhysicalDeviceLimits& PhysicalDevice::getLimits() const
+{
+	VkSampleCountFlags sampleCounts = getSampleCounts();
+
+	static const VkPhysicalDeviceLimits limits =
+	{
+		(1 << vk::MAX_IMAGE_LEVELS_1D), // maxImageDimension1D
+		(1 << vk::MAX_IMAGE_LEVELS_2D), // maxImageDimension2D
+		(1 << vk::MAX_IMAGE_LEVELS_3D), // maxImageDimension3D
+		(1 << vk::MAX_IMAGE_LEVELS_CUBE), // maxImageDimensionCube
+		(1 << vk::MAX_IMAGE_ARRAY_LAYERS), // maxImageArrayLayers
+		65536, // maxTexelBufferElements
+		16384, // maxUniformBufferRange
+		(1ul << 27), // maxStorageBufferRange
+		128, // maxPushConstantsSize
+		4096, // maxMemoryAllocationCount
+		4000, // maxSamplerAllocationCount
+		131072, // bufferImageGranularity
+		0, // sparseAddressSpaceSize (unsupported)
+		4, // maxBoundDescriptorSets
+		16, // maxPerStageDescriptorSamplers
+		12, // maxPerStageDescriptorUniformBuffers
+		4, // maxPerStageDescriptorStorageBuffers
+		16, // maxPerStageDescriptorSampledImages
+		4, // maxPerStageDescriptorStorageImages
+		4, // maxPerStageDescriptorInputAttachments
+		128, // maxPerStageResources
+		96, // maxDescriptorSetSamplers
+		72, // maxDescriptorSetUniformBuffers
+		8, // maxDescriptorSetUniformBuffersDynamic
+		24, // maxDescriptorSetStorageBuffers
+		4, // maxDescriptorSetStorageBuffersDynamic
+		96, // maxDescriptorSetSampledImages
+		24, // maxDescriptorSetStorageImages
+		4, // maxDescriptorSetInputAttachments
+		16, // maxVertexInputAttributes
+		vk::MaxVertexInputBindings, // maxVertexInputBindings
+		2047, // maxVertexInputAttributeOffset
+		2048, // maxVertexInputBindingStride
+		64, // maxVertexOutputComponents
+		0, // maxTessellationGenerationLevel (unsupported)
+		0, // maxTessellationPatchSize (unsupported)
+		0, // maxTessellationControlPerVertexInputComponents (unsupported)
+		0, // maxTessellationControlPerVertexOutputComponents (unsupported)
+		0, // maxTessellationControlPerPatchOutputComponents (unsupported)
+		0, // maxTessellationControlTotalOutputComponents (unsupported)
+		0, // maxTessellationEvaluationInputComponents (unsupported)
+		0, // maxTessellationEvaluationOutputComponents (unsupported)
+		0, // maxGeometryShaderInvocations (unsupported)
+		0, // maxGeometryInputComponents (unsupported)
+		0, // maxGeometryOutputComponents (unsupported)
+		0, // maxGeometryOutputVertices (unsupported)
+		0, // maxGeometryTotalOutputComponents (unsupported)
+		64, // maxFragmentInputComponents
+		4, // maxFragmentOutputAttachments
+		1, // maxFragmentDualSrcAttachments
+		4, // maxFragmentCombinedOutputResources
+		16384, // maxComputeSharedMemorySize
+		{ 65535, 65535, 65535 }, // maxComputeWorkGroupCount[3]
+		128, // maxComputeWorkGroupInvocations
+		{ 128, 128, 64, }, // maxComputeWorkGroupSize[3]
+		4, // subPixelPrecisionBits
+		4, // subTexelPrecisionBits
+		4, // mipmapPrecisionBits
+		UINT32_MAX, // maxDrawIndexedIndexValue
+		UINT32_MAX, // maxDrawIndirectCount
+		2, // maxSamplerLodBias
+		16, // maxSamplerAnisotropy
+		16, // maxViewports
+		{ 4096, 4096 }, // maxViewportDimensions[2]
+		{ -8192, 8191 }, // viewportBoundsRange[2]
+		0, // viewportSubPixelBits
+		64, // minMemoryMapAlignment
+		256, // minTexelBufferOffsetAlignment
+		256, // minUniformBufferOffsetAlignment
+		256, // minStorageBufferOffsetAlignment
+		-8, // minTexelOffset
+		7, // maxTexelOffset
+		-8, // minTexelGatherOffset
+		7, // maxTexelGatherOffset
+		-0.5, // minInterpolationOffset
+		0.5, // maxInterpolationOffset
+		4, // subPixelInterpolationOffsetBits
+		4096, // maxFramebufferWidth
+		4096, // maxFramebufferHeight
+		256, // maxFramebufferLayers
+		sampleCounts, // framebufferColorSampleCounts
+		sampleCounts, // framebufferDepthSampleCounts
+		sampleCounts, // framebufferStencilSampleCounts
+		sampleCounts, // framebufferNoAttachmentsSampleCounts
+		4,  // maxColorAttachments
+		sampleCounts, // sampledImageColorSampleCounts
+		VK_SAMPLE_COUNT_1_BIT, // sampledImageIntegerSampleCounts
+		sampleCounts, // sampledImageDepthSampleCounts
+		sampleCounts, // sampledImageStencilSampleCounts
+		VK_SAMPLE_COUNT_1_BIT, // storageImageSampleCounts (unsupported)
+		1, // maxSampleMaskWords
+		false, // timestampComputeAndGraphics
+		60, // timestampPeriod
+		8, // maxClipDistances
+		8, // maxCullDistances
+		8, // maxCombinedClipAndCullDistances
+		2, // discreteQueuePriorities
+		{ 1.0, 64.0 }, // pointSizeRange[2]
+		{ 0.0, 8.0 }, // lineWidthRange[2]
+		1.0, // pointSizeGranularity
+		1.0, // lineWidthGranularity
+		false, // strictLines
+		true, // standardSampleLocations
+		64, // optimalBufferCopyOffsetAlignment
+		64, // optimalBufferCopyRowPitchAlignment
+		256, // nonCoherentAtomSize
+	};
+
+	return limits;
+}
+
+
+const VkPhysicalDeviceProperties& PhysicalDevice::getProperties() const
+{
+	uint32_t apiVersion;
+	VkResult result = vkEnumerateInstanceVersion(&apiVersion);
+	ASSERT(result == VK_SUCCESS);
+
+	static const VkPhysicalDeviceProperties properties
+	{
+		apiVersion,
+		DRIVER_VERSION,
+		VENDOR_ID,
+		DEVICE_ID,
+		VK_PHYSICAL_DEVICE_TYPE_CPU, // deviceType
+		SWIFTSHADER_DEVICE_NAME, // deviceName
+		SWIFTSHADER_UUID, // pipelineCacheUUID
+		getLimits(), // limits
+		{ 0 } // sparseProperties
+	};
+
+	return properties;
+}
+
+bool PhysicalDevice::hasFeatures(const VkPhysicalDeviceFeatures& requestedFeatures) const
+{
+	const VkPhysicalDeviceFeatures& availableFeatures = getFeatures();
+
+	return (!requestedFeatures.robustBufferAccess || availableFeatures.robustBufferAccess) &&
+	       (!requestedFeatures.fullDrawIndexUint32 || availableFeatures.fullDrawIndexUint32) &&
+	       (!requestedFeatures.imageCubeArray || availableFeatures.imageCubeArray) &&
+	       (!requestedFeatures.independentBlend || availableFeatures.independentBlend) &&
+	       (!requestedFeatures.geometryShader || availableFeatures.geometryShader) &&
+	       (!requestedFeatures.tessellationShader || availableFeatures.tessellationShader) &&
+	       (!requestedFeatures.sampleRateShading || availableFeatures.sampleRateShading) &&
+	       (!requestedFeatures.dualSrcBlend || availableFeatures.dualSrcBlend) &&
+	       (!requestedFeatures.logicOp || availableFeatures.logicOp) &&
+	       (!requestedFeatures.multiDrawIndirect || availableFeatures.multiDrawIndirect) &&
+	       (!requestedFeatures.drawIndirectFirstInstance || availableFeatures.drawIndirectFirstInstance) &&
+	       (!requestedFeatures.depthClamp || availableFeatures.depthClamp) &&
+	       (!requestedFeatures.depthBiasClamp || availableFeatures.depthBiasClamp) &&
+	       (!requestedFeatures.fillModeNonSolid || availableFeatures.fillModeNonSolid) &&
+	       (!requestedFeatures.depthBounds || availableFeatures.depthBounds) &&
+	       (!requestedFeatures.wideLines || availableFeatures.wideLines) &&
+	       (!requestedFeatures.largePoints || availableFeatures.largePoints) &&
+	       (!requestedFeatures.alphaToOne || availableFeatures.alphaToOne) &&
+	       (!requestedFeatures.multiViewport || availableFeatures.multiViewport) &&
+	       (!requestedFeatures.samplerAnisotropy || availableFeatures.samplerAnisotropy) &&
+	       (!requestedFeatures.textureCompressionETC2 || availableFeatures.textureCompressionETC2) &&
+	       (!requestedFeatures.textureCompressionASTC_LDR || availableFeatures.textureCompressionASTC_LDR) &&
+	       (!requestedFeatures.textureCompressionBC || availableFeatures.textureCompressionBC) &&
+	       (!requestedFeatures.occlusionQueryPrecise || availableFeatures.occlusionQueryPrecise) &&
+	       (!requestedFeatures.pipelineStatisticsQuery || availableFeatures.pipelineStatisticsQuery) &&
+	       (!requestedFeatures.vertexPipelineStoresAndAtomics || availableFeatures.vertexPipelineStoresAndAtomics) &&
+	       (!requestedFeatures.fragmentStoresAndAtomics || availableFeatures.fragmentStoresAndAtomics) &&
+	       (!requestedFeatures.shaderTessellationAndGeometryPointSize || availableFeatures.shaderTessellationAndGeometryPointSize) &&
+	       (!requestedFeatures.shaderImageGatherExtended || availableFeatures.shaderImageGatherExtended) &&
+	       (!requestedFeatures.shaderStorageImageExtendedFormats || availableFeatures.shaderStorageImageExtendedFormats) &&
+	       (!requestedFeatures.shaderStorageImageMultisample || availableFeatures.shaderStorageImageMultisample) &&
+	       (!requestedFeatures.shaderStorageImageReadWithoutFormat || availableFeatures.shaderStorageImageReadWithoutFormat) &&
+	       (!requestedFeatures.shaderStorageImageWriteWithoutFormat || availableFeatures.shaderStorageImageWriteWithoutFormat) &&
+	       (!requestedFeatures.shaderUniformBufferArrayDynamicIndexing || availableFeatures.shaderUniformBufferArrayDynamicIndexing) &&
+	       (!requestedFeatures.shaderSampledImageArrayDynamicIndexing || availableFeatures.shaderSampledImageArrayDynamicIndexing) &&
+	       (!requestedFeatures.shaderStorageBufferArrayDynamicIndexing || availableFeatures.shaderStorageBufferArrayDynamicIndexing) &&
+	       (!requestedFeatures.shaderStorageImageArrayDynamicIndexing || availableFeatures.shaderStorageImageArrayDynamicIndexing) &&
+	       (!requestedFeatures.shaderClipDistance || availableFeatures.shaderClipDistance) &&
+	       (!requestedFeatures.shaderCullDistance || availableFeatures.shaderCullDistance) &&
+	       (!requestedFeatures.shaderFloat64 || availableFeatures.shaderFloat64) &&
+	       (!requestedFeatures.shaderInt64 || availableFeatures.shaderInt64) &&
+	       (!requestedFeatures.shaderInt16 || availableFeatures.shaderInt16) &&
+	       (!requestedFeatures.shaderResourceResidency || availableFeatures.shaderResourceResidency) &&
+	       (!requestedFeatures.shaderResourceMinLod || availableFeatures.shaderResourceMinLod) &&
+	       (!requestedFeatures.sparseBinding || availableFeatures.sparseBinding) &&
+	       (!requestedFeatures.sparseResidencyBuffer || availableFeatures.sparseResidencyBuffer) &&
+	       (!requestedFeatures.sparseResidencyImage2D || availableFeatures.sparseResidencyImage2D) &&
+	       (!requestedFeatures.sparseResidencyImage3D || availableFeatures.sparseResidencyImage3D) &&
+	       (!requestedFeatures.sparseResidency2Samples || availableFeatures.sparseResidency2Samples) &&
+	       (!requestedFeatures.sparseResidency4Samples || availableFeatures.sparseResidency4Samples) &&
+	       (!requestedFeatures.sparseResidency8Samples || availableFeatures.sparseResidency8Samples) &&
+	       (!requestedFeatures.sparseResidency16Samples || availableFeatures.sparseResidency16Samples) &&
+	       (!requestedFeatures.sparseResidencyAliased || availableFeatures.sparseResidencyAliased) &&
+	       (!requestedFeatures.variableMultisampleRate || availableFeatures.variableMultisampleRate) &&
+	       (!requestedFeatures.inheritedQueries || availableFeatures.inheritedQueries);
+}
+
+void PhysicalDevice::getFormatProperties(VkFormat format, VkFormatProperties* pFormatProperties) const
+{
+	pFormatProperties->linearTilingFeatures = 0; // Unsupported format
+	pFormatProperties->optimalTilingFeatures = 0; // Unsupported format
+	pFormatProperties->bufferFeatures = 0; // Unsupported format
+}
+
+void PhysicalDevice::getImageFormatProperties(VkFormat format, VkImageType type, VkImageTiling tiling,
+                                              VkImageUsageFlags usage, VkImageCreateFlags flags,
+	                                          VkImageFormatProperties* pImageFormatProperties) const
+{
+	pImageFormatProperties->maxArrayLayers = 1 << vk::MAX_IMAGE_ARRAY_LAYERS;
+
+	switch(type)
+	{
+	case VK_IMAGE_TYPE_1D:
+		pImageFormatProperties->maxMipLevels = vk::MAX_IMAGE_LEVELS_1D;
+		pImageFormatProperties->maxExtent.width = 1 << vk::MAX_IMAGE_LEVELS_1D;
+		pImageFormatProperties->maxExtent.height = 1;
+		pImageFormatProperties->maxExtent.depth = 1;
+		break;
+	case VK_IMAGE_TYPE_2D:
+		if(flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT)
+		{
+			pImageFormatProperties->maxMipLevels = vk::MAX_IMAGE_LEVELS_CUBE;
+			pImageFormatProperties->maxExtent.width = 1 << vk::MAX_IMAGE_LEVELS_CUBE;
+			pImageFormatProperties->maxExtent.height = 1 << vk::MAX_IMAGE_LEVELS_CUBE;
+			pImageFormatProperties->maxExtent.depth = 1;
+		}
+		else
+		{
+			pImageFormatProperties->maxMipLevels = vk::MAX_IMAGE_LEVELS_2D;
+			pImageFormatProperties->maxExtent.width = 1 << vk::MAX_IMAGE_LEVELS_2D;
+			pImageFormatProperties->maxExtent.height = 1 << vk::MAX_IMAGE_LEVELS_2D;
+			pImageFormatProperties->maxExtent.depth = 1;
+		}
+		break;
+	case VK_IMAGE_TYPE_3D:
+		pImageFormatProperties->maxMipLevels = vk::MAX_IMAGE_LEVELS_3D;
+		pImageFormatProperties->maxExtent.width = 1 << vk::MAX_IMAGE_LEVELS_3D;
+		pImageFormatProperties->maxExtent.height = 1 << vk::MAX_IMAGE_LEVELS_3D;
+		pImageFormatProperties->maxExtent.depth = 1 << vk::MAX_IMAGE_LEVELS_3D;
+		break;
+	default:
+		UNREACHABLE(type);
+		break;
+	}
+
+	pImageFormatProperties->maxResourceSize = 1 << 31; // Minimum value for maxResourceSize
+	pImageFormatProperties->sampleCounts = getSampleCounts();
+
+}
+
+uint32_t PhysicalDevice::getQueueFamilyPropertyCount() const
+{
+	return 1;
+}
+
+void PhysicalDevice::getQueueFamilyProperties(uint32_t pQueueFamilyPropertyCount,
+                                              VkQueueFamilyProperties* pQueueFamilyProperties) const
+{
+	for(uint32_t i = 0; i < pQueueFamilyPropertyCount; i++)
+	{
+		pQueueFamilyProperties[i].minImageTransferGranularity.width = 1;
+		pQueueFamilyProperties[i].minImageTransferGranularity.height = 1;
+		pQueueFamilyProperties[i].minImageTransferGranularity.depth = 1;
+		pQueueFamilyProperties[i].queueCount = 1;
+		pQueueFamilyProperties[i].queueFlags = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT;
+		pQueueFamilyProperties[i].timestampValidBits = 0; // No support for time stamps
+	}
+}
+
+const VkPhysicalDeviceMemoryProperties& PhysicalDevice::getMemoryProperties() const
+{
+	static const VkPhysicalDeviceMemoryProperties properties
+	{
+		1, // memoryTypeCount
+		{{VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
+		  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
+		  VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
+		  0}}, // heapIndex
+		1, // memoryHeapCount
+		{{1ull << 31, // size, FIXME(sugoi): This could be configurable based on available RAM
+		  VK_MEMORY_HEAP_DEVICE_LOCAL_BIT}},
+	};
+
+	return properties;
+}
+
+} // namespace vk
\ No newline at end of file
diff --git a/src/Vulkan/VkPhysicalDevice.hpp b/src/Vulkan/VkPhysicalDevice.hpp
new file mode 100644
index 0000000..c1cd043
--- /dev/null
+++ b/src/Vulkan/VkPhysicalDevice.hpp
@@ -0,0 +1,59 @@
+// Copyright 2018 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_PHYSICAL_DEVICE_HPP_
+#define VK_PHYSICAL_DEVICE_HPP_
+
+#include "VkObject.hpp"
+
+namespace vk
+{
+
+class PhysicalDevice
+{
+public:
+	static constexpr VkSystemAllocationScope GetAllocationScope() { return VK_SYSTEM_ALLOCATION_SCOPE_DEVICE; }
+
+	PhysicalDevice(const void*, void* mem);
+	void destroy(const VkAllocationCallbacks* pAllocator) {}
+
+	static size_t ComputeRequiredAllocationSize(const void*) { return 0; }
+
+	const VkPhysicalDeviceFeatures& getFeatures() const;
+	bool hasFeatures(const VkPhysicalDeviceFeatures& requestedFeatures) const;
+	const VkPhysicalDeviceProperties& getProperties() const;
+	void getFormatProperties(VkFormat format, VkFormatProperties* pFormatProperties) const;
+	void getImageFormatProperties(VkFormat format, VkImageType type, VkImageTiling tiling,
+	                              VkImageUsageFlags usage, VkImageCreateFlags flags,
+	                              VkImageFormatProperties* pImageFormatProperties) const;
+	uint32_t getQueueFamilyPropertyCount() const;
+	void getQueueFamilyProperties(uint32_t pQueueFamilyPropertyCount,
+	                              VkQueueFamilyProperties* pQueueFamilyProperties) const;
+	const VkPhysicalDeviceMemoryProperties& getMemoryProperties() const;
+
+private:
+	const VkPhysicalDeviceLimits& getLimits() const;
+	VkSampleCountFlags getSampleCounts() const;
+};
+
+using DispatchablePhysicalDevice = DispatchableObject<PhysicalDevice, VkPhysicalDevice>;
+
+static inline PhysicalDevice* Cast(VkPhysicalDevice object)
+{
+	return DispatchablePhysicalDevice::Cast(object);
+}
+
+} // namespace vk
+
+#endif // VK_PHYSICAL_DEVICE_HPP_
diff --git a/src/Vulkan/VkQueue.cpp b/src/Vulkan/VkQueue.cpp
new file mode 100644
index 0000000..537849c
--- /dev/null
+++ b/src/Vulkan/VkQueue.cpp
@@ -0,0 +1,24 @@
+// Copyright 2018 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 "VkQueue.hpp"
+
+namespace vk
+{
+
+Queue::Queue(uint32_t pFamilyIndex, float pPriority) : familyIndex(pFamilyIndex), priority(pPriority)
+{
+}
+
+} // namespace vk
\ No newline at end of file
diff --git a/src/Vulkan/VkQueue.hpp b/src/Vulkan/VkQueue.hpp
new file mode 100644
index 0000000..cb6517f
--- /dev/null
+++ b/src/Vulkan/VkQueue.hpp
@@ -0,0 +1,48 @@
+// Copyright 2018 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_QUEUE_HPP_
+#define VK_QUEUE_HPP_
+
+#include "VkObject.hpp"
+
+namespace vk
+{
+
+class Queue
+{
+	VK_LOADER_DATA loaderData = { ICD_LOADER_MAGIC };
+
+public:
+	Queue(uint32_t pFamilyIndex, float pPriority);
+	~Queue() = delete;
+
+	operator VkQueue()
+	{
+		return reinterpret_cast<VkQueue>(this);
+	}
+
+private:
+	uint32_t familyIndex = 0;
+	float    priority = 0.0f;
+};
+
+static inline Queue* Cast(VkQueue object)
+{
+	return reinterpret_cast<Queue*>(object);
+}
+
+} // namespace vk
+
+#endif // VK_QUEUE_HPP_
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index 2e15309..5fe4559 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -12,10 +12,16 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "VkConfig.h"
+#include "VkCommandBuffer.hpp"
 #include "VkDebug.hpp"
+#include "VkDevice.hpp"
 #include "VkGetProcAddress.h"
-#include <vulkan/vulkan.h>
+#include "VkInstance.hpp"
+#include "VkPhysicalDevice.hpp"
+#include "VkQueue.hpp"
 #include <cstring>
+#include <string>
 
 extern "C"
 {
@@ -29,16 +35,62 @@
 	TRACE("(const VkInstanceCreateInfo* pCreateInfo = 0x%X, const VkAllocationCallbacks* pAllocator = 0x%X, VkInstance* pInstance = 0x%X)",
 			pCreateInfo, pAllocator, pInstance);
 
-	UNIMPLEMENTED();
+	if(pCreateInfo->enabledLayerCount)
+	{
+		UNIMPLEMENTED();
+	}
 
-	return VK_SUCCESS;
+	if(pCreateInfo->enabledExtensionCount)
+	{
+		UNIMPLEMENTED();
+	}
+
+	if(pCreateInfo->pNext)
+	{
+		switch(*reinterpret_cast<const VkStructureType*>(pCreateInfo->pNext))
+		{
+		case VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO:
+			// According to the Vulkan spec, section 2.7.2. Implicit Valid Usage:
+			// "The values VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO and
+			//  VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO are reserved for
+			//  internal use by the loader, and do not have corresponding
+			//  Vulkan structures in this Specification."
+			break;
+		default:
+			UNIMPLEMENTED();
+		}
+	}
+
+	*pInstance = VK_NULL_HANDLE;
+	VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
+
+	VkResult result = vk::DispatchablePhysicalDevice::Create(pAllocator, pCreateInfo, &physicalDevice);
+	if(result != VK_SUCCESS)
+	{
+		return result;
+	}
+
+	vk::Instance::CreateInfo info =
+	{
+		pCreateInfo,
+		physicalDevice
+	};
+
+	result = vk::DispatchableInstance::Create(pAllocator, &info, pInstance);
+	if(result != VK_SUCCESS)
+	{
+		vk::destroy(physicalDevice, pAllocator);
+		return result;
+	}
+
+	return result;
 }
 
 VKAPI_ATTR void VKAPI_CALL vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks* pAllocator)
 {
 	TRACE("(VkInstance instance = 0x%X, const VkAllocationCallbacks* pAllocator = 0x%X)", instance, pAllocator);
 
-	UNIMPLEMENTED();
+	vk::destroy(instance, pAllocator);
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDevices(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices)
@@ -46,7 +98,14 @@
 	TRACE("(VkInstance instance = 0x%X, uint32_t* pPhysicalDeviceCount = 0x%X, VkPhysicalDevice* pPhysicalDevices = 0x%X)",
 		    instance, pPhysicalDeviceCount, pPhysicalDevices);
 
-	UNIMPLEMENTED();
+	if(!pPhysicalDevices)
+	{
+		*pPhysicalDeviceCount = vk::Cast(instance)->getPhysicalDeviceCount();
+	}
+	else
+	{
+		vk::Cast(instance)->getPhysicalDevices(*pPhysicalDeviceCount, pPhysicalDevices);
+	}
 
 	return VK_SUCCESS;
 }
@@ -56,7 +115,7 @@
 	TRACE("(VkPhysicalDevice physicalDevice = 0x%X, VkPhysicalDeviceFeatures* pFeatures = 0x%X)",
 			physicalDevice, pFeatures);
 
-	UNIMPLEMENTED();
+	*pFeatures = vk::Cast(physicalDevice)->getFeatures();
 }
 
 VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties* pFormatProperties)
@@ -64,7 +123,7 @@
 	TRACE("GetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice = 0x%X, VkFormat format = %d, VkFormatProperties* pFormatProperties = 0x%X)",
 			physicalDevice, (int)format, pFormatProperties);
 
-	UNIMPLEMENTED();
+	vk::Cast(physicalDevice)->getFormatProperties(format, pFormatProperties);
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* pImageFormatProperties)
@@ -72,7 +131,7 @@
 	TRACE("(VkPhysicalDevice physicalDevice = 0x%X, VkFormat format = %d, VkImageType type = %d, VkImageTiling tiling = %d, VkImageUsageFlags usage = %d, VkImageCreateFlags flags = %d, VkImageFormatProperties* pImageFormatProperties = 0x%X)",
 			physicalDevice, (int)format, (int)type, (int)tiling, usage, flags, pImageFormatProperties);
 
-	UNIMPLEMENTED();
+	vk::Cast(physicalDevice)->getImageFormatProperties(format, type, tiling, usage, flags, pImageFormatProperties);
 
 	return VK_SUCCESS;
 }
@@ -82,38 +141,39 @@
 	TRACE("(VkPhysicalDevice physicalDevice = 0x%X, VkPhysicalDeviceProperties* pProperties = 0x%X)",
 		    physicalDevice, pProperties);
 
-	UNIMPLEMENTED();
+	*pProperties = vk::Cast(physicalDevice)->getProperties();
 }
 
 VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties* pQueueFamilyProperties)
 {
 	TRACE("(VkPhysicalDevice physicalDevice = 0x%X, uint32_t* pQueueFamilyPropertyCount = 0x%X, VkQueueFamilyProperties* pQueueFamilyProperties = 0x%X))", physicalDevice, pQueueFamilyPropertyCount, pQueueFamilyProperties);
 
-	UNIMPLEMENTED();
+	if(!pQueueFamilyProperties)
+	{
+		*pQueueFamilyPropertyCount = vk::Cast(physicalDevice)->getQueueFamilyPropertyCount();
+	}
+	else
+	{
+		vk::Cast(physicalDevice)->getQueueFamilyProperties(*pQueueFamilyPropertyCount, pQueueFamilyProperties);
+	}
 }
 
 VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties* pMemoryProperties)
 {
 	TRACE("(VkPhysicalDevice physicalDevice = 0x%X, VkPhysicalDeviceMemoryProperties* pMemoryProperties = 0x%X)", physicalDevice, pMemoryProperties);
 
-	UNIMPLEMENTED();
+	*pMemoryProperties = vk::Cast(physicalDevice)->getMemoryProperties();
 }
 
 VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char* pName)
 {
 	TRACE("(VkInstance instance = 0x%X, const char* pName = 0x%X)", instance, pName);
-
-	UNIMPLEMENTED();
-
 	return vk::GetProcAddr(pName);
 }
 
 VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice device, const char* pName)
 {
 	TRACE("(VkDevice device = 0x%X, const char* pName = 0x%X)", device, pName);
-
-	UNIMPLEMENTED();
-
 	return vk::GetProcAddr(pName);
 }
 
@@ -122,16 +182,62 @@
 	TRACE("(VkPhysicalDevice physicalDevice = 0x%X, const VkDeviceCreateInfo* pCreateInfo = 0x%X, const VkAllocationCallbacks* pAllocator = 0x%X, VkDevice* pDevice = 0x%X)",
 		physicalDevice, pCreateInfo, pAllocator, pDevice);
 
-	UNIMPLEMENTED();
+	if(pCreateInfo->enabledLayerCount || pCreateInfo->enabledExtensionCount)
+	{
+		UNIMPLEMENTED();
+	}
 
-	return VK_SUCCESS;
+	if(pCreateInfo->pNext)
+	{
+		switch(*reinterpret_cast<const VkStructureType*>(pCreateInfo->pNext))
+		{
+		case VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO:
+			// According to the Vulkan spec, section 2.7.2. Implicit Valid Usage:
+			// "The values VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO and
+			//  VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO are reserved for
+			//  internal use by the loader, and do not have corresponding
+			//  Vulkan structures in this Specification."
+			break;
+		default:
+			UNIMPLEMENTED();
+		}
+	}
+
+	ASSERT(pCreateInfo->queueCreateInfoCount > 0);
+
+	if(pCreateInfo->pEnabledFeatures &&
+	   !vk::Cast(physicalDevice)->hasFeatures(*(pCreateInfo->pEnabledFeatures)))
+	{
+		return VK_ERROR_FEATURE_NOT_PRESENT;
+	}
+
+	uint32_t queueFamilyPropertyCount = vk::Cast(physicalDevice)->getQueueFamilyPropertyCount();
+
+	for(uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++)
+	{
+		const VkDeviceQueueCreateInfo& queueCreateInfo = pCreateInfo->pQueueCreateInfos[i];
+		if(queueCreateInfo.pNext || queueCreateInfo.flags)
+		{
+			UNIMPLEMENTED();
+		}
+
+		ASSERT(queueCreateInfo.queueFamilyIndex < queueFamilyPropertyCount);
+	}
+
+	vk::Device::CreateInfo deviceCreateInfo =
+	{
+		pCreateInfo,
+		physicalDevice
+	};
+
+	return vk::DispatchableDevice::Create(pAllocator, &deviceCreateInfo, pDevice);
 }
 
 VKAPI_ATTR void VKAPI_CALL vkDestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator)
 {
 	TRACE("(VkDevice device = 0x%X, const VkAllocationCallbacks* pAllocator = 0x%X)", device, pAllocator);
 
-	UNIMPLEMENTED();
+	vk::destroy(device, pAllocator);
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties)
@@ -194,7 +300,11 @@
 {
 	TRACE("(VkPhysicalDevice physicalDevice = 0x%X, const char* pLayerName, uint32_t* pPropertyCount = 0x%X, VkExtensionProperties* pProperties = 0x%X)", physicalDevice, pPropertyCount, pProperties);
 
-	UNIMPLEMENTED();
+	if(!pProperties)
+	{
+		*pPropertyCount = 0;
+		return VK_SUCCESS;
+	}
 
 	return VK_SUCCESS;
 }
@@ -203,7 +313,11 @@
 {
 	TRACE("(uint32_t* pPropertyCount = 0x%X, VkLayerProperties* pProperties = 0x%X)", pPropertyCount, pProperties);
 
-	UNIMPLEMENTED();
+	if(!pProperties)
+	{
+		*pPropertyCount = 0;
+		return VK_SUCCESS;
+	}
 
 	return VK_SUCCESS;
 }
@@ -212,7 +326,11 @@
 {
 	TRACE("(VkPhysicalDevice physicalDevice = 0x%X, uint32_t* pPropertyCount = 0x%X, VkLayerProperties* pProperties = 0x%X)", physicalDevice, pPropertyCount, pProperties);
 
-	UNIMPLEMENTED();
+	if(!pProperties)
+	{
+		*pPropertyCount = 0;
+		return VK_SUCCESS;
+	}
 
 	return VK_SUCCESS;
 }
@@ -222,7 +340,7 @@
 	TRACE("(VkDevice device = 0x%X, uint32_t queueFamilyIndex = %d, uint32_t queueIndex = %d, VkQueue* pQueue = 0x%X)",
 		    device, queueFamilyIndex, queueIndex, pQueue);
 
-	UNIMPLEMENTED();
+	*pQueue = vk::Cast(device)->getQueue(queueFamilyIndex, queueIndex);
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL vkQueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence)
@@ -376,7 +494,7 @@
 {
 	TRACE("(VkDevice device = 0x%X, VkFence fence = 0x%X, const VkAllocationCallbacks* pAllocator = 0x%X)",
 		    device, fence, pAllocator);
-	
+
 	UNIMPLEMENTED();
 }
 
@@ -1163,14 +1281,24 @@
 {
 	TRACE("(VkPhysicalDevice physicalDevice = 0x%X, VkPhysicalDeviceFeatures2* pFeatures = 0x%X)", physicalDevice, pFeatures);
 
-	UNIMPLEMENTED();
+	if(pFeatures->pNext)
+	{
+		UNIMPLEMENTED();
+	}
+
+	vkGetPhysicalDeviceFeatures(physicalDevice, &(pFeatures->features));
 }
 
 VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties)
 {
 	TRACE("(VkPhysicalDevice physicalDevice = 0x%X, VkPhysicalDeviceProperties2* pProperties = 0x%X)", physicalDevice, pProperties);
 
-	UNIMPLEMENTED();
+	if(pProperties->pNext)
+	{
+		UNIMPLEMENTED();
+	}
+
+	vkGetPhysicalDeviceProperties(physicalDevice, &(pProperties->properties));
 }
 
 VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties)
@@ -1178,7 +1306,12 @@
 	TRACE("(VkPhysicalDevice physicalDevice = 0x%X, VkFormat format = %d, VkFormatProperties2* pFormatProperties = 0x%X)",
 		    physicalDevice, format, pFormatProperties);
 
-	UNIMPLEMENTED();
+	if(pFormatProperties->pNext)
+	{
+		UNIMPLEMENTED();
+	}
+
+	vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &(pFormatProperties->formatProperties));
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties)
@@ -1186,9 +1319,18 @@
 	TRACE("(VkPhysicalDevice physicalDevice = 0x%X, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo = 0x%X, VkImageFormatProperties2* pImageFormatProperties = 0x%X)",
 		    physicalDevice, pImageFormatInfo, pImageFormatProperties);
 
-	UNIMPLEMENTED();
+	if(pImageFormatProperties->pNext)
+	{
+		UNIMPLEMENTED();
+	}
 
-	return VK_SUCCESS;
+	return vkGetPhysicalDeviceImageFormatProperties(physicalDevice,
+		                                            pImageFormatInfo->format,
+		                                            pImageFormatInfo->type,
+		                                            pImageFormatInfo->tiling,
+		                                            pImageFormatInfo->usage,
+		                                            pImageFormatInfo->flags,
+		                                            &(pImageFormatProperties->imageFormatProperties));
 }
 
 VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties)
@@ -1196,20 +1338,53 @@
 	TRACE("(VkPhysicalDevice physicalDevice = 0x%X, uint32_t* pQueueFamilyPropertyCount = 0x%X, VkQueueFamilyProperties2* pQueueFamilyProperties = 0x%X)",
 		physicalDevice, pQueueFamilyPropertyCount, pQueueFamilyProperties);
 
-	UNIMPLEMENTED();
+	if(!pQueueFamilyProperties)
+	{
+		*pQueueFamilyPropertyCount = 1;
+	}
+	else
+	{
+		if(pQueueFamilyProperties->pNext)
+		{
+			UNIMPLEMENTED();
+		}
+
+		vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, pQueueFamilyPropertyCount, &(pQueueFamilyProperties->queueFamilyProperties));
+	}
 }
 
 VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties)
 {
 	TRACE("(VkPhysicalDevice physicalDevice = 0x%X, VkPhysicalDeviceMemoryProperties2* pMemoryProperties = 0x%X)", physicalDevice, pMemoryProperties);
 
-	UNIMPLEMENTED();
+	if(pMemoryProperties->pNext)
+	{
+		UNIMPLEMENTED();
+	}
+
+	vkGetPhysicalDeviceMemoryProperties(physicalDevice, &(pMemoryProperties->memoryProperties));
 }
 
 VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties)
 {
-	TRACE("()");
-	UNIMPLEMENTED();
+	TRACE("(VkPhysicalDevice physicalDevice = 0x%X, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo = 0x%X, uint32_t* pPropertyCount = 0x%X, VkSparseImageFormatProperties2* pProperties = 0x%X)",
+	     physicalDevice, pFormatInfo, pPropertyCount, pProperties);
+
+	if(!pProperties)
+	{
+		*pPropertyCount = 1;
+	}
+	else
+	{
+		if(pProperties->pNext)
+		{
+			UNIMPLEMENTED();
+		}
+
+		vkGetPhysicalDeviceSparseImageFormatProperties(physicalDevice, pFormatInfo->format, pFormatInfo->type,
+		                                               pFormatInfo->samples, pFormatInfo->usage, pFormatInfo->tiling,
+		                                               pPropertyCount, &(pProperties->properties));
+	}
 }
 
 VKAPI_ATTR void VKAPI_CALL vkTrimCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags)
diff --git a/src/Vulkan/vulkan.vcxproj b/src/Vulkan/vulkan.vcxproj
index bf95f24..92b83df 100644
--- a/src/Vulkan/vulkan.vcxproj
+++ b/src/Vulkan/vulkan.vcxproj
@@ -171,6 +171,17 @@
     </PostBuildEvent>

   </ItemDefinitionGroup>

   <ItemGroup>

+    <ClCompile Include="libVulkan.cpp" />

+    <ClCompile Include="main.cpp" />

+    <ClCompile Include="VkCommandBuffer.cpp" />

+    <ClCompile Include="VkDebug.cpp" />

+    <ClCompile Include="VkDevice.cpp" />

+    <ClCompile Include="VkGetProcAddress.cpp" />

+    <ClCompile Include="VkInstance.cpp" />

+    <ClCompile Include="VkMemory.cpp" />

+    <ClCompile Include="VkPhysicalDevice.cpp" />

+    <ClCompile Include="VkPromotedExtensions.cpp" />

+    <ClCompile Include="VkQueue.cpp" />

     <ClCompile Include="..\Device\Blitter.cpp" />

     <ClCompile Include="..\Device\Clipper.cpp" />

     <ClCompile Include="..\Device\Color.cpp" />

@@ -253,13 +264,19 @@
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>

       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>

     </ClCompile>

-    <ClCompile Include="libVulkan.cpp" />

-    <ClCompile Include="main.cpp" />

-    <ClCompile Include="VkDebug.cpp" />

-    <ClCompile Include="VkGetProcAddress.cpp" />

-    <ClCompile Include="VkPromotedExtensions.cpp" />

   </ItemGroup>

   <ItemGroup>

+    <ClInclude Include="resource.h" />

+    <ClInclude Include="VkCommandBuffer.hpp" />

+    <ClInclude Include="VkConfig.h" />

+    <ClInclude Include="VkDebug.hpp" />

+    <ClInclude Include="VkDevice.hpp" />

+    <ClInclude Include="VkGetProcAddress.h" />

+    <ClInclude Include="VkInstance.hpp" />

+    <ClInclude Include="VkMemory.h" />

+    <ClInclude Include="VkObject.hpp" />

+    <ClInclude Include="VkPhysicalDevice.hpp" />

+    <ClInclude Include="VkQueue.hpp" />

     <ClInclude Include="..\Device\Blitter.hpp" />

     <ClInclude Include="..\Device\Clipper.hpp" />

     <ClInclude Include="..\Device\Color.hpp" />

@@ -359,9 +376,6 @@
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>

       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>

     </ClInclude>

-    <ClInclude Include="VkDebug.hpp" />

-    <ClInclude Include="resource.h" />

-    <ClInclude Include="VkGetProcAddress.h" />

   </ItemGroup>

   <ItemGroup>

     <None Include="..\WSI\FrameBufferOSX.mm">

diff --git a/src/Vulkan/vulkan.vcxproj.filters b/src/Vulkan/vulkan.vcxproj.filters
index 99a4c89..2d6ed035 100644
--- a/src/Vulkan/vulkan.vcxproj.filters
+++ b/src/Vulkan/vulkan.vcxproj.filters
@@ -22,6 +22,12 @@
     <Filter Include="Header Files\Pipeline">

       <UniqueIdentifier>{ab31f9cb-85bf-4ad3-8ee0-1810977a5944}</UniqueIdentifier>

     </Filter>

+    <Filter Include="Header Files\Vulkan">

+      <UniqueIdentifier>{eae937f9-88b4-4bd4-ba7b-bb4a4dcdaf52}</UniqueIdentifier>

+    </Filter>

+    <Filter Include="Header Files\Device">

+      <UniqueIdentifier>{31e80f94-e9d4-42cf-97b1-58bda4d1ab31}</UniqueIdentifier>

+    </Filter>

     <Filter Include="Source Files\System">

       <UniqueIdentifier>{c9884906-cd72-4adb-9641-d72660051aa3}</UniqueIdentifier>

     </Filter>

@@ -37,29 +43,8 @@
     <Filter Include="Source Files\Device">

       <UniqueIdentifier>{3fd774af-dfbe-40e2-9944-a85206cf00ee}</UniqueIdentifier>

     </Filter>

-    <Filter Include="Header Files\Vulkan">

-      <UniqueIdentifier>{eae937f9-88b4-4bd4-ba7b-bb4a4dcdaf52}</UniqueIdentifier>

-    </Filter>

-    <Filter Include="Header Files\Device">

-      <UniqueIdentifier>{31e80f94-e9d4-42cf-97b1-58bda4d1ab31}</UniqueIdentifier>

-    </Filter>

   </ItemGroup>

   <ItemGroup>

-    <ClCompile Include="libVulkan.cpp">

-      <Filter>Source Files\Vulkan</Filter>

-    </ClCompile>

-    <ClCompile Include="main.cpp">

-      <Filter>Source Files\Vulkan</Filter>

-    </ClCompile>

-    <ClCompile Include="VkDebug.cpp">

-      <Filter>Source Files\Vulkan</Filter>

-    </ClCompile>

-    <ClCompile Include="VkGetProcAddress.cpp">

-      <Filter>Source Files\Vulkan</Filter>

-    </ClCompile>

-    <ClCompile Include="VkPromotedExtensions.cpp">

-      <Filter>Source Files\Vulkan</Filter>

-    </ClCompile>

     <ClCompile Include="..\Device\VertexProcessor.cpp">

       <Filter>Source Files\Device</Filter>

     </ClCompile>

@@ -216,17 +201,71 @@
     <ClCompile Include="..\System\Timer.cpp">

       <Filter>Source Files\System</Filter>

     </ClCompile>

+    <ClCompile Include="libVulkan.cpp">

+      <Filter>Source Files\Vulkan</Filter>

+    </ClCompile>

+    <ClCompile Include="main.cpp">

+      <Filter>Source Files\Vulkan</Filter>

+    </ClCompile>

+    <ClCompile Include="VkCommandBuffer.cpp">

+      <Filter>Source Files\Vulkan</Filter>

+    </ClCompile>

+    <ClCompile Include="VkDebug.cpp">

+      <Filter>Source Files\Vulkan</Filter>

+    </ClCompile>

+    <ClCompile Include="VkDevice.cpp">

+      <Filter>Source Files\Vulkan</Filter>

+    </ClCompile>

+    <ClCompile Include="VkGetProcAddress.cpp">

+      <Filter>Source Files\Vulkan</Filter>

+    </ClCompile>

+    <ClCompile Include="VkInstance.cpp">

+      <Filter>Source Files\Vulkan</Filter>

+    </ClCompile>

+    <ClCompile Include="VkMemory.cpp">

+      <Filter>Source Files\Vulkan</Filter>

+    </ClCompile>

+    <ClCompile Include="VkPhysicalDevice.cpp">

+      <Filter>Source Files\Vulkan</Filter>

+    </ClCompile>

+    <ClCompile Include="VkPromotedExtensions.cpp">

+      <Filter>Source Files\Vulkan</Filter>

+    </ClCompile>

+    <ClCompile Include="VkQueue.cpp">

+      <Filter>Source Files\Vulkan</Filter>

+    </ClCompile>

   </ItemGroup>

   <ItemGroup>

     <ClInclude Include="resource.h">

       <Filter>Header Files\Vulkan</Filter>

     </ClInclude>

-    <ClInclude Include="VkDebug.hpp">

+    <ClInclude Include="VkCommandBuffer.hpp">

+      <Filter>Header Files\Vulkan</Filter>

+    </ClInclude>

+    <ClInclude Include="VkConfig.h">

+      <Filter>Header Files\Vulkan</Filter>

+    </ClInclude>

+    <ClInclude Include="VkDevice.hpp">

       <Filter>Header Files\Vulkan</Filter>

     </ClInclude>

     <ClInclude Include="VkGetProcAddress.h">

       <Filter>Header Files\Vulkan</Filter>

     </ClInclude>

+    <ClInclude Include="VkInstance.hpp">

+      <Filter>Header Files\Vulkan</Filter>

+    </ClInclude>

+    <ClInclude Include="VkMemory.h">

+      <Filter>Header Files\Vulkan</Filter>

+    </ClInclude>

+    <ClInclude Include="VkObject.hpp">

+      <Filter>Header Files\Vulkan</Filter>

+    </ClInclude>

+    <ClInclude Include="VkPhysicalDevice.hpp">

+      <Filter>Header Files\Vulkan</Filter>

+    </ClInclude>

+    <ClInclude Include="VkQueue.hpp">

+      <Filter>Header Files\Vulkan</Filter>

+    </ClInclude>

     <ClInclude Include="..\Device\VertexProcessor.hpp">

       <Filter>Header Files\Device</Filter>

     </ClInclude>

@@ -419,6 +458,9 @@
     <ClInclude Include="..\System\Types.hpp">

       <Filter>Header Files\System</Filter>

     </ClInclude>

+    <ClInclude Include="VkDebug.hpp">

+      <Filter>Header Files\Vulkan</Filter>

+    </ClInclude>

   </ItemGroup>

   <ItemGroup>

     <None Include="swiftshader_icd.def" />