Browse Source

More work on Vulkan buffers

BearishSun 9 years ago
parent
commit
6e60730055
23 changed files with 295 additions and 72 deletions
  1. 2 9
      Source/BansheeCore/Include/BsHardwareBuffer.h
  2. 1 1
      Source/BansheeCore/Source/BsIndexBuffer.cpp
  3. 1 1
      Source/BansheeCore/Source/BsVertexBuffer.cpp
  4. 1 1
      Source/BansheeD3D11RenderAPI/Source/BsD3D11HardwareBuffer.cpp
  5. 1 1
      Source/BansheeD3D11RenderAPI/Source/BsD3D11IndexBuffer.cpp
  6. 1 1
      Source/BansheeD3D11RenderAPI/Source/BsD3D11VertexBuffer.cpp
  7. 1 0
      Source/BansheeVulkanRenderAPI/Include/BsVulkanDescriptorPool.h
  8. 10 1
      Source/BansheeVulkanRenderAPI/Include/BsVulkanDevice.h
  9. 7 0
      Source/BansheeVulkanRenderAPI/Include/BsVulkanGpuBuffer.h
  10. 8 0
      Source/BansheeVulkanRenderAPI/Include/BsVulkanGpuParamBlockBuffer.h
  11. 1 0
      Source/BansheeVulkanRenderAPI/Include/BsVulkanGpuParams.h
  12. 43 7
      Source/BansheeVulkanRenderAPI/Include/BsVulkanHardwareBuffer.h
  13. 1 1
      Source/BansheeVulkanRenderAPI/Include/BsVulkanSamplerState.h
  14. 2 1
      Source/BansheeVulkanRenderAPI/Include/BsVulkanTexture.h
  15. 1 0
      Source/BansheeVulkanRenderAPI/Source/BsVulkanDescriptorManager.cpp
  16. 6 3
      Source/BansheeVulkanRenderAPI/Source/BsVulkanDescriptorPool.cpp
  17. 5 4
      Source/BansheeVulkanRenderAPI/Source/BsVulkanDevice.cpp
  18. 21 1
      Source/BansheeVulkanRenderAPI/Source/BsVulkanGpuBuffer.cpp
  19. 14 1
      Source/BansheeVulkanRenderAPI/Source/BsVulkanGpuParamBlockBuffer.cpp
  20. 33 10
      Source/BansheeVulkanRenderAPI/Source/BsVulkanGpuParams.cpp
  21. 104 25
      Source/BansheeVulkanRenderAPI/Source/BsVulkanHardwareBuffer.cpp
  22. 13 1
      Source/BansheeVulkanRenderAPI/Source/BsVulkanRenderAPI.cpp
  23. 18 3
      Source/BansheeVulkanRenderAPI/Source/BsVulkanTexture.cpp

+ 2 - 9
Source/BansheeCore/Include/BsHardwareBuffer.h

@@ -169,9 +169,6 @@ namespace BansheeEngine
 		/**	Returns the Usage flags with which this buffer was created. */
         GpuBufferUsage getUsage() const { return mUsage; }
 
-		/**	Returns whether this buffer is held in system memory. */
-		bool isSystemMemory() const { return mSystemMemory; }
-
 		/**	Returns whether or not this buffer is currently locked. */
         bool isLocked() const { return mIsLocked; }	
 
@@ -184,12 +181,9 @@ namespace BansheeEngine
 		 * @param[in]	usage			Determines most common usage of the buffer. Usually has effect on what type of 
 		 *								memory will be buffer allocated in but that depends on render API. Specify dynamic 
 		 *								if you plan on modifying it often, static otherwise.
-		 * @param[in]	systemMemory	If enabled the the buffer will be kept in the system memory. System memory buffers 
-		 *								are often used as a source or destination for copies from/to other buffers. Some 
-		 *								APIs don't allow reading from non-system memory buffers.
 		 */
-		HardwareBuffer(GpuBufferUsage usage, bool systemMemory)
-			: mUsage(usage), mIsLocked(false), mSystemMemory(systemMemory)
+		HardwareBuffer(GpuBufferUsage usage)
+			: mUsage(usage), mIsLocked(false)
 		{  }
 
 		/** @copydoc lock */
@@ -204,7 +198,6 @@ namespace BansheeEngine
 		bool mIsLocked;
 		UINT32 mLockStart;
 		UINT32 mLockSize;
-		bool mSystemMemory;
     };
 
 	/** @} */

+ 1 - 1
Source/BansheeCore/Source/BsIndexBuffer.cpp

@@ -21,7 +21,7 @@ namespace BansheeEngine
 	}
 
 	IndexBufferCore::IndexBufferCore(const INDEX_BUFFER_DESC& desc, GpuDeviceFlags deviceMask)
-		:HardwareBuffer(desc.usage, false), mProperties(desc.indexType, desc.numIndices)
+		:HardwareBuffer(desc.usage), mProperties(desc.indexType, desc.numIndices)
 	{ 
 		mSizeInBytes = mProperties.mIndexSize * mProperties.mNumIndices;
 	}

+ 1 - 1
Source/BansheeCore/Source/BsVertexBuffer.cpp

@@ -12,7 +12,7 @@ namespace BansheeEngine
 	}
 
 	VertexBufferCore::VertexBufferCore(const VERTEX_BUFFER_DESC& desc, GpuDeviceFlags deviceMask)
-		:HardwareBuffer(desc.usage, false), mProperties(desc.numVerts, desc.vertexSize)
+		:HardwareBuffer(desc.usage), mProperties(desc.numVerts, desc.vertexSize)
 	{
 		mSizeInBytes = mProperties.mVertexSize * mProperties.mNumVertices;
 	}

+ 1 - 1
Source/BansheeD3D11RenderAPI/Source/BsD3D11HardwareBuffer.cpp

@@ -10,7 +10,7 @@ namespace BansheeEngine
 {
 	D3D11HardwareBuffer::D3D11HardwareBuffer(BufferType btype, GpuBufferUsage usage, UINT32 elementCount, UINT32 elementSize, 
 		D3D11Device& device, bool useSystemMem, bool streamOut, bool randomGpuWrite, bool useCounter)
-		: HardwareBuffer(usage, useSystemMem), mD3DBuffer(nullptr), mpTempStagingBuffer(nullptr), mUseTempStagingBuffer(false),
+		: HardwareBuffer(usage), mD3DBuffer(nullptr), mpTempStagingBuffer(nullptr), mUseTempStagingBuffer(false),
 		 mBufferType(btype), mDevice(device), mElementCount(elementCount), mElementSize(elementSize), mRandomGpuWrite(randomGpuWrite),
 		 mUseCounter(useCounter)
 	{

+ 1 - 1
Source/BansheeD3D11RenderAPI/Source/BsD3D11IndexBuffer.cpp

@@ -23,7 +23,7 @@ namespace BansheeEngine
 
 	void D3D11IndexBufferCore::initialize()
 	{
-		mBuffer = bs_new<D3D11HardwareBuffer>(D3D11HardwareBuffer::BT_INDEX, mUsage, 1, mSizeInBytes, std::ref(mDevice), mSystemMemory);
+		mBuffer = bs_new<D3D11HardwareBuffer>(D3D11HardwareBuffer::BT_INDEX, mUsage, 1, mSizeInBytes, std::ref(mDevice), false);
 
 		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_IndexBuffer);
 		IndexBufferCore::initialize();

+ 1 - 1
Source/BansheeD3D11RenderAPI/Source/BsD3D11VertexBuffer.cpp

@@ -65,7 +65,7 @@ namespace BansheeEngine
 	void D3D11VertexBufferCore::initialize()
 	{
 		mBuffer = bs_new<D3D11HardwareBuffer>(D3D11HardwareBuffer::BT_VERTEX, 
-			mUsage, 1, mSizeInBytes, std::ref(mDevice), mSystemMemory, mStreamOut);
+			mUsage, 1, mSizeInBytes, std::ref(mDevice), false, mStreamOut);
 
 		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_VertexBuffer);
 		VertexBufferCore::initialize();

+ 1 - 0
Source/BansheeVulkanRenderAPI/Include/BsVulkanDescriptorPool.h

@@ -24,6 +24,7 @@ namespace BansheeEngine
 		static const UINT32 sMaxSets = 8192;
 		static const UINT32 sMaxSampledImages = 4096;
 		static const UINT32 sMaxImages = 2048;
+		static const UINT32 sMaxSampledBuffers = 2048;
 		static const UINT32 sMaxBuffers = 2048;
 		static const UINT32 sMaxUniformBuffers = 2048;
 

+ 10 - 1
Source/BansheeVulkanRenderAPI/Include/BsVulkanDevice.h

@@ -26,7 +26,10 @@ namespace BansheeEngine
 		VkDevice getLogical() const { return mLogicalDevice; }
 
 		/** Returns true if the device is one of the primary GPU's. */
-		bool isPrimary() const;
+		bool isPrimary() const { return mIsPrimary; }
+
+		/** Blocks the calling thread until all operations on the device finish. */
+		void waitIdle() const;
 
 		/** Returns a set of properties describing the physical device. */
 		const VkPhysicalDeviceProperties& getDeviceProperties() const { return mDeviceProperties; }
@@ -80,11 +83,17 @@ namespace BansheeEngine
 		void freeMemory(VkDeviceMemory memory);
 
 	private:
+		friend class VulkanRenderAPI;
+
 		/** Attempts to find a memory type that matches the requirements bits and the requested flags. */
 		uint32_t findMemoryType(uint32_t requirementBits, VkMemoryPropertyFlags wantedFlags);
 
+		/** Marks the device as a primary device. */
+		void setIsPrimary() { mIsPrimary = true; }
+
 		VkPhysicalDevice mPhysicalDevice;
 		VkDevice mLogicalDevice;
+		bool mIsPrimary;
 
 		VulkanCmdBufferPool* mCommandBufferPool;
 		VulkanDescriptorManager* mDescriptorManager;

+ 7 - 0
Source/BansheeVulkanRenderAPI/Include/BsVulkanGpuBuffer.h

@@ -34,6 +34,11 @@ namespace BansheeEngine
 		void copyData(GpuBufferCore& srcBuffer, UINT32 srcOffset, 
 			UINT32 dstOffset, UINT32 length, bool discardWholeBuffer = false) override;
 		
+		/** 
+		 * Gets the resource wrapping the buffer object, on the specified device. If GPU param block buffer's device mask
+		 * doesn't include the provided device, null is returned. 
+		 */
+		VulkanBuffer* getResource(UINT32 deviceIdx) const;
 	protected:
 		friend class VulkanHardwareBufferCoreManager;
 
@@ -48,6 +53,8 @@ namespace BansheeEngine
 		/** @copydoc GpuBufferCore::initialize */
 		void initialize() override;
 	private:
+		VulkanHardwareBuffer* mBuffer;
+		GpuDeviceFlags mDeviceMask;
     };
 
 	/** @} */

+ 8 - 0
Source/BansheeVulkanRenderAPI/Include/BsVulkanGpuParamBlockBuffer.h

@@ -23,11 +23,19 @@ namespace BansheeEngine
 
 		/** @copydoc GpuParamBlockBufferCore::readFromGPU */
 		void readFromGPU(UINT8* data) const override;
+
+		/** 
+		 * Gets the resource wrapping the buffer object, on the specified device. If GPU param block buffer's device mask
+		 * doesn't include the provided device, null is returned. 
+		 */
+		VulkanBuffer* getResource(UINT32 deviceIdx) const;
 	protected:
 		/** @copydoc GpuParamBlockBufferCore::initialize */
 		void initialize() override;
 
 	private:
+		VulkanHardwareBuffer* mBuffer;
+		GpuDeviceFlags mDeviceMask;
 	};
 
 	/** @} */

+ 1 - 0
Source/BansheeVulkanRenderAPI/Include/BsVulkanGpuParams.h

@@ -42,6 +42,7 @@ namespace BansheeEngine
 		{
 			VkDescriptorImageInfo image;
 			VkDescriptorBufferInfo buffer;
+			VkBufferView bufferView;
 		};
 
 		/** All GPU param data related to a single descriptor set. */

+ 43 - 7
Source/BansheeVulkanRenderAPI/Include/BsVulkanHardwareBuffer.h

@@ -3,6 +3,7 @@
 #pragma once
 
 #include "BsVulkanPrerequisites.h"
+#include "BsVulkanResource.h"
 #include "BsHardwareBuffer.h"
 
 namespace BansheeEngine
@@ -11,18 +12,47 @@ namespace BansheeEngine
 	 *  @{
 	 */
 
+	/** Wrapper around a Vulkan buffer object that manages its usage and lifetime. */
+	class VulkanBuffer : public VulkanResource
+	{
+	public:
+		VulkanBuffer(VulkanResourceManager* owner, VkBuffer buffer, VkBufferView view, VkDeviceMemory memory);
+		~VulkanBuffer();
+
+		/** Returns the internal handle to the Vulkan object. */
+		VkBuffer getHandle() const { return mBuffer; }
+
+		/** Returns a buffer view that covers the entire buffer. */
+		VkBufferView getView() const { return mView; }
+
+	private:
+		VkBuffer mBuffer;
+		VkBufferView mView;
+		VkDeviceMemory mMemory;
+	};
+	
 	/**	Class containing common functionality for all Vulkan hardware buffers. */
 	class VulkanHardwareBuffer : public HardwareBuffer
 	{
-		/** Information about allocated buffer memory for a single device. */
-		struct MemoryInfo
+	public:
+		/**	Available types of Vulkan buffers. */
+		enum BufferType
 		{
-			SPtr<VulkanDevice> device;
-			VkDeviceMemory memory;
+			/** Contains geometry vertices and their properties. */
+			BT_VERTEX = 0x1,
+			/** Contains triangle to vertex mapping. */
+			BT_INDEX = 0x2,
+			/** Contains GPU program parameters. */
+			BT_UNIFORM = 0x4,
+			/** Generic read-only GPU buffer containing formatted data. */
+			BT_GENERIC = 0x8,
+			/** Generic read/write GPU buffer containing formatted data. */
+			BT_STORAGE = 0x10,
+			/** Helper buffer that can be written to on the CPU. Used for copy operations. */
+			BT_STAGING = 0x20,
 		};
 
-	public:
-		VulkanHardwareBuffer(GpuBufferUsage usage, const VkMemoryRequirements& reqs, bool useSystemMem = false,
+		VulkanHardwareBuffer(BufferType type, GpuBufferFormat format, GpuBufferUsage usage, UINT32 size,
 			GpuDeviceFlags deviceMask = GDF_DEFAULT);
 		~VulkanHardwareBuffer();
 
@@ -37,6 +67,12 @@ namespace BansheeEngine
 		void copyData(HardwareBuffer& srcBuffer, UINT32 srcOffset, UINT32 dstOffset, 
 			UINT32 length, bool discardWholeBuffer = false, UINT32 syncMask = 0x00000001) override;
 
+		/** 
+		 * Gets the resource wrapping the buffer object, on the specified device. If hardware buffer device mask doesn't 
+		 * include the provided device, null is returned. 
+		 */
+		VulkanBuffer* getResource(UINT32 deviceIdx) const { return mBuffers[deviceIdx]; }
+
 	protected:
 		/** @copydoc HardwareBuffer::map */
 		void* map(UINT32 offset, UINT32 length, GpuLockOptions options, UINT32 syncMask) override;
@@ -44,7 +80,7 @@ namespace BansheeEngine
 		/** @copydoc HardwareBuffer::unmap */
 		void unmap() override;
 
-		MemoryInfo mAllocations[BS_MAX_DEVICES];
+		VulkanBuffer* mBuffers[BS_MAX_DEVICES];
 	};
 
 	/** @} */

+ 1 - 1
Source/BansheeVulkanRenderAPI/Include/BsVulkanSamplerState.h

@@ -50,7 +50,7 @@ namespace BansheeEngine
 		void getHandles(GpuDeviceFlags mask, VkSampler(&handles)[BS_MAX_LINKED_DEVICES], UINT32& numHandles);
 
 	protected:
-		friend class D3D11RenderStateCoreManager;
+		friend class VulkanRenderStateCoreManager;
 
 		VulkanSamplerStateCore(const SAMPLER_STATE_DESC& desc, GpuDeviceFlags deviceMask);
 

+ 2 - 1
Source/BansheeVulkanRenderAPI/Include/BsVulkanTexture.h

@@ -16,7 +16,7 @@ namespace BansheeEngine
 	class VulkanImage : public VulkanResource
 	{
 	public:
-		VulkanImage(VulkanResourceManager* owner, VkImage image, VkImageLayout layout);
+		VulkanImage(VulkanResourceManager* owner, VkImage image, VkDeviceMemory memory, VkImageLayout layout);
 		~VulkanImage();
 
 		/** Returns the internal handle to the Vulkan object. */
@@ -30,6 +30,7 @@ namespace BansheeEngine
 
 	private:
 		VkImage mImage;
+		VkDeviceMemory mMemory;
 		VkImageLayout mLayout;
 	};
 

+ 1 - 0
Source/BansheeVulkanRenderAPI/Source/BsVulkanDescriptorManager.cpp

@@ -2,6 +2,7 @@
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 #include "BsVulkanDescriptorManager.h"
 #include "BsVulkanDescriptorLayout.h"
+#include "BsVulkanDescriptorSet.h"
 #include "BsVulkanDescriptorPool.h"
 #include "BsVulkanDevice.h"
 #include "BsVulkanResource.h"

+ 6 - 3
Source/BansheeVulkanRenderAPI/Source/BsVulkanDescriptorPool.cpp

@@ -8,7 +8,7 @@ namespace BansheeEngine
 	VulkanDescriptorPool::VulkanDescriptorPool(VulkanDevice& device)
 		:mDevice(device)
 	{
-		VkDescriptorPoolSize poolSizes[4];
+		VkDescriptorPoolSize poolSizes[5];
 		poolSizes[0].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
 		poolSizes[0].descriptorCount = sMaxSampledImages;
 
@@ -18,8 +18,11 @@ namespace BansheeEngine
 		poolSizes[2].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
 		poolSizes[2].descriptorCount = sMaxImages;
 
-		poolSizes[3].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
-		poolSizes[3].descriptorCount = sMaxBuffers;
+		poolSizes[3].type = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
+		poolSizes[3].descriptorCount = sMaxSampledBuffers;
+
+		poolSizes[4].type = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
+		poolSizes[4].descriptorCount = sMaxBuffers;
 
 		VkDescriptorPoolCreateInfo poolCI;
 		poolCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;

+ 5 - 4
Source/BansheeVulkanRenderAPI/Source/BsVulkanDevice.cpp

@@ -8,7 +8,7 @@
 namespace BansheeEngine
 {
 	VulkanDevice::VulkanDevice(VkPhysicalDevice device)
-		:mPhysicalDevice(device), mLogicalDevice(nullptr), mQueueInfos{}
+		:mPhysicalDevice(device), mLogicalDevice(nullptr), mIsPrimary(false), mQueueInfos()
 	{
 		// Set to default
 		for (UINT32 i = 0; i < GQT_COUNT; i++)
@@ -116,7 +116,7 @@ namespace BansheeEngine
 
 	VulkanDevice::~VulkanDevice()
 	{
-		vkDeviceWaitIdle(mLogicalDevice);
+		waitIdle();
 
 		for (UINT32 i = 0; i < GQT_COUNT; i++)
 		{
@@ -132,9 +132,10 @@ namespace BansheeEngine
 		vkDestroyDevice(mLogicalDevice, gVulkanAllocator);
 	}
 
-	bool VulkanDevice::isPrimary() const
+	void VulkanDevice::waitIdle() const
 	{
-		return getDeviceProperties().deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU;
+		VkResult result = vkDeviceWaitIdle(mLogicalDevice);
+		assert(result == VK_SUCCESS);
 	}
 
 	VkDeviceMemory VulkanDevice::allocateMemory(VkImage image, VkMemoryPropertyFlags flags)

+ 21 - 1
Source/BansheeVulkanRenderAPI/Source/BsVulkanGpuBuffer.cpp

@@ -1,13 +1,14 @@
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 #include "BsVulkanGpuBuffer.h"
+#include "BsVulkanHardwareBuffer.h"
 #include "BsRenderStats.h"
 #include "BsException.h"
 
 namespace BansheeEngine
 {
 	VulkanGpuBufferCore::VulkanGpuBufferCore(const GPU_BUFFER_DESC& desc, GpuDeviceFlags deviceMask)
-		: GpuBufferCore(desc, deviceMask)
+		: GpuBufferCore(desc, deviceMask), mBuffer(nullptr), mDeviceMask(deviceMask)
 	{
 		if (desc.type != GBT_STANDARD)
 			assert(desc.format == BF_UNKNOWN && "Format must be set to BF_UNKNOWN when using non-standard buffers");
@@ -17,6 +18,9 @@ namespace BansheeEngine
 
 	VulkanGpuBufferCore::~VulkanGpuBufferCore()
 	{ 
+		if (mBuffer != nullptr)
+			bs_delete(mBuffer);
+
 		clearBufferViews();
 		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_GpuBuffer);
 	}
@@ -25,6 +29,17 @@ namespace BansheeEngine
 	{
 		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_GpuBuffer);
 
+		const GpuBufferProperties& props = getProperties();
+
+		VulkanHardwareBuffer::BufferType bufferType;
+		if (props.getRandomGpuWrite())
+			bufferType = VulkanHardwareBuffer::BT_STORAGE;
+		else
+			bufferType = VulkanHardwareBuffer::BT_GENERIC;;
+
+		UINT32 size = props.getElementCount() * props.getElementSize();;
+		mBuffer = bs_new<VulkanHardwareBuffer>(bufferType, props.getFormat(), props.getUsage(), size, mDeviceMask);
+
 		GpuBufferCore::initialize();
 	}
 
@@ -66,6 +81,11 @@ namespace BansheeEngine
 
 	}
 
+	VulkanBuffer* VulkanGpuBufferCore::getResource(UINT32 deviceIdx) const
+	{
+		return mBuffer->getResource(deviceIdx);
+	}
+
 	GpuBufferView* VulkanGpuBufferCore::createView()
 	{
 		// Not used

+ 14 - 1
Source/BansheeVulkanRenderAPI/Source/BsVulkanGpuParamBlockBuffer.cpp

@@ -1,17 +1,21 @@
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 #include "BsVulkanGpuParamBlockBuffer.h"
+#include "BsVulkanHardwareBuffer.h"
 #include "BsRenderStats.h"
 
 namespace BansheeEngine
 {
 	VulkanGpuParamBlockBufferCore::VulkanGpuParamBlockBufferCore(UINT32 size, GpuParamBlockUsage usage,
 		GpuDeviceFlags deviceMask)
-		:GpuParamBlockBufferCore(size, usage, deviceMask)
+		:GpuParamBlockBufferCore(size, usage, deviceMask), mBuffer(nullptr), mDeviceMask(deviceMask)
 	{ }
 
 	VulkanGpuParamBlockBufferCore::~VulkanGpuParamBlockBufferCore()
 	{
+		if(mBuffer != nullptr)
+			bs_delete(mBuffer);
+
 		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_GpuParamBuffer);
 	}
 
@@ -19,6 +23,10 @@ namespace BansheeEngine
 	{
 		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_GpuParamBuffer);
 
+		GpuBufferUsage usage = mUsage == GPBU_STATIC ? GBU_STATIC : GBU_DYNAMIC;
+
+		mBuffer = bs_new<VulkanHardwareBuffer>(VulkanHardwareBuffer::BT_UNIFORM, BF_32X1F, usage, mSize, mDeviceMask);
+
 		GpuParamBlockBufferCore::initialize();
 	}
 
@@ -31,4 +39,9 @@ namespace BansheeEngine
 	{
 		BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_GpuParamBuffer);
 	}
+
+	VulkanBuffer* VulkanGpuParamBlockBufferCore::getResource(UINT32 deviceIdx) const
+	{
+		return mBuffer->getResource(deviceIdx);
+	}
 }

+ 33 - 10
Source/BansheeVulkanRenderAPI/Source/BsVulkanGpuParams.cpp

@@ -7,6 +7,7 @@
 #include "BsVulkanGpuParamBlockBuffer.h"
 #include "BsVulkanGpuBuffer.h"
 #include "BsVulkanTexture.h"
+#include "BsVulkanHardwareBuffer.h"
 #include "BsVulkanDescriptorSet.h"
 #include "BsVulkanSamplerState.h"
 #include "BsGpuParamDesc.h"
@@ -104,8 +105,21 @@ namespace BansheeEngine
 			setUpBindings(paramDesc->paramBlocks, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
 			setUpBindings(paramDesc->textures, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
 			setUpBindings(paramDesc->loadStoreTextures, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
-			setUpBindings(paramDesc->buffers, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
 			setUpBindings(paramDesc->samplers, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
+
+			// Set up buffer bindings
+			for (auto& entry : paramDesc->buffers)
+			{
+				bool isLoadStore = entry.second.type != GPOT_BYTE_BUFFER &&
+					entry.second.type != GPOT_STRUCTURED_BUFFER;
+
+				UINT32 bindingIdx = bindingOffsets[entry.second.set] + entry.second.slot;
+
+				VkDescriptorSetLayoutBinding& binding = bindings[bindingIdx];
+				binding.descriptorCount = 1;
+				binding.stageFlags |= stageFlagsLookup[i];
+				binding.descriptorType = isLoadStore ? VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER : VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
+			}
 		}
 
 		VulkanRenderAPI& rapi = static_cast<VulkanRenderAPI&>(RenderAPICore::instance());
@@ -181,8 +195,7 @@ namespace BansheeEngine
 					writeSetInfo.dstArrayElement = 0;
 					writeSetInfo.descriptorCount = perSetBindings[k].descriptorCount;
 					writeSetInfo.descriptorType = perSetBindings[k].descriptorType;
-					writeSetInfo.pTexelBufferView = nullptr;
-					
+
 					bool isImage = writeSetInfo.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ||
 						writeSetInfo.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ||
 						writeSetInfo.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
@@ -198,15 +211,25 @@ namespace BansheeEngine
 
 						writeSetInfo.pImageInfo = &imageInfo;
 						writeSetInfo.pBufferInfo = nullptr;
+						writeSetInfo.pTexelBufferView = nullptr;
 					}
 					else
 					{
-						VkDescriptorBufferInfo& bufferInfo = perSetData.writeInfos[k].buffer;
-						bufferInfo.buffer = VK_NULL_HANDLE;
-						bufferInfo.offset = 0;
-						bufferInfo.range = VK_WHOLE_SIZE;
+						bool isLoadStore = writeSetInfo.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
+
+						if (!isLoadStore)
+						{
+							VkDescriptorBufferInfo& bufferInfo = perSetData.writeInfos[k].buffer;
+							bufferInfo.buffer = VK_NULL_HANDLE;
+							bufferInfo.offset = 0;
+							bufferInfo.range = VK_WHOLE_SIZE;
+
+							writeSetInfo.pBufferInfo = &bufferInfo;
+						}
+						else
+							writeSetInfo.pBufferInfo = nullptr;
 
-						writeSetInfo.pBufferInfo = &bufferInfo;
+						writeSetInfo.pTexelBufferView = nullptr;
 						writeSetInfo.pImageInfo = nullptr;
 					}
 				}
@@ -298,9 +321,9 @@ namespace BansheeEngine
 
 			VulkanBuffer* bufferRes = vulkanBuffer->getResource(i);
 			if (bufferRes != nullptr)
-				mPerDeviceData[i].perSetData[set].writeInfos[slot].buffer.buffer = bufferRes->getHandle();
+				mPerDeviceData[i].perSetData[set].writeInfos[slot].bufferView = bufferRes->getView();
 			else
-				mPerDeviceData[i].perSetData[set].writeInfos[slot].buffer.buffer = VK_NULL_HANDLE;
+				mPerDeviceData[i].perSetData[set].writeInfos[slot].bufferView = VK_NULL_HANDLE;
 		}
 
 		mSetsDirty[set] = true;

+ 104 - 25
Source/BansheeVulkanRenderAPI/Source/BsVulkanHardwareBuffer.cpp

@@ -3,51 +3,130 @@
 #include "BsVulkanHardwareBuffer.h"
 #include "BsVulkanRenderAPI.h"
 #include "BsVulkanDevice.h"
+#include "BsVulkanUtility.h"
 #include "BsException.h"
 
 namespace BansheeEngine
 {
-	VulkanHardwareBuffer::VulkanHardwareBuffer(GpuBufferUsage usage, const VkMemoryRequirements& reqs, bool useSystemMem, 
-		GpuDeviceFlags deviceMask)
-		: HardwareBuffer(usage, useSystemMem), mAllocations{}
+	VulkanBuffer::VulkanBuffer(VulkanResourceManager* owner, VkBuffer buffer, VkBufferView view, VkDeviceMemory memory)
+		:VulkanResource(owner, false, VulkanResourceType::Buffer), mBuffer(buffer), mView(view), mMemory(memory)
 	{
-		VulkanRenderAPI& rapi = static_cast<VulkanRenderAPI&>(RenderAPICore::instance());
 
-		UINT32 deviceIdx = 0;
-		if(deviceMask == GDF_DEFAULT)
-		{
-			const Vector<SPtr<VulkanDevice>>& devices = rapi._getPrimaryDevices();
-			for (auto& device : devices)
-				mAllocations[deviceIdx++].device = device;
-		}
-		else
-		{
-			for(UINT32 i = 0; i < BS_MAX_DEVICES; i++)
-			{
-				if ((1 << i) & deviceMask)
-					mAllocations[deviceIdx++].device = rapi._getDevice(i);
-			}
-		}
+	}
+
+	VulkanBuffer::~VulkanBuffer()
+	{
+		VulkanDevice& device = mOwner->getDevice();
 
-		VkMemoryPropertyFlags flags = useSystemMem ?
+		if (mView != VK_NULL_HANDLE)
+			vkDestroyBufferView(device.getLogical(), mView, gVulkanAllocator);
+
+		vkDestroyBuffer(device.getLogical(), mBuffer, gVulkanAllocator);
+		device.freeMemory(mMemory);
+	}
+
+	VulkanHardwareBuffer::VulkanHardwareBuffer(BufferType type, GpuBufferFormat format, GpuBufferUsage usage, 
+		UINT32 size, GpuDeviceFlags deviceMask)
+		: HardwareBuffer(usage), mBuffers()
+	{
+		bool staging = type == BT_STAGING;
+		bool needsView = false;
+
+		VkMemoryPropertyFlags flags = staging ?
 			(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) : // Note: Try using cached uncoherent memory
 			VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
 
+		VkBufferUsageFlags usageFlags = 0;
+		switch(type)
+		{
+		case BT_VERTEX:
+			usageFlags = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
+			break;
+		case BT_INDEX:
+			usageFlags = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
+			break;
+		case BT_UNIFORM:
+			usageFlags = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
+			break;
+		case BT_GENERIC:
+			usageFlags = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
+			needsView = true;
+			break;
+		case BT_STORAGE:
+			usageFlags = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
+			needsView = true;
+			break;
+		case BT_STAGING:
+			usageFlags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
+			break;
+		}
+
+		VulkanRenderAPI& rapi = static_cast<VulkanRenderAPI&>(RenderAPICore::instance());
+		VulkanDevice* devices[BS_MAX_DEVICES];
+		VulkanUtility::getDevices(rapi, deviceMask, devices);
+
+		// Allocate buffers per-device
 		for (UINT32 i = 0; i < BS_MAX_DEVICES; i++)
 		{
-			if (mAllocations[i].device == nullptr)
+			if (devices[i] == nullptr)
 				break;
 
-			mAllocations[i].memory = mAllocations[i].device->allocateMemory(reqs, flags);
+			VkBufferCreateInfo bufferCI;
+			bufferCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+			bufferCI.pNext = nullptr;
+			bufferCI.flags = 0; 
+			bufferCI.size = size;
+			bufferCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+			bufferCI.usage = usageFlags;
+			bufferCI.queueFamilyIndexCount = 0;
+			bufferCI.pQueueFamilyIndices = nullptr;
+
+			VkDevice device = devices[i]->getLogical();
+
+			VkBuffer buffer;
+			VkResult result = vkCreateBuffer(device, &bufferCI, gVulkanAllocator, &buffer);
+			assert(result == VK_SUCCESS);
+
+			VkMemoryRequirements memReqs;
+			vkGetBufferMemoryRequirements(device, buffer, &memReqs);
+
+			VkDeviceMemory memory = devices[i]->allocateMemory(memReqs, flags);
+			result = vkBindBufferMemory(device, buffer, memory, 0);
+			assert(result == VK_SUCCESS);
+
+			VkBufferView view;
+			if (needsView)
+			{
+				VkBufferViewCreateInfo bufferViewCI;
+				bufferViewCI.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
+				bufferViewCI.pNext = nullptr;
+				bufferViewCI.flags = 0;
+				bufferViewCI.buffer = buffer;
+				bufferViewCI.format = VulkanUtility::getBufferFormat(format);
+				bufferViewCI.offset = 0;
+				bufferViewCI.range = VK_WHOLE_SIZE;
+
+				result = vkCreateBufferView(device, &bufferViewCI, gVulkanAllocator, &view);
+				assert(result == VK_SUCCESS);
+			}
+			else
+				view = VK_NULL_HANDLE;
+
+			mBuffers[i] = devices[i]->getResourceManager().create<VulkanBuffer>(buffer, view, memory);
 		}
 
-		mSizeInBytes = (UINT32)reqs.size;
+		mSizeInBytes = size;
 	}
 
 	VulkanHardwareBuffer::~VulkanHardwareBuffer()
 	{
-		for(auto& alloc : mAllocations)
-			alloc.device->freeMemory(alloc.memory);
+		for (UINT32 i = 0; i < BS_MAX_DEVICES; i++)
+		{
+			if (mBuffers[i] == nullptr)
+				return;
+
+			mBuffers[i]->destroy();
+		}
 	}
 
 	void* VulkanHardwareBuffer::map(UINT32 offset, UINT32 length, GpuLockOptions options, UINT32 syncMask)

+ 13 - 1
Source/BansheeVulkanRenderAPI/Source/BsVulkanRenderAPI.cpp

@@ -185,8 +185,11 @@ namespace BansheeEngine
 		// Note: MULTIGPU - Detect multiple similar devices here if supporting multi-GPU
 		for (uint32_t i = 0; i < numDevices; i++)
 		{
-			if (mDevices[i]->isPrimary())
+			bool isPrimary = mDevices[i]->getDeviceProperties().deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU;
+
+			if (isPrimary)
 			{
+				mDevices[i]->setIsPrimary();
 				mPrimaryDevices.push_back(mDevices[i]);
 				break;
 			}
@@ -266,6 +269,15 @@ namespace BansheeEngine
 		HardwareBufferManager::shutDown();
 		TextureCoreManager::shutDown();
 		TextureManager::shutDown();
+
+		// Make sure everything finishes and all resources get freed
+		VulkanCommandBufferManager& cmdBufManager = static_cast<VulkanCommandBufferManager&>(CommandBufferManager::instance());
+		for (UINT32 i = 0; i < (UINT32)mDevices.size(); i++)
+		{
+			mDevices[i]->waitIdle();
+			cmdBufManager.refreshStates(i);
+		}
+
 		CommandBufferManager::shutDown();
 
 		mPrimaryDevices.clear();

+ 18 - 3
Source/BansheeVulkanRenderAPI/Source/BsVulkanTexture.cpp

@@ -8,15 +8,18 @@
 
 namespace BansheeEngine
 {
-	VulkanImage::VulkanImage(VulkanResourceManager* owner, VkImage image, VkImageLayout layout)
-		:VulkanResource(owner, false, VulkanResourceType::Image), mImage(image), mLayout(layout)
+	VulkanImage::VulkanImage(VulkanResourceManager* owner, VkImage image, VkDeviceMemory memory, VkImageLayout layout)
+		:VulkanResource(owner, false, VulkanResourceType::Image), mImage(image), mMemory(memory), mLayout(layout)
 	{
 		
 	}
 
 	VulkanImage::~VulkanImage()
 	{
-		vkDestroyImage(mOwner->getDevice().getLogical(), mImage, gVulkanAllocator);
+		VkDevice device = mOwner->getDevice().getLogical();
+
+		vkDestroyImage(device, mImage, gVulkanAllocator);
+		vkFreeMemory(device, mMemory, gVulkanAllocator);
 	}
 
 	VulkanTextureCore::VulkanTextureCore(const TEXTURE_DESC& desc, const SPtr<PixelData>& initialData,
@@ -28,6 +31,14 @@ namespace BansheeEngine
 
 	VulkanTextureCore::~VulkanTextureCore()
 	{ 
+		for (UINT32 i = 0; i < BS_MAX_DEVICES; i++)
+		{
+			if (mImages[i] == nullptr)
+				return;
+
+			mImages[i]->destroy();
+		}
+
 		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_Texture);
 	}
 
@@ -45,6 +56,8 @@ namespace BansheeEngine
 		// - If device idx doesn't match the mask, return VK_NULL_HANDLE
 		// - Otherwise return the default image view (created by default in initialize())
 		// - Free the view in destructor
+
+		return VK_NULL_HANDLE;
 	}
 
 	VkImageView VulkanTextureCore::getView(UINT32 deviceIdx, const TextureSurface& surface)
@@ -57,6 +70,8 @@ namespace BansheeEngine
 		//   - Resize the mTextureViews array as needed
 		//   - By default mTextureViews is nullptr, so allocate it during first call
 		// - Free the views in destructor (if any were allocated)
+
+		return VK_NULL_HANDLE;
 	}
 
 	void VulkanTextureCore::copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel, const SPtr<TextureCore>& target)