Browse Source

Finishing up Vulkan sampler states

BearishSun 9 years ago
parent
commit
ca328eff7d

+ 13 - 5
Source/BansheeCore/Include/BsRenderStateManager.h

@@ -126,8 +126,12 @@ namespace BansheeEngine
 	public:
 		RenderStateCoreManager();
 
-		/** @copydoc RenderStateManager::createSamplerState */
-		SPtr<SamplerStateCore> createSamplerState(const SAMPLER_STATE_DESC& desc) const;
+		/** 
+		 * @copydoc RenderStateManager::createSamplerState 
+		 * @param[in]	deviceMask		Mask that determines on which GPU devices should the object be created on.
+		 */
+		SPtr<SamplerStateCore> createSamplerState(const SAMPLER_STATE_DESC& desc, 
+			GpuDeviceFlags deviceMask = GDF_DEFAULT) const;
 
 		/** @copydoc RenderStateManager::createDepthStencilState */
 		SPtr<DepthStencilStateCore> createDepthStencilState(const DEPTH_STENCIL_STATE_DESC& desc) const;
@@ -138,12 +142,16 @@ namespace BansheeEngine
 		/** @copydoc RenderStateManager::createBlendState */
 		SPtr<BlendStateCore> createBlendState(const BLEND_STATE_DESC& desc) const;
 
-		/** @copydoc RenderStateManager::createPipelineState */
+		/** 
+		 * @copydoc RenderStateManager::createPipelineState 
+		 * @param[in]	deviceMask		Mask that determines on which GPU devices should the object be created on.
+		 */
 		SPtr<GpuPipelineStateCore> createPipelineState(const PIPELINE_STATE_CORE_DESC& desc, 
 			GpuDeviceFlags deviceMask = GDF_DEFAULT) const;
 
 		/** Creates an uninitialized sampler state. Requires manual initialization after creation. */
-		SPtr<SamplerStateCore> _createSamplerState(const SAMPLER_STATE_DESC& desc) const;
+		SPtr<SamplerStateCore> _createSamplerState(const SAMPLER_STATE_DESC& desc, 
+			GpuDeviceFlags deviceMask = GDF_DEFAULT) const;
 
 		/** Creates an uninitialized depth-stencil state. Requires manual initialization after creation. */
 		SPtr<DepthStencilStateCore> _createDepthStencilState(const DEPTH_STENCIL_STATE_DESC& desc) const;
@@ -184,7 +192,7 @@ namespace BansheeEngine
 		void onShutDown() override;
 
 		/** @copydoc createSamplerState */
-		virtual SPtr<SamplerStateCore> createSamplerStateInternal(const SAMPLER_STATE_DESC& desc) const;
+		virtual SPtr<SamplerStateCore> createSamplerStateInternal(const SAMPLER_STATE_DESC& desc, GpuDeviceFlags deviceMask) const;
 
 		/** @copydoc createBlendState */
 		virtual SPtr<BlendStateCore> createBlendStateInternal(const BLEND_STATE_DESC& desc, UINT32 id) const;

+ 3 - 3
Source/BansheeCore/Include/BsSamplerState.h

@@ -166,8 +166,8 @@ namespace BansheeEngine
 		/**	Returns information about the sampler state. */
 		const SamplerProperties& getProperties() const;
 
-		/**	Creates a new sampler state using the provided descriptor structure. */
-		static SPtr<SamplerStateCore> create(const SAMPLER_STATE_DESC& desc);
+		/**	@copydoc RenderStateCoreManager::createSamplerState */
+		static SPtr<SamplerStateCore> create(const SAMPLER_STATE_DESC& desc, GpuDeviceFlags deviceMask = GDF_DEFAULT);
 
 		/**	Returns the default sampler state. */
 		static const SPtr<SamplerStateCore>& getDefault();
@@ -175,7 +175,7 @@ namespace BansheeEngine
 	protected:
 		friend class RenderStateCoreManager;
 
-		SamplerStateCore(const SAMPLER_STATE_DESC& desc);
+		SamplerStateCore(const SAMPLER_STATE_DESC& desc, GpuDeviceFlags deviceMask);
 
 		/** @copydoc CoreObjectCore::initialize */
 		void initialize() override;

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

@@ -125,7 +125,7 @@ namespace BansheeEngine
 
 	SPtr<BlendStateCore> BlendStateCore::create(const BLEND_STATE_DESC& desc)
 	{
-		return RenderStateCoreManager::instance()._createBlendState(desc);
+		return RenderStateCoreManager::instance().createBlendState(desc);
 	}
 
 	const SPtr<BlendStateCore>& BlendStateCore::getDefault()

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

@@ -62,7 +62,7 @@ namespace BansheeEngine
 
 	SPtr<DepthStencilStateCore> DepthStencilStateCore::create(const DEPTH_STENCIL_STATE_DESC& desc)
 	{
-		return RenderStateCoreManager::instance()._createDepthStencilState(desc);
+		return RenderStateCoreManager::instance().createDepthStencilState(desc);
 	}
 
 	const SPtr<DepthStencilStateCore>& DepthStencilStateCore::getDefault()

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

@@ -54,7 +54,7 @@ namespace BansheeEngine
 
 	SPtr<RasterizerStateCore> RasterizerStateCore::create(const RASTERIZER_STATE_DESC& desc)
 	{
-		return RenderStateCoreManager::instance()._createRasterizerState(desc);
+		return RenderStateCoreManager::instance().createRasterizerState(desc);
 	}
 
 	const SPtr<RasterizerStateCore>& RasterizerStateCore::getDefault()

+ 9 - 6
Source/BansheeCore/Source/BsRenderStateManager.cpp

@@ -127,12 +127,13 @@ namespace BansheeEngine
 		
 	}
 
-	SPtr<SamplerStateCore> RenderStateCoreManager::createSamplerState(const SAMPLER_STATE_DESC& desc) const
+	SPtr<SamplerStateCore> RenderStateCoreManager::createSamplerState(const SAMPLER_STATE_DESC& desc, 
+		GpuDeviceFlags deviceMask) const
 	{
 		SPtr<SamplerStateCore> state = findCachedState(desc);
 		if (state == nullptr)
 		{
-			state = createSamplerStateInternal(desc);
+			state = createSamplerStateInternal(desc, deviceMask);
 			state->initialize();
 
 			notifySamplerStateCreated(desc, state);
@@ -204,12 +205,13 @@ namespace BansheeEngine
 		return state;
 	}
 
-	SPtr<SamplerStateCore> RenderStateCoreManager::_createSamplerState(const SAMPLER_STATE_DESC& desc) const
+	SPtr<SamplerStateCore> RenderStateCoreManager::_createSamplerState(const SAMPLER_STATE_DESC& desc, 
+		GpuDeviceFlags deviceMask) const
 	{
 		SPtr<SamplerStateCore> state = findCachedState(desc);
 		if (state == nullptr)
 		{
-			state = createSamplerStateInternal(desc);
+			state = createSamplerStateInternal(desc, deviceMask);
 
 			notifySamplerStateCreated(desc, state);
 		}
@@ -427,9 +429,10 @@ namespace BansheeEngine
 		return nullptr;
 	}
 
-	SPtr<SamplerStateCore> RenderStateCoreManager::createSamplerStateInternal(const SAMPLER_STATE_DESC& desc) const
+	SPtr<SamplerStateCore> RenderStateCoreManager::createSamplerStateInternal(const SAMPLER_STATE_DESC& desc, GpuDeviceFlags deviceMask) const
 	{
-		SPtr<SamplerStateCore> state = bs_shared_ptr<SamplerStateCore>(new (bs_alloc<SamplerStateCore>()) SamplerStateCore(desc));
+		SPtr<SamplerStateCore> state = 
+			bs_shared_ptr<SamplerStateCore>(new (bs_alloc<SamplerStateCore>()) SamplerStateCore(desc, deviceMask));
 		state->_setThisPtr(state);
 
 		return state;

+ 3 - 3
Source/BansheeCore/Source/BsSamplerState.cpp

@@ -44,7 +44,7 @@ namespace BansheeEngine
 		return mData.borderColor;
 	}
 
-	SamplerStateCore::SamplerStateCore(const SAMPLER_STATE_DESC& desc)
+	SamplerStateCore::SamplerStateCore(const SAMPLER_STATE_DESC& desc, GpuDeviceFlags deviceMask)
 		:mProperties(desc)
 	{
 		
@@ -71,9 +71,9 @@ namespace BansheeEngine
 		return mProperties;
 	}
 
-	SPtr<SamplerStateCore> SamplerStateCore::create(const SAMPLER_STATE_DESC& desc)
+	SPtr<SamplerStateCore> SamplerStateCore::create(const SAMPLER_STATE_DESC& desc, GpuDeviceFlags deviceMask)
 	{
-		return RenderStateCoreManager::instance()._createSamplerState(desc);
+		return RenderStateCoreManager::instance().createSamplerState(desc, deviceMask);
 	}
 
 	const SPtr<SamplerStateCore>& SamplerStateCore::getDefault()

+ 1 - 1
Source/BansheeD3D11RenderAPI/Include/BsD3D11RenderStateManager.h

@@ -16,7 +16,7 @@ namespace BansheeEngine
 	{
 	protected:
 		/** @copydoc RenderStateCoreManager::createSamplerStateInternal */
-		SPtr<SamplerStateCore> createSamplerStateInternal(const SAMPLER_STATE_DESC& desc) const override;
+		SPtr<SamplerStateCore> createSamplerStateInternal(const SAMPLER_STATE_DESC& desc, GpuDeviceFlags deviceMask) const override;
 
 		/** @copydoc RenderStateCoreManager::createBlendStateInternal */
 		SPtr<BlendStateCore> createBlendStateInternal(const BLEND_STATE_DESC& desc, UINT32 id) const override;

+ 1 - 1
Source/BansheeD3D11RenderAPI/Include/BsD3D11SamplerState.h

@@ -21,7 +21,7 @@ namespace BansheeEngine
 	protected:
 		friend class D3D11RenderStateCoreManager;
 
-		D3D11SamplerStateCore(const SAMPLER_STATE_DESC& desc);
+		D3D11SamplerStateCore(const SAMPLER_STATE_DESC& desc, GpuDeviceFlags deviceMask);
 
 		/** @copydoc SamplerStateCore::createInternal */
 		void createInternal() override;

+ 2 - 2
Source/BansheeD3D11RenderAPI/Source/BsD3D11RenderStateManager.cpp

@@ -8,9 +8,9 @@
 
 namespace BansheeEngine
 {
-	SPtr<SamplerStateCore> D3D11RenderStateCoreManager::createSamplerStateInternal(const SAMPLER_STATE_DESC& desc) const
+	SPtr<SamplerStateCore> D3D11RenderStateCoreManager::createSamplerStateInternal(const SAMPLER_STATE_DESC& desc, GpuDeviceFlags deviceMask) const
 	{
-		SPtr<SamplerStateCore> ret = bs_shared_ptr<D3D11SamplerStateCore>(new (bs_alloc<D3D11SamplerStateCore>()) D3D11SamplerStateCore(desc));
+		SPtr<SamplerStateCore> ret = bs_shared_ptr<D3D11SamplerStateCore>(new (bs_alloc<D3D11SamplerStateCore>()) D3D11SamplerStateCore(desc, deviceMask));
 		ret->_setThisPtr(ret);
 
 		return ret;

+ 2 - 2
Source/BansheeD3D11RenderAPI/Source/BsD3D11SamplerState.cpp

@@ -8,8 +8,8 @@
 
 namespace BansheeEngine
 {
-	D3D11SamplerStateCore::D3D11SamplerStateCore(const SAMPLER_STATE_DESC& desc)
-		:SamplerStateCore(desc), mSamplerState(nullptr)
+	D3D11SamplerStateCore::D3D11SamplerStateCore(const SAMPLER_STATE_DESC& desc, GpuDeviceFlags deviceMask)
+		:SamplerStateCore(desc, deviceMask), mSamplerState(nullptr)
 	{ }
 
 	D3D11SamplerStateCore::~D3D11SamplerStateCore()

+ 3 - 0
Source/BansheeVulkanRenderAPI/Include/BsVulkanDevice.h

@@ -25,6 +25,9 @@ namespace BansheeEngine
 		/** Returns an object describing the logical properties of the device. */
 		VkDevice getLogical() const { return mLogicalDevice; }
 
+		/** Returns true if the device is one of the primary GPU's. */
+		bool isPrimary() const;
+
 		/** Returns a set of properties describing the physical device. */
 		const VkPhysicalDeviceProperties& getDeviceProperties() const { return mDeviceProperties; }
 

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

@@ -66,8 +66,7 @@ namespace BansheeEngine
 
 		VulkanGpuParams(const GPU_PARAMS_DESC& desc, GpuDeviceFlags deviceMask);
 
-		PerDeviceData mPerDeviceData[BS_MAX_LINKED_DEVICES];
-		UINT32 mNumDevices;
+		PerDeviceData mPerDeviceData[BS_MAX_DEVICES];
 		GpuDeviceFlags mDeviceMask;
 		UINT8* mData;
 		bool* mSetsDirty;

+ 4 - 0
Source/BansheeVulkanRenderAPI/Include/BsVulkanRenderStateManager.h

@@ -15,6 +15,10 @@ namespace BansheeEngine
 	class VulkanRenderStateCoreManager : public RenderStateCoreManager
 	{
 	protected:
+		/** @copydoc RenderStateCoreManager::createSamplerStateStateInternal */
+		SPtr<SamplerStateCore> createSamplerStateInternal(const SAMPLER_STATE_DESC& desc,
+			GpuDeviceFlags deviceMask) const override;
+
 		/** @copydoc RenderStateCoreManager::_createPipelineState */
 		SPtr<GpuPipelineStateCore> _createPipelineState(const PIPELINE_STATE_CORE_DESC& desc,
 			GpuDeviceFlags deviceMask = GDF_DEFAULT) const override;

+ 19 - 4
Source/BansheeVulkanRenderAPI/Include/BsVulkanSamplerState.h

@@ -32,18 +32,33 @@ namespace BansheeEngine
 	public:
 		~VulkanSamplerStateCore();
 
-		/** Gets the resource wrapping the sampler object. */
-		VulkanSampler* getResource() const { return mSampler; }
+		/** 
+		 * Gets the resource wrapping the sampler object, on the specified device. If sampler state device mask doesn't 
+		 * include the provided device, null is returned. 
+		 */
+		VulkanSampler* getResource(UINT32 deviceIdx) const { return mSamplers[deviceIdx]; }
+
+		/* 
+		 * Returns a set sampler handles for the devices matching the provided mask. 
+		 * 
+		 * @param[in]	mask		Mask which determines for which devices we want the handles for. The device must exist 
+		 *							in both the provided mask and the mask of the sampler state was created with.
+		 * @param[out]	handles		Output array holding up to BS_MAX_LINKED_DEVICES handles. Only the first @p numHandles
+		 *							entries of the array are defined.
+		 * @param[out]	numHandles	Number of entries in the @p handles array. 
+		 */
+		void getHandles(GpuDeviceFlags mask, VkSampler(&handles)[BS_MAX_LINKED_DEVICES], UINT32& numHandles);
 
 	protected:
 		friend class D3D11RenderStateCoreManager;
 
-		VulkanSamplerStateCore(const SAMPLER_STATE_DESC& desc);
+		VulkanSamplerStateCore(const SAMPLER_STATE_DESC& desc, GpuDeviceFlags deviceMask);
 
 		/** @copydoc SamplerStateCore::createInternal */
 		void createInternal() override;
 
-		VulkanSampler* mSampler;
+		VulkanSampler* mSamplers[BS_MAX_DEVICES];
+		GpuDeviceFlags mDeviceMask;
 	};
 
 	/** @} */

+ 5 - 1
Source/BansheeVulkanRenderAPI/Include/BsVulkanUtility.h

@@ -63,8 +63,12 @@ namespace BansheeEngine
 
 		/** 
 		 * Populates the provided array with Vulkan devices that correspond to provided flags. Sets null in unused slots. 
+		 * Each device is placed at its own index in the output array.
 		 */
-		static void getDevices(const VulkanRenderAPI& rapi, GpuDeviceFlags flags, VulkanDevice* (&devices)[BS_MAX_LINKED_DEVICES]);
+		static void getDevices(const VulkanRenderAPI& rapi, GpuDeviceFlags flags, VulkanDevice* (&devices)[BS_MAX_DEVICES]);
+
+		/** Checks is a flag for a particular device enabled. */
+		static bool isDeviceIdxSet(const VulkanRenderAPI& rapi, UINT32 idx, GpuDeviceFlags flags);
 	};
 
 	/** @} */

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

@@ -132,6 +132,11 @@ namespace BansheeEngine
 		vkDestroyDevice(mLogicalDevice, gVulkanAllocator);
 	}
 
+	bool VulkanDevice::isPrimary() const
+	{
+		return getDeviceProperties().deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU;
+	}
+
 	VkDeviceMemory VulkanDevice::allocateMemory(VkImage image, VkMemoryPropertyFlags flags)
 	{
 		VkMemoryRequirements memReq;

+ 81 - 41
Source/BansheeVulkanRenderAPI/Source/BsVulkanGpuParams.cpp

@@ -14,8 +14,7 @@
 namespace BansheeEngine
 {
 	VulkanGpuParams::VulkanGpuParams(const GPU_PARAMS_DESC& desc, GpuDeviceFlags deviceMask)
-		: GpuParamsCore(desc, deviceMask), mPerDeviceData{}, mNumDevices(0), mDeviceMask(deviceMask), mData(nullptr)
-		, mSetsDirty(nullptr)
+		: GpuParamsCore(desc, deviceMask), mPerDeviceData(), mDeviceMask(deviceMask), mData(nullptr), mSetsDirty(nullptr)
 	{
 		// Generate all required bindings
 		UINT32 numBindings = 0;
@@ -110,16 +109,18 @@ namespace BansheeEngine
 		}
 
 		VulkanRenderAPI& rapi = static_cast<VulkanRenderAPI&>(RenderAPICore::instance());
-		VulkanDevice* devices[BS_MAX_LINKED_DEVICES];
-		VulkanUtility::getDevices(rapi, deviceMask, devices);
+		VulkanDevice* devices[BS_MAX_DEVICES];
 
 		// Allocate layouts per-device
-		for (UINT32 i = 0; i < BS_MAX_LINKED_DEVICES; i++)
+		UINT32 numDevices = 0;
+		for (UINT32 i = 0; i < BS_MAX_DEVICES; i++)
 		{
-			if (devices[i] == nullptr)
-				break;
+			if (VulkanUtility::isDeviceIdxSet(rapi, i, deviceMask))
+				devices[i] = rapi._getDevice(i).get();
+			else
+				devices[i] = nullptr;
 
-			mNumDevices++;
+			numDevices++;
 		}
 
 		// Note: I'm assuming a single WriteInfo per binding, but if arrays sizes larger than 1 are eventually supported
@@ -128,15 +129,23 @@ namespace BansheeEngine
 		UINT32 perSetBytes = sizeof(PerSetData) * numSets;
 		UINT32 writeSetInfosBytes = sizeof(VkWriteDescriptorSet) * numBindings;
 		UINT32 writeInfosBytes = sizeof(WriteInfo) * numBindings;
-		mData = (UINT8*)bs_alloc(setsDirtyBytes + (perSetBytes + writeSetInfosBytes + writeInfosBytes) * mNumDevices);
+		mData = (UINT8*)bs_alloc(setsDirtyBytes + (perSetBytes + writeSetInfosBytes + writeInfosBytes) * numDevices);
 		UINT8* dataIter = mData;
 
 		mSetsDirty = (bool*)dataIter;
 		memset(mSetsDirty, 1, setsDirtyBytes);
 		dataIter += setsDirtyBytes;
 
-		for(UINT32 i = 0; i < mNumDevices; i++)
+		for(UINT32 i = 0; i < BS_MAX_DEVICES; i++)
 		{
+			if(devices[i] == nullptr)
+			{
+				mPerDeviceData[i].numSets = 0;
+				mPerDeviceData[i].perSetData = nullptr;
+
+				continue;
+			}
+
 			mPerDeviceData[i].numSets = numSets;
 			mPerDeviceData[i].perSetData = (PerSetData*)dataIter;
 			dataIter += sizeof(perSetBytes);
@@ -213,7 +222,7 @@ namespace BansheeEngine
 
 	VulkanGpuParams::~VulkanGpuParams()
 	{
-		for (UINT32 i = 0; i < mNumDevices; i++)
+		for (UINT32 i = 0; i < BS_MAX_DEVICES; i++)
 		{
 			for (UINT32 j = 0; j < mPerDeviceData[i].numSets; j++)
 				mPerDeviceData[i].perSetData[j].set->destroy();
@@ -229,11 +238,17 @@ namespace BansheeEngine
 		VulkanGpuParamBlockBufferCore* vulkanParamBlockBuffer =
 			static_cast<VulkanGpuParamBlockBufferCore*>(paramBlockBuffer.get());
 
-		VkBuffer buffers[BS_MAX_LINKED_DEVICES];
-		vulkanParamBlockBuffer->getHandles(mDeviceMask, buffers);
+		for (UINT32 i = 0; i < BS_MAX_DEVICES; i++)
+		{
+			if (mPerDeviceData[i].perSetData == nullptr)
+				continue;
 
-		for (UINT32 i = 0; i < mNumDevices; i++)
-			mPerDeviceData[i].perSetData[set].writeInfos[slot].buffer.buffer = buffers[i];
+			VulkanBuffer* bufferRes = vulkanParamBlockBuffer->getResource(i);
+			if (bufferRes != nullptr)
+				mPerDeviceData[i].perSetData[set].writeInfos[slot].buffer.buffer = bufferRes->getHandle();
+			else
+				mPerDeviceData[i].perSetData[set].writeInfos[slot].buffer.buffer = VK_NULL_HANDLE;
+		}
 
 		mSetsDirty[set] = true;
 	}
@@ -243,12 +258,17 @@ namespace BansheeEngine
 		GpuParamsCore::setTexture(set, slot, texture);
 
 		VulkanTextureCore* vulkanTexture = static_cast<VulkanTextureCore*>(texture.get());
+		for (UINT32 i = 0; i < BS_MAX_DEVICES; i++)
+		{
+			if (mPerDeviceData[i].perSetData == nullptr)
+				continue;
 
-		VkImageView imageViews[BS_MAX_LINKED_DEVICES];
-		vulkanTexture->getViews(mDeviceMask, imageViews);
-
-		for (UINT32 i = 0; i < mNumDevices; i++)
-			mPerDeviceData[i].perSetData[set].writeInfos[slot].image.imageView = imageViews[i];
+			VulkanImage* imageRes = vulkanTexture->getResource(i);
+			if (imageRes != nullptr)
+				mPerDeviceData[i].perSetData[set].writeInfos[slot].image.imageView = imageRes->getView();
+			else
+				mPerDeviceData[i].perSetData[set].writeInfos[slot].image.imageView = VK_NULL_HANDLE;
+		}
 
 		mSetsDirty[set] = true;
 	}
@@ -259,12 +279,17 @@ namespace BansheeEngine
 		GpuParamsCore::setLoadStoreTexture(set, slot, texture, surface);
 
 		VulkanTextureCore* vulkanTexture = static_cast<VulkanTextureCore*>(texture.get());
+		for (UINT32 i = 0; i < BS_MAX_DEVICES; i++)
+		{
+			if (mPerDeviceData[i].perSetData == nullptr)
+				continue;
 
-		VkImageView imageViews[BS_MAX_LINKED_DEVICES];
-		vulkanTexture->getViews(mDeviceMask, imageViews, surface);
-
-		for (UINT32 i = 0; i < mNumDevices; i++)
-			mPerDeviceData[i].perSetData[set].writeInfos[slot].image.imageView = imageViews[i];
+			VulkanImage* imageRes = vulkanTexture->getResource(i);
+			if (imageRes != nullptr)
+				mPerDeviceData[i].perSetData[set].writeInfos[slot].image.imageView = imageRes->getView(surface);
+			else
+				mPerDeviceData[i].perSetData[set].writeInfos[slot].image.imageView = VK_NULL_HANDLE;
+		}
 
 		mSetsDirty[set] = true;
 	}
@@ -274,12 +299,17 @@ namespace BansheeEngine
 		GpuParamsCore::setBuffer(set, slot, buffer);
 
 		VulkanGpuBufferCore* vulkanBuffer = static_cast<VulkanGpuBufferCore*>(buffer.get());
+		for (UINT32 i = 0; i < BS_MAX_DEVICES; i++)
+		{
+			if (mPerDeviceData[i].perSetData == nullptr)
+				continue;
 
-		VkBuffer buffers[BS_MAX_LINKED_DEVICES];
-		vulkanBuffer->getHandles(mDeviceMask, buffers);
-
-		for (UINT32 i = 0; i < mNumDevices; i++)
-			mPerDeviceData[i].perSetData[set].writeInfos[slot].buffer.buffer = buffers[i];
+			VulkanBuffer* bufferRes = vulkanBuffer->getResource(i);
+			if (bufferRes != nullptr)
+				mPerDeviceData[i].perSetData[set].writeInfos[slot].buffer.buffer = bufferRes->getHandle();
+			else
+				mPerDeviceData[i].perSetData[set].writeInfos[slot].buffer.buffer = VK_NULL_HANDLE;
+		}
 
 		mSetsDirty[set] = true;
 	}
@@ -288,13 +318,18 @@ namespace BansheeEngine
 	{
 		GpuParamsCore::setSamplerState(set, slot, sampler);
 
-		VulkanSamplerState* vulkanSampler = static_cast<VulkanSamplerState*>(sampler.get());
-
-		VkSampler samplers[BS_MAX_LINKED_DEVICES];
-		vulkanSampler->getHandles(mDeviceMask, samplers);
+		VulkanSamplerStateCore* vulkanSampler = static_cast<VulkanSamplerStateCore*>(sampler.get());
+		for(UINT32 i = 0; i < BS_MAX_DEVICES; i++)
+		{
+			if (mPerDeviceData[i].perSetData == nullptr)
+				continue;
 
-		for (UINT32 i = 0; i < mNumDevices; i++)
-			mPerDeviceData[i].perSetData[set].writeInfos[slot].image.sampler = samplers[i];
+			VulkanSampler* samplerRes = vulkanSampler->getResource(i);
+			if (samplerRes != nullptr)
+				mPerDeviceData[i].perSetData[set].writeInfos[slot].image.sampler = samplerRes->getHandle();
+			else
+				mPerDeviceData[i].perSetData[set].writeInfos[slot].image.sampler = VK_NULL_HANDLE;
+		}
 
 		mSetsDirty[set] = true;
 	}
@@ -308,12 +343,17 @@ namespace BansheeEngine
 			return;
 
 		VulkanTextureCore* vulkanTexture = static_cast<VulkanTextureCore*>(texture.get());
+		for (UINT32 i = 0; i < BS_MAX_DEVICES; i++)
+		{
+			if (mPerDeviceData[i].perSetData == nullptr)
+				continue;
 
-		VkImageView imageViews[BS_MAX_LINKED_DEVICES];
-		vulkanTexture->getViews(mDeviceMask, imageViews, surface);
-
-		for (UINT32 i = 0; i < mNumDevices; i++)
-			mPerDeviceData[i].perSetData[set].writeInfos[slot].image.imageView = imageViews[i];
+			VulkanImage* imageRes = vulkanTexture->getResource(i);
+			if (imageRes != nullptr)
+				mPerDeviceData[i].perSetData[set].writeInfos[slot].image.imageView = imageRes->getView(surface);
+			else
+				mPerDeviceData[i].perSetData[set].writeInfos[slot].image.imageView = VK_NULL_HANDLE;
+		}
 
 		mSetsDirty[set] = true;
 	}

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

@@ -185,7 +185,7 @@ namespace BansheeEngine
 		// Note: MULTIGPU - Detect multiple similar devices here if supporting multi-GPU
 		for (uint32_t i = 0; i < numDevices; i++)
 		{
-			if (mDevices[i]->getDeviceProperties().deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
+			if (mDevices[i]->isPrimary())
 			{
 				mPrimaryDevices.push_back(mDevices[i]);
 				break;

+ 11 - 0
Source/BansheeVulkanRenderAPI/Source/BsVulkanRenderStateManager.cpp

@@ -2,9 +2,20 @@
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 #include "BsVulkanRenderStateManager.h"
 #include "BsVulkanGpuPipelineState.h"
+#include "BsVulkanSamplerState.h"
 
 namespace BansheeEngine
 {
+	SPtr<SamplerStateCore> VulkanRenderStateCoreManager::createSamplerStateInternal(const SAMPLER_STATE_DESC& desc,
+		GpuDeviceFlags deviceMask) const
+	{
+		SPtr<VulkanSamplerStateCore> samplerState =
+			bs_shared_ptr<VulkanSamplerStateCore>(new (bs_alloc<VulkanSamplerStateCore>()) VulkanSamplerStateCore(desc, deviceMask));
+		samplerState->_setThisPtr(samplerState);
+
+		return samplerState;
+	}
+
 	SPtr<GpuPipelineStateCore> VulkanRenderStateCoreManager::_createPipelineState(const PIPELINE_STATE_CORE_DESC& desc,
 		GpuDeviceFlags deviceMask) const
 	{

+ 43 - 8
Source/BansheeVulkanRenderAPI/Source/BsVulkanSamplerState.cpp

@@ -3,6 +3,7 @@
 #include "BsVulkanSamplerState.h"
 #include "BsVulkanDevice.h"
 #include "BsVulkanUtility.h"
+#include "BsVulkanRenderAPI.h"
 
 namespace BansheeEngine
 {
@@ -15,14 +16,19 @@ namespace BansheeEngine
 		vkDestroySampler(mOwner->getDevice().getLogical(), mSampler, gVulkanAllocator);
 	}
 
-	VulkanSamplerStateCore::VulkanSamplerStateCore(const SAMPLER_STATE_DESC& desc)
-		:SamplerStateCore(desc), mSampler(nullptr)
+	VulkanSamplerStateCore::VulkanSamplerStateCore(const SAMPLER_STATE_DESC& desc, GpuDeviceFlags deviceMask)
+		:SamplerStateCore(desc, deviceMask), mSamplers(), mDeviceMask(deviceMask)
 	{ }
 
 	VulkanSamplerStateCore::~VulkanSamplerStateCore()
 	{
-		if(mSampler != nullptr)
-			mSampler->destroy();
+		for(UINT32 i = 0; i < BS_MAX_DEVICES; i++)
+		{
+			if (mSamplers[i] == nullptr)
+				return;
+
+			mSamplers[i]->destroy();
+		}
 	}
 
 	void VulkanSamplerStateCore::createInternal()
@@ -56,10 +62,39 @@ namespace BansheeEngine
 		samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
 		samplerInfo.unnormalizedCoordinates = false;
 
-		// TODO - Create state per device
+		VulkanRenderAPI& rapi = static_cast<VulkanRenderAPI&>(RenderAPICore::instance());
+		VulkanDevice* devices[BS_MAX_DEVICES];
+		VulkanUtility::getDevices(rapi, mDeviceMask, devices);
+
+		// Allocate samplers per-device
+		for (UINT32 i = 0; i < BS_MAX_DEVICES; i++)
+		{
+			if (devices[i] == nullptr)
+				break;
+
+			VkSampler sampler;
+			VkResult result = vkCreateSampler(devices[i]->getLogical(), &samplerInfo, gVulkanAllocator, &sampler);
+			assert(result == VK_SUCCESS);
+
+			mSamplers[i] = devices[i]->getResourceManager().create<VulkanSampler>(sampler);
+		}
+	}
+
+	void VulkanSamplerStateCore::getHandles(GpuDeviceFlags mask, VkSampler(&handles)[BS_MAX_LINKED_DEVICES], 
+		UINT32& numHandles)
+	{
+		numHandles = 0;
+
+		for (UINT32 i = 0; i < BS_MAX_DEVICES; i++)
+		{
+			UINT32 deviceMask = 1 << i;
+			if ((mask & deviceMask) == 0 || mSamplers[i] == nullptr)
+				continue;
+
+			handles[numHandles++] = mSamplers[i]->getHandle();
 
-		VkSampler sampler;
-		VkResult result = vkCreateSampler(mOwner->getDevice().getLogical(), &samplerInfo, gVulkanAllocator, &sampler);
-		assert(result == VK_SUCCESS);
+			if (numHandles >= BS_MAX_LINKED_DEVICES)
+				break;
+		}
 	}
 }

+ 14 - 23
Source/BansheeVulkanRenderAPI/Source/BsVulkanUtility.cpp

@@ -2,6 +2,7 @@
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 #include "BsVulkanUtility.h"
 #include "BsVulkanRenderAPI.h"
+#include "BsVulkanDevice.h"
 #include "BsException.h"
 
 namespace BansheeEngine
@@ -435,35 +436,25 @@ namespace BansheeEngine
 		return VK_SAMPLER_MIPMAP_MODE_LINEAR;
 	}
 
-	void VulkanUtility::getDevices(const VulkanRenderAPI& rapi, GpuDeviceFlags flags, VulkanDevice*(&devices)[BS_MAX_LINKED_DEVICES])
+	void VulkanUtility::getDevices(const VulkanRenderAPI& rapi, GpuDeviceFlags flags, VulkanDevice*(&devices)[BS_MAX_DEVICES])
 	{
-		if(flags == GDF_DEFAULT)
-		{
-			const Vector<SPtr<VulkanDevice>>& primaryDevices = rapi._getPrimaryDevices();
-			UINT32 count = std::min(BS_MAX_LINKED_DEVICES, (UINT32)primaryDevices.size());
+		UINT32 numDevices = std::min(BS_MAX_DEVICES, rapi._getNumDevices());
 
-			for (UINT32 i = 0; i < count; i++)
-				devices[i] = primaryDevices[i].get();
+		for (UINT32 i = 0; i < numDevices; i++)
+		{
+			VulkanDevice* device = rapi._getDevice(i).get();
 
-			for (UINT32 i = count; i < BS_MAX_LINKED_DEVICES; i++)
+			if (isDeviceIdxSet(rapi, i, flags))
+				devices[i] = device;
+			else
 				devices[i] = nullptr;
 		}
-		else
-		{
-			UINT32 numDevices = rapi._getNumDevices();
-
-			UINT32 deviceIdx = 0;
-			for(UINT32 i = 0; i < numDevices; i++)
-			{
-				if (flags & (1 << i))
-					devices[deviceIdx++] = rapi._getDevice(i).get();
+	}
 
-				if (deviceIdx >= BS_MAX_LINKED_DEVICES)
-					break;
-			}
+	bool VulkanUtility::isDeviceIdxSet(const VulkanRenderAPI& rapi, UINT32 idx, GpuDeviceFlags flags)
+	{
+		VulkanDevice* device = rapi._getDevice(idx).get();
 
-			for (UINT32 i = deviceIdx; i < BS_MAX_LINKED_DEVICES; i++)
-				devices[i] = nullptr;
-		}
+		return ((flags & (1 << idx)) != 0 || (flags == GDF_DEFAULT && device->isPrimary()));
 	}
 }