Buffer, BufferView and DeviceMemory

This cl adds Buffer, BufferView and DeviceMemory.
- DeviceMemory contains the appropriate logic to allocate and map
  device memory.
- Buffer simply wraps a DeviceMemory and an offset for now.
- BufferView wraps a Buffer with a memory region and a Format.

Bug b/118383648

Change-Id: I6d53b9f0728d4cdec2696339cc6aa8ce2e05ca49
Reviewed-on: https://swiftshader-review.googlesource.com/c/21728
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Vulkan/VkBuffer.cpp b/src/Vulkan/VkBuffer.cpp
new file mode 100644
index 0000000..57c6870
--- /dev/null
+++ b/src/Vulkan/VkBuffer.cpp
@@ -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.
+
+#include "VkBuffer.hpp"
+#include "VkConfig.h"
+#include "VkDeviceMemory.hpp"
+#include <memory.h>
+
+namespace vk
+{
+
+Buffer::Buffer(const VkBufferCreateInfo* pCreateInfo, void* mem) :
+	flags(pCreateInfo->flags), size(pCreateInfo->size), usage(pCreateInfo->usage),
+	sharingMode(pCreateInfo->sharingMode), queueFamilyIndexCount(pCreateInfo->queueFamilyIndexCount),
+	queueFamilyIndices(reinterpret_cast<uint32_t*>(mem))
+{
+	size_t queueFamilyIndicesSize = sizeof(uint32_t) * queueFamilyIndexCount;
+	memcpy(queueFamilyIndices, pCreateInfo->pQueueFamilyIndices, queueFamilyIndicesSize);
+}
+
+void Buffer::destroy(const VkAllocationCallbacks* pAllocator)
+{
+	vk::deallocate(queueFamilyIndices, pAllocator);
+}
+
+size_t Buffer::ComputeRequiredAllocationSize(const VkBufferCreateInfo* pCreateInfo)
+{
+	return sizeof(uint32_t) * pCreateInfo->queueFamilyIndexCount;
+}
+
+const VkMemoryRequirements Buffer::getMemoryRequirements() const
+{
+	VkMemoryRequirements memoryRequirements = {};
+	memoryRequirements.alignment = vk::REQUIRED_MEMORY_ALIGNMENT;
+	memoryRequirements.memoryTypeBits = vk::REQUIRED_MEMORY_TYPE_BITS;
+	memoryRequirements.size = size; // TODO: also reserve space for a header containing
+		                            // the size of the buffer (for robust buffer access)
+	return memoryRequirements;
+}
+
+void Buffer::bind(VkDeviceMemory pDeviceMemory, VkDeviceSize pMemoryOffset)
+{
+	memory = Cast(pDeviceMemory)->getOffsetPointer(pMemoryOffset);
+}
+
+} // namespace vk
diff --git a/src/Vulkan/VkBuffer.hpp b/src/Vulkan/VkBuffer.hpp
new file mode 100644
index 0000000..f25a717
--- /dev/null
+++ b/src/Vulkan/VkBuffer.hpp
@@ -0,0 +1,52 @@
+// 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_BUFFER_HPP_
+#define VK_BUFFER_HPP_
+
+#include "VkObject.hpp"
+
+namespace vk
+{
+
+class Buffer : public Object<Buffer, VkBuffer>
+{
+public:
+	Buffer(const VkBufferCreateInfo* pCreateInfo, void* mem);
+	~Buffer() = delete;
+	void destroy(const VkAllocationCallbacks* pAllocator);
+
+	static size_t ComputeRequiredAllocationSize(const VkBufferCreateInfo* pCreateInfo);
+
+	const VkMemoryRequirements getMemoryRequirements() const;
+	void bind(VkDeviceMemory pDeviceMemory, VkDeviceSize pMemoryOffset);
+
+private:
+	void*                 memory = nullptr;
+	VkBufferCreateFlags   flags = 0;
+	VkDeviceSize          size = 0;
+	VkBufferUsageFlags    usage = 0;
+	VkSharingMode         sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+	uint32_t              queueFamilyIndexCount = 0;
+	uint32_t*             queueFamilyIndices = nullptr;
+};
+
+static inline Buffer* Cast(VkBuffer object)
+{
+	return reinterpret_cast<Buffer*>(object);
+}
+
+} // namespace vk
+
+#endif // VK_BUFFER_HPP_
diff --git a/src/Vulkan/VkBufferView.hpp b/src/Vulkan/VkBufferView.hpp
new file mode 100644
index 0000000..e7fc734
--- /dev/null
+++ b/src/Vulkan/VkBufferView.hpp
@@ -0,0 +1,52 @@
+// 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_BUFFER_VIEW_HPP_
+#define VK_BUFFER_VIEW_HPP_
+
+#include "VkObject.hpp"
+
+namespace vk
+{
+
+class BufferView : public Object<BufferView, VkBufferView>
+{
+public:
+	BufferView(const VkBufferViewCreateInfo* pCreateInfo, void* mem) :
+		buffer(pCreateInfo->buffer), format(pCreateInfo->format), offset(pCreateInfo->offset), range(pCreateInfo->range)
+	{
+	}
+
+	~BufferView() = delete;
+
+	static size_t ComputeRequiredAllocationSize(const VkBufferViewCreateInfo* pCreateInfo)
+	{
+		return 0;
+	}
+
+private:
+	VkBuffer     buffer;
+	VkFormat     format;
+	VkDeviceSize offset;
+	VkDeviceSize range;
+};
+
+static inline BufferView* Cast(VkBufferView object)
+{
+	return reinterpret_cast<BufferView*>(object);
+}
+
+} // namespace vk
+
+#endif // VK_BUFFER_VIEW_HPP_
diff --git a/src/Vulkan/VkDestroy.h b/src/Vulkan/VkDestroy.h
index cf7251f..99a16e9 100644
--- a/src/Vulkan/VkDestroy.h
+++ b/src/Vulkan/VkDestroy.h
@@ -12,8 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "VkBuffer.hpp"
+#include "VkBufferView.hpp"
 #include "VkCommandBuffer.hpp"
 #include "VkDevice.hpp"
+#include "VkDeviceMemory.hpp"
 #include "VkEvent.hpp"
 #include "VkFence.hpp"
 #include "VkInstance.hpp"
diff --git a/src/Vulkan/VkDevice.hpp b/src/Vulkan/VkDevice.hpp
index e35549f..7f1f6af 100644
--- a/src/Vulkan/VkDevice.hpp
+++ b/src/Vulkan/VkDevice.hpp
@@ -45,6 +45,7 @@
 	                                VkPeerMemoryFeatureFlags* pPeerMemoryFeatures) const;
 	void getDescriptorSetLayoutSupport(const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
 	                                   VkDescriptorSetLayoutSupport* pSupport) const;
+	VkPhysicalDevice getPhysicalDevice() const { return physicalDevice; }
 
 private:
 	VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
diff --git a/src/Vulkan/VkDeviceMemory.cpp b/src/Vulkan/VkDeviceMemory.cpp
new file mode 100644
index 0000000..3dc42c4
--- /dev/null
+++ b/src/Vulkan/VkDeviceMemory.cpp
@@ -0,0 +1,72 @@
+// 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 "VkDeviceMemory.hpp"
+
+namespace vk
+{
+
+DeviceMemory::DeviceMemory(const VkMemoryAllocateInfo* pCreateInfo, void* mem) :
+	size(pCreateInfo->allocationSize), buffer(nullptr), memoryTypeIndex(pCreateInfo->memoryTypeIndex)
+{
+	ASSERT(size);
+}
+
+void DeviceMemory::destroy(const VkAllocationCallbacks* pAllocator)
+{
+	vk::deallocate(buffer, DEVICE_MEMORY);
+}
+
+size_t DeviceMemory::ComputeRequiredAllocationSize(const VkMemoryAllocateInfo* pCreateInfo)
+{
+	// buffer is "GPU memory", so we use device memory for it
+	return 0;
+}
+
+VkResult DeviceMemory::allocate()
+{
+	if(!buffer)
+	{
+		buffer = vk::allocate(size, REQUIRED_MEMORY_ALIGNMENT, DEVICE_MEMORY);
+	}
+
+	if(!buffer)
+	{
+		return VK_ERROR_OUT_OF_DEVICE_MEMORY;
+	}
+
+	return VK_SUCCESS;
+}
+
+VkResult DeviceMemory::map(VkDeviceSize pOffset, VkDeviceSize pSize, void** ppData)
+{
+	*ppData = getOffsetPointer(pOffset);
+	
+	return VK_SUCCESS;
+}
+
+VkDeviceSize DeviceMemory::getCommittedMemoryInBytes() const
+{
+	return size;
+}
+
+void* DeviceMemory::getOffsetPointer(VkDeviceSize pOffset)
+{
+	ASSERT(buffer);
+
+	return reinterpret_cast<char*>(buffer) + pOffset;
+}
+
+} // namespace vk
diff --git a/src/Vulkan/VkDeviceMemory.hpp b/src/Vulkan/VkDeviceMemory.hpp
new file mode 100644
index 0000000..ade5092
--- /dev/null
+++ b/src/Vulkan/VkDeviceMemory.hpp
@@ -0,0 +1,52 @@
+// 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_MEMORY_HPP_
+#define VK_DEVICE_MEMORY_HPP_
+
+#include "VkObject.hpp"
+
+namespace vk
+{
+
+class DeviceMemory : public Object<DeviceMemory, VkDeviceMemory>
+{
+public:
+	DeviceMemory(const VkMemoryAllocateInfo* pCreateInfo, void* mem);
+	~DeviceMemory() = delete;
+
+	static size_t ComputeRequiredAllocationSize(const VkMemoryAllocateInfo* pCreateInfo);
+
+	void destroy(const VkAllocationCallbacks* pAllocator);
+	VkResult allocate();
+	VkResult map(VkDeviceSize offset, VkDeviceSize size, void** ppData);
+	VkDeviceSize getCommittedMemoryInBytes() const;
+	void* getOffsetPointer(VkDeviceSize pOffset);
+	uint32_t getMemoryTypeIndex() const { return memoryTypeIndex; }
+
+private:
+	void*        buffer = nullptr;
+	VkDeviceSize size = 0;
+	uint32_t     memoryTypeIndex = 0;
+};
+
+static inline DeviceMemory* Cast(VkDeviceMemory object)
+{
+	return reinterpret_cast<DeviceMemory*>(object);
+}
+
+
+} // namespace vk
+
+#endif // VK_DEVICE_MEMORY_HPP_
diff --git a/src/Vulkan/VkPhysicalDevice.cpp b/src/Vulkan/VkPhysicalDevice.cpp
index 09c26de..23e2721 100644
--- a/src/Vulkan/VkPhysicalDevice.cpp
+++ b/src/Vulkan/VkPhysicalDevice.cpp
@@ -94,29 +94,29 @@
 
 void PhysicalDevice::getFeatures(VkPhysicalDevice16BitStorageFeatures* features) const
 {
-	features->storageBuffer16BitAccess = VK_FALSE;

-	features->storageInputOutput16 = VK_FALSE;

-	features->storagePushConstant16 = VK_FALSE;

+	features->storageBuffer16BitAccess = VK_FALSE;
+	features->storageInputOutput16 = VK_FALSE;
+	features->storagePushConstant16 = VK_FALSE;
 	features->uniformAndStorageBuffer16BitAccess = VK_FALSE;
 }
 
 void PhysicalDevice::getFeatures(VkPhysicalDeviceVariablePointerFeatures* features) const
 {
-	features->variablePointersStorageBuffer = VK_FALSE;

+	features->variablePointersStorageBuffer = VK_FALSE;
 	features->variablePointers = VK_FALSE;
 }
 
 void PhysicalDevice::getFeatures(VkPhysicalDevice8BitStorageFeaturesKHR* features) const
 {
-	features->storageBuffer8BitAccess = VK_FALSE;

-	features->uniformAndStorageBuffer8BitAccess = VK_FALSE;

+	features->storageBuffer8BitAccess = VK_FALSE;
+	features->uniformAndStorageBuffer8BitAccess = VK_FALSE;
 	features->storagePushConstant8 = VK_FALSE;
 }
 
 void PhysicalDevice::getFeatures(VkPhysicalDeviceMultiviewFeatures* features) const
 {
-	features->multiview = VK_FALSE;

-	features->multiviewGeometryShader = VK_FALSE;

+	features->multiview = VK_FALSE;
+	features->multiviewGeometryShader = VK_FALSE;
 	features->multiviewTessellationShader = VK_FALSE;
 }
 
@@ -272,24 +272,24 @@
 }
 
 void PhysicalDevice::getProperties(VkPhysicalDeviceIDProperties* properties) const
-{

-	memcpy(properties->deviceUUID, SWIFTSHADER_UUID, VK_UUID_SIZE);

-	memset(properties->deviceLUID, 0, VK_LUID_SIZE);

-	memset(properties->driverUUID, 0, VK_UUID_SIZE);

-	*((uint64_t*)properties->driverUUID) = DRIVER_VERSION;

-	properties->deviceNodeMask = 0;

+{
+	memcpy(properties->deviceUUID, SWIFTSHADER_UUID, VK_UUID_SIZE);
+	memset(properties->deviceLUID, 0, VK_LUID_SIZE);
+	memset(properties->driverUUID, 0, VK_UUID_SIZE);
+	*((uint64_t*)properties->driverUUID) = DRIVER_VERSION;
+	properties->deviceNodeMask = 0;
 	properties->deviceLUIDValid = VK_FALSE;
 }
 
 void PhysicalDevice::getProperties(VkPhysicalDeviceMaintenance3Properties* properties) const
 {
-	properties->maxMemoryAllocationSize = 1 << 31;

+	properties->maxMemoryAllocationSize = 1 << 31;
 	properties->maxPerSetDescriptors = 1024;
 }
 
 void PhysicalDevice::getProperties(VkPhysicalDeviceMultiviewProperties* properties) const
 {
-	properties->maxMultiviewInstanceIndex = (1 << 27) - 1;

+	properties->maxMultiviewInstanceIndex = (1 << 27) - 1;
 	properties->maxMultiviewViewCount = 6;
 }
 
@@ -305,9 +305,9 @@
 
 void PhysicalDevice::getProperties(VkPhysicalDeviceSubgroupProperties* properties) const
 {
-	properties->subgroupSize = 1;

-	properties->supportedStages = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_COMPUTE_BIT;

-	properties->supportedOperations = VK_SUBGROUP_FEATURE_BASIC_BIT;

+	properties->subgroupSize = 1;
+	properties->supportedStages = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_COMPUTE_BIT;
+	properties->supportedOperations = VK_SUBGROUP_FEATURE_BASIC_BIT;
 	properties->quadOperationsInAllStages = VK_FALSE;
 }
 
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index 50a91d8..4d1f44a 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -12,11 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "VkBuffer.hpp"
+#include "VkBufferView.hpp"
 #include "VkConfig.h"
 #include "VkCommandBuffer.hpp"
 #include "VkDebug.hpp"
 #include "VkDestroy.h"
 #include "VkDevice.hpp"
+#include "VkDeviceMemory.hpp"
 #include "VkEvent.hpp"
 #include "VkFence.hpp"
 #include "VkGetProcAddress.h"
@@ -377,9 +380,26 @@
 	TRACE("(VkDevice device = 0x%X, const VkMemoryAllocateInfo* pAllocateInfo = 0x%X, const VkAllocationCallbacks* pAllocator = 0x%X, VkDeviceMemory* pMemory = 0x%X)",
 		    device, pAllocateInfo, pAllocator, pMemory);
 
-	UNIMPLEMENTED();
+	if(pAllocateInfo->pNext)
+	{
+		UNIMPLEMENTED();
+	}
 
-	return VK_SUCCESS;
+	VkResult result = vk::DeviceMemory::Create(pAllocator, pAllocateInfo, pMemory);
+	if(result != VK_SUCCESS)
+	{
+		return result;
+	}
+
+	// Make sure the memory allocation is done now so that OOM errors can be checked now
+	result = vk::Cast(*pMemory)->allocate();
+	if(result != VK_SUCCESS)
+	{
+		vk::destroy(*pMemory, pAllocator);
+		*pMemory = VK_NULL_HANDLE;
+	}
+
+	return result;
 }
 
 VKAPI_ATTR void VKAPI_CALL vkFreeMemory(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks* pAllocator)
@@ -387,7 +407,7 @@
 	TRACE("(VkDevice device = 0x%X, VkDeviceMemory memory = 0x%X, const VkAllocationCallbacks* pAllocator = 0x%X)",
 		    device, memory, pAllocator);
 
-	UNIMPLEMENTED();
+	vk::destroy(memory, pAllocator);
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL vkMapMemory(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void** ppData)
@@ -395,16 +415,14 @@
 	TRACE("(VkDevice device = 0x%X, VkDeviceMemory memory = 0x%X, VkDeviceSize offset = %d, VkDeviceSize size = %d, VkMemoryMapFlags flags = 0x%X, void** ppData = 0x%X)",
 		    device, memory, offset, size, flags, ppData);
 
-	UNIMPLEMENTED();
-
-	return VK_SUCCESS;
+	return vk::Cast(memory)->map(offset, size, ppData);
 }
 
 VKAPI_ATTR void VKAPI_CALL vkUnmapMemory(VkDevice device, VkDeviceMemory memory)
 {
 	TRACE("(VkDevice device = 0x%X, VkDeviceMemory memory = 0x%X)", device, memory);
 
-	UNIMPLEMENTED();
+	// Noop, memory will be released when the DeviceMemory object is released
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL vkFlushMappedMemoryRanges(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges)
@@ -412,7 +430,7 @@
 	TRACE("(VkDevice device = 0x%X, uint32_t memoryRangeCount = %d, const VkMappedMemoryRange* pMemoryRanges = 0x%X)",
 		    device, memoryRangeCount, pMemoryRanges);
 
-	UNIMPLEMENTED();
+	// Noop, host and device memory are the same to SwiftShader
 
 	return VK_SUCCESS;
 }
@@ -422,15 +440,26 @@
 	TRACE("(VkDevice device = 0x%X, uint32_t memoryRangeCount = %d, const VkMappedMemoryRange* pMemoryRanges = 0x%X)",
 		    device, memoryRangeCount, pMemoryRanges);
 
-	UNIMPLEMENTED();
+	// Noop, host and device memory are the same to SwiftShader
 
 	return VK_SUCCESS;
 }
 
-VKAPI_ATTR void VKAPI_CALL vkGetDeviceMemoryCommitment(VkDevice device, VkDeviceMemory memory, VkDeviceSize* pCommittedMemoryInBytes)
+VKAPI_ATTR void VKAPI_CALL vkGetDeviceMemoryCommitment(VkDevice pDevice, VkDeviceMemory pMemory, VkDeviceSize* pCommittedMemoryInBytes)
 {
-	TRACE("()");
-	UNIMPLEMENTED();
+	TRACE("(VkDevice device = 0x%X, VkDeviceMemory memory = 0x%X, VkDeviceSize* pCommittedMemoryInBytes = 0x%X)",
+	      pDevice, pMemory, pCommittedMemoryInBytes);
+
+	auto memory = vk::Cast(pMemory);
+
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+	const auto& memoryProperties = vk::Cast(vk::Cast(pDevice)->getPhysicalDevice())->getMemoryProperties();
+	uint32_t typeIndex = memory->getMemoryTypeIndex();
+	ASSERT(typeIndex < memoryProperties.memoryTypeCount);
+	ASSERT(memoryProperties.memoryTypes[typeIndex].propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT);
+#endif
+
+	*pCommittedMemoryInBytes = memory->getCommittedMemoryInBytes();
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset)
@@ -438,7 +467,7 @@
 	TRACE("(VkDevice device = 0x%X, VkBuffer buffer = 0x%X, VkDeviceMemory memory = 0x%X, VkDeviceSize memoryOffset = %d)",
 		    device, buffer, memory, memoryOffset);
 
-	UNIMPLEMENTED();
+	vk::Cast(buffer)->bind(memory, memoryOffset);
 
 	return VK_SUCCESS;
 }
@@ -458,7 +487,7 @@
 	TRACE("(VkDevice device = 0x%X, VkBuffer buffer = 0x%X, VkMemoryRequirements* pMemoryRequirements = 0x%X)",
 		    device, buffer, pMemoryRequirements);
 
-	UNIMPLEMENTED();
+	*pMemoryRequirements = vk::Cast(buffer)->getMemoryRequirements();
 }
 
 VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements(VkDevice device, VkImage image, VkMemoryRequirements* pMemoryRequirements)
@@ -631,9 +660,12 @@
 	TRACE("(VkDevice device = 0x%X, const VkBufferCreateInfo* pCreateInfo = 0x%X, const VkAllocationCallbacks* pAllocator = 0x%X, VkBuffer* pBuffer = 0x%X)",
 		    device, pCreateInfo, pAllocator, pBuffer);
 
-	UNIMPLEMENTED();
+	if(pCreateInfo->pNext)
+	{
+		UNIMPLEMENTED();
+	}
 
-	return VK_SUCCESS;
+	return vk::Buffer::Create(pAllocator, pCreateInfo, pBuffer);
 }
 
 VKAPI_ATTR void VKAPI_CALL vkDestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator)
@@ -641,20 +673,28 @@
 	TRACE("(VkDevice device = 0x%X, VkBuffer buffer = 0x%X, const VkAllocationCallbacks* pAllocator = 0x%X)",
 		    device, buffer, pAllocator);
 
-	UNIMPLEMENTED();
+	vk::destroy(buffer, pAllocator);
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL vkCreateBufferView(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferView* pView)
 {
-	TRACE("()");
-	UNIMPLEMENTED();
-	return VK_SUCCESS;
+	TRACE("(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferView* pView)",
+		device, pCreateInfo, pAllocator, pView);
+
+	if(pCreateInfo->pNext || pCreateInfo->flags)
+	{
+		UNIMPLEMENTED();
+	}
+
+	return vk::BufferView::Create(pAllocator, pCreateInfo, pView);
 }
 
 VKAPI_ATTR void VKAPI_CALL vkDestroyBufferView(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks* pAllocator)
 {
-	TRACE("()");
-	UNIMPLEMENTED();
+	TRACE("(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks* pAllocator)",
+	      device, bufferView, pAllocator);
+
+	vk::destroy(bufferView, pAllocator);
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL vkCreateImage(VkDevice device, const VkImageCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImage* pImage)
@@ -1236,8 +1276,8 @@
 VKAPI_ATTR void VKAPI_CALL vkCmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers)
 {
 	TRACE("(VkCommandBuffer commandBuffer = 0x%X, VkPipelineStageFlags srcStageMask = 0x%X, VkPipelineStageFlags dstStageMask = 0x%X, VkDependencyFlags dependencyFlags = %d, uint32_t memoryBarrierCount = %d, onst VkMemoryBarrier* pMemoryBarriers = 0x%X,"
-		    " uint32_t bufferMemoryBarrierCount = %d, const VkBufferMemoryBarrier* pBufferMemoryBarriers = 0x%X, uint32_t imageMemoryBarrierCount = %d, const VkImageMemoryBarrier* pImageMemoryBarriers = 0x%X)",
-		    commandBuffer, srcStageMask, dstStageMask, dependencyFlags, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
+	      " uint32_t bufferMemoryBarrierCount = %d, const VkBufferMemoryBarrier* pBufferMemoryBarriers = 0x%X, uint32_t imageMemoryBarrierCount = %d, const VkImageMemoryBarrier* pImageMemoryBarriers = 0x%X)",
+	      commandBuffer, srcStageMask, dstStageMask, dependencyFlags, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
 
 	vk::Cast(commandBuffer)->pipelineBarrier(srcStageMask, dstStageMask, dependencyFlags,
 	                                         memoryBarrierCount, pMemoryBarriers,
@@ -1296,7 +1336,7 @@
 VKAPI_ATTR void VKAPI_CALL vkCmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents)
 {
 	TRACE("(VkCommandBuffer commandBuffer = 0x%X, const VkRenderPassBeginInfo* pRenderPassBegin = 0x%X, VkSubpassContents contents = %d)",
-		    commandBuffer, pRenderPassBegin, contents);
+	      commandBuffer, pRenderPassBegin, contents);
 
 	if(pRenderPassBegin->pNext)
 	{
@@ -1340,8 +1380,19 @@
 
 VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos)
 {
-	TRACE("()");
-	UNIMPLEMENTED();
+	TRACE("(VkDevice device = 0x%X, uint32_t bindInfoCount = %d, const VkBindBufferMemoryInfo* pBindInfos = 0x%X)",
+	      device, bindInfoCount, pBindInfos);
+
+	for(uint32_t i = 0; i < bindInfoCount; i++)
+	{
+		if(pBindInfos[i].pNext)
+		{
+			UNIMPLEMENTED();
+		}
+
+		vk::Cast(pBindInfos[i].buffer)->bind(pBindInfos[i].memory, pBindInfos[i].memoryOffset);
+	}
+
 	return VK_SUCCESS;
 }
 
diff --git a/src/Vulkan/vulkan.vcxproj b/src/Vulkan/vulkan.vcxproj
index 708ae7a..bf267c1 100644
--- a/src/Vulkan/vulkan.vcxproj
+++ b/src/Vulkan/vulkan.vcxproj
@@ -98,9 +98,11 @@
   <ItemGroup>

     <ClCompile Include="libVulkan.cpp" />

     <ClCompile Include="main.cpp" />

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

     <ClCompile Include="VkCommandBuffer.cpp" />

     <ClCompile Include="VkDebug.cpp" />

     <ClCompile Include="VkDevice.cpp" />

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

     <ClCompile Include="VkGetProcAddress.cpp" />

     <ClCompile Include="VkInstance.cpp" />

     <ClCompile Include="VkMemory.cpp" />

@@ -180,11 +182,14 @@
   </ItemGroup>

   <ItemGroup>

     <ClInclude Include="resource.h" />

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

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

     <ClInclude Include="VkCommandBuffer.hpp" />

     <ClInclude Include="VkConfig.h" />

     <ClInclude Include="VkDebug.hpp" />

     <ClInclude Include="VkDestroy.h" />

     <ClInclude Include="VkDevice.hpp" />

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

     <ClInclude Include="VkEvent.hpp" />

     <ClInclude Include="VkFence.hpp" />

     <ClInclude Include="VkGetProcAddress.h" />

diff --git a/src/Vulkan/vulkan.vcxproj.filters b/src/Vulkan/vulkan.vcxproj.filters
index 5486518..b134e04 100644
--- a/src/Vulkan/vulkan.vcxproj.filters
+++ b/src/Vulkan/vulkan.vcxproj.filters
@@ -207,6 +207,9 @@
     <ClCompile Include="main.cpp">

       <Filter>Source Files\Vulkan</Filter>

     </ClCompile>

+    <ClCompile Include="VkBuffer.cpp">

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

+    </ClCompile>

     <ClCompile Include="VkCommandBuffer.cpp">

       <Filter>Source Files\Vulkan</Filter>

     </ClCompile>

@@ -216,6 +219,9 @@
     <ClCompile Include="VkDevice.cpp">

       <Filter>Source Files\Vulkan</Filter>

     </ClCompile>

+    <ClCompile Include="VkDeviceMemory.cpp">

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

+    </ClCompile>

     <ClCompile Include="VkGetProcAddress.cpp">

       <Filter>Source Files\Vulkan</Filter>

     </ClCompile>

@@ -239,6 +245,12 @@
     <ClInclude Include="resource.h">

       <Filter>Header Files\Vulkan</Filter>

     </ClInclude>

+    <ClInclude Include="VkBuffer.hpp">

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

+    </ClInclude>

+    <ClInclude Include="VkBufferView.hpp">

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

+    </ClInclude>

     <ClInclude Include="VkCommandBuffer.hpp">

       <Filter>Header Files\Vulkan</Filter>

     </ClInclude>

@@ -248,6 +260,9 @@
     <ClInclude Include="VkDevice.hpp">

       <Filter>Header Files\Vulkan</Filter>

     </ClInclude>

+    <ClInclude Include="VkDeviceMemory.hpp">

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

+    </ClInclude>

     <ClInclude Include="VkEvent.hpp">

       <Filter>Header Files\Vulkan</Filter>

     </ClInclude>