Переглянути джерело

Refactoring GpuParams so parameter meta-data is stored on GpuPipelineState rather than on GpuParams

BearishSun 9 роки тому
батько
коміт
0a78764779

+ 1 - 0
Source/BansheeCore/Include/BsCorePrerequisites.h

@@ -372,6 +372,7 @@ namespace BansheeEngine
 	class AudioClipImportOptions;
 	class AnimationClip;
 	class CCamera;
+	class GpuPipelineParamInfo;
 	template <class T> class TAnimationCurve;
 	struct AnimationCurves;
 	class Skeleton;

+ 11 - 37
Source/BansheeCore/Include/BsGpuParams.h

@@ -36,17 +36,6 @@ namespace BansheeEngine
 	template<> struct TGpuDataParamInfo < Matrix4x3 > { enum { TypeId = GPDT_MATRIX_4X3 }; };
 	template<> struct TGpuDataParamInfo < Color > { enum { TypeId = GPDT_COLOR }; };
 
-	/** Helper structure used for initializing GpuParams. */
-	struct GPU_PARAMS_DESC
-	{
-		SPtr<GpuParamDesc> fragmentParams;
-		SPtr<GpuParamDesc> vertexParams;
-		SPtr<GpuParamDesc> geometryParams;
-		SPtr<GpuParamDesc> hullParams;
-		SPtr<GpuParamDesc> domainParams;
-		SPtr<GpuParamDesc> computeParams;
-	};
-
 	/** Contains functionality common for both sim and core thread version of GpuParams. */
 	class BS_CORE_EXPORT GpuParamsBase
 	{
@@ -59,7 +48,7 @@ namespace BansheeEngine
 		GpuParamsBase& operator=(const GpuParamsBase& rhs) = delete;
 
 		/** Returns a description of all stored parameters. */
-		SPtr<GpuParamDesc> getParamDesc(GpuProgramType type) const { return mParamDescs[(int)type]; }
+		SPtr<GpuParamDesc> getParamDesc(GpuProgramType type) const;
 
 		/**
 		 * Returns the size of a data parameter with the specified name, in bytes. Returns 0 if such parameter doesn't exist.
@@ -94,12 +83,12 @@ namespace BansheeEngine
 		virtual void _markResourcesDirty() { }
 
 	protected:
-		GpuParamsBase(const GPU_PARAMS_DESC& desc);
+		GpuParamsBase(const SPtr<GpuPipelineParamInfo>& paramInfo);
 
 		/**	Gets a descriptor for a data parameter with the specified name. */
 		GpuParamDataDesc* getParamDesc(GpuProgramType type, const String& name) const;
 
-		SPtr<GpuParamDesc> mParamDescs[6];
+		const SPtr<GpuPipelineParamInfo>& mParamInfo;
 	};
 
 	template<bool Core> struct TGpuParamsTypes { };
@@ -217,27 +206,11 @@ namespace BansheeEngine
 		virtual void setLoadStoreSurface(UINT32 set, UINT32 slot, const TextureSurface& surface);
 
 	protected:
-		/** Type of elements stored in this object. */
-		enum class ElementType
-		{
-			ParamBlock, Texture, LoadStoreTexture, Buffer, SamplerState, Count
-		};
-
-		TGpuParams(const GPU_PARAMS_DESC& desc);
+		TGpuParams(const SPtr<GpuPipelineParamInfo>& paramInfo);
 
 		/** @copydoc CoreObject::getThisPtr */
 		virtual SPtr<GpuParamsType> _getThisPtr() const = 0;
 
-		/** 
-		 * Converts a set/slot combination into a global slot. If the set or slot is out of valid range, the method logs
-		 * an error and returns -1. Only performs range checking in debug mode.
-		 */
-		UINT32 getGlobalSlot(ElementType type, UINT32 set, UINT32 slot) const;
-
-		UINT32 mNumSets[(int)ElementType::Count];
-		UINT32 mNumElements[(int)ElementType::Count];
-		UINT32* mOffsets[(int)ElementType::Count];
-
 		ParamsBufferType* mParamBlockBuffers = nullptr;
 		TextureType* mTextures = nullptr;
 		TextureType* mLoadStoreTextures = nullptr;
@@ -266,13 +239,14 @@ namespace BansheeEngine
 		 * @copydoc GpuParams::create 
 		 * @param[in]	deviceMask		Mask that determines on which GPU devices should the buffer be created on.
 		 */
-		static SPtr<GpuParamsCore> create(const GPU_PARAMS_DESC& desc, GpuDeviceFlags deviceMask = GDF_DEFAULT);
+		static SPtr<GpuParamsCore> create(const SPtr<GpuPipelineParamInfo>& paramInfo,
+										  GpuDeviceFlags deviceMask = GDF_DEFAULT);
 
 	protected:
 		friend class GpuParams;
 		friend class HardwareBufferCoreManager;
 
-		GpuParamsCore(const GPU_PARAMS_DESC& desc, GpuDeviceFlags deviceMask);
+		GpuParamsCore(const SPtr<GpuPipelineParamInfo>& paramInfo, GpuDeviceFlags deviceMask);
 
 		/** @copydoc CoreObject::getThisPtr */
 		SPtr<GpuParamsCore> _getThisPtr() const override;
@@ -302,11 +276,11 @@ namespace BansheeEngine
 		SPtr<GpuParamsCore> getCore() const;
 
 		/**
-		 * Creates new GpuParams object using the specified parameter descriptions.
+		 * Creates new GpuParams object using the specified parameter description.
 		 *
-		 * @param[in]	desc	Object containing parameter descriptions for all relevant GPU program stages.
+		 * @param[in]	paramInfo	Object containing parameter descriptions for all relevant GPU program stages.
 		 */
-		static SPtr<GpuParams> create(const GPU_PARAMS_DESC& desc);
+		static SPtr<GpuParams> create(const SPtr<GpuPipelineParamInfo>& paramInfo);
 
 		/** Contains a lookup table for sizes of all data parameters. Sizes are in bytes. */
 		const static GpuDataParamInfos PARAM_SIZES;
@@ -325,7 +299,7 @@ namespace BansheeEngine
 	protected:
 		friend class HardwareBufferManager;
 
-		GpuParams(const GPU_PARAMS_DESC& desc);
+		GpuParams(const SPtr<GpuPipelineParamInfo>& paramInfo);
 
 		/** @copydoc CoreObject::getThisPtr */
 		SPtr<GpuParams> _getThisPtr() const override;

+ 2 - 0
Source/BansheeCore/Include/BsGpuParamsSet.h

@@ -5,6 +5,7 @@
 #include "BsCorePrerequisites.h"
 #include "BsMaterial.h"
 #include "BsShader.h"
+#include "BsPass.h"
 
 namespace BansheeEngine
 {
@@ -31,6 +32,7 @@ namespace BansheeEngine
 		typedef typename TGpuParamTextureType<Core>::Type TextureType;
 		typedef typename TGpuBufferType<Core>::Type BufferType;
 		typedef typename TGpuParamSamplerStateType<Core>::Type SamplerStateType;
+		typedef typename TPassTypes<Core>::GpuPipelineStateType GpuPipelineStateType;
 
 		/** Information about a parameter block buffer. */
 		struct BlockInfo

+ 73 - 0
Source/BansheeCore/Include/BsGpuPipelineState.h

@@ -107,11 +107,15 @@ namespace BansheeEngine
 		const GpuProgramType& getHullProgram() const { return mData.hullProgram; }
 		const GpuProgramType& getDomainProgram() const { return mData.domainProgram; }
 
+		/** Returns an object containing meta-data for parameters of all GPU programs used in this pipeline state. */
+		const SPtr<GpuPipelineParamInfo>& getParamInfo() const { return mParamInfo; }
+
 	protected:
 		TGpuPipelineState();
 		TGpuPipelineState(const StateDescType& desc);
 
 		StateDescType mData;
+		SPtr<GpuPipelineParamInfo> mParamInfo;
     };
 
 	/** @} */
@@ -168,5 +172,74 @@ namespace BansheeEngine
 			GpuDeviceFlags deviceMask = GDF_DEFAULT);
 	};
 
+	/** Helper structure used for initializing GpuPipelineParamInfo. */
+	struct GPU_PIPELINE_PARAMS_DESC
+	{
+		SPtr<GpuParamDesc> fragmentParams;
+		SPtr<GpuParamDesc> vertexParams;
+		SPtr<GpuParamDesc> geometryParams;
+		SPtr<GpuParamDesc> hullParams;
+		SPtr<GpuParamDesc> domainParams;
+		SPtr<GpuParamDesc> computeParams;
+	};
+
+	/** Holds meta-data about a set of GPU parameters used by a single pipeline state. */
+	class BS_CORE_EXPORT GpuPipelineParamInfo
+	{
+	public:
+		/** Types of GPU parameters. */
+		enum class ParamType
+		{
+			ParamBlock, Texture, LoadStoreTexture, Buffer, SamplerState, Count
+		};
+
+		/** Constructs the object using the provided GPU parameter descriptors. */
+		GpuPipelineParamInfo(const GPU_PIPELINE_PARAMS_DESC& desc);
+		~GpuPipelineParamInfo();
+
+		/** Gets the total number of sets, across all parameter types. */
+		UINT32 getNumSets() const { return mTotalNumSets; }
+
+		/** Returns the number of sets for the specified parameter type. */
+		UINT32 getNumSets(ParamType type) { return mNumSets[(int)type]; }
+
+		/** Returns the number of elements in all sets for the specified parameter type. */
+		UINT32 getNumElements(ParamType type) { return mNumElements[(int)type]; }
+
+		/** 
+		 * Assuming all elements for a specific parameter type are laid out sequentially and grouped by their sets, 
+		 * returns the sequential index to the first parameter of the provided set.
+		 */
+		UINT32 getSetOffset(ParamType type, UINT32 set) { return mOffsets[(int)type][set]; }
+
+		/** 
+		 * Converts a set/slot combination into a sequential index that maps to the parameter in that parameter type's 
+		 * array. 
+		 * 
+		 * If the set or slot is out of valid range, the method logs an error and returns -1. Only performs range checking
+		 * in debug mode.
+		 */
+		UINT32 getSequentialSlot(ParamType type, UINT32 set, UINT32 slot) const;
+
+		/** Returns descriptions of individual parameters for the specified GPU program type. */
+		const SPtr<GpuParamDesc>& getParamDesc(GpuProgramType type) const { return mParamDescs[(int)type]; }
+
+		/** Constructs the object using the provided GPU parameter descriptors. */
+		static SPtr<GpuPipelineParamInfo> create(const GPU_PIPELINE_PARAMS_DESC& desc)
+		{
+			return bs_shared_ptr_new<GpuPipelineParamInfo>(desc);
+		}
+
+	private:
+		std::array<SPtr<GpuParamDesc>, 6> mParamDescs;
+
+		UINT32 mTotalNumSets;
+		UINT32 mNumSets[(int)ParamType::Count];
+		UINT32 mNumElements[(int)ParamType::Count];
+		UINT32* mOffsets[(int)ParamType::Count];
+
+		UINT8* mData;
+	};
+
 	/** @} */
 }

+ 6 - 5
Source/BansheeCore/Include/BsHardwareBufferManager.h

@@ -70,11 +70,11 @@ namespace BansheeEngine
 		SPtr<VertexDeclaration> createVertexDeclaration(const SPtr<VertexDataDesc>& desc);
 
 		/** 
-		 * Creates a new GpuParams object from the provided set of GPU parameter descriptors.
+		 * Creates a new GpuParams object.
 		 *  
-		 * @param[in]	desc	Description of the object to create.
+		 * @param[in]	paramInfo	Object containing parameter descriptions for all relevant GPU program stages.
 		 */
-		SPtr<GpuParams> createGpuParams(const GPU_PARAMS_DESC& desc);
+		SPtr<GpuParams> createGpuParams(const SPtr<GpuPipelineParamInfo>& paramInfo);
 	};
 
 	/**
@@ -132,7 +132,8 @@ namespace BansheeEngine
 		 * @copydoc HardwareBufferManager::createGpuParams 
 		 * @param[in]	deviceMask		Mask that determines on which GPU devices should the object be created on.
 		 */
-		SPtr<GpuParamsCore> createGpuParams(const GPU_PARAMS_DESC& desc, GpuDeviceFlags deviceMask = GDF_DEFAULT);
+		SPtr<GpuParamsCore> createGpuParams(const SPtr<GpuPipelineParamInfo>& paramInfo,
+											GpuDeviceFlags deviceMask = GDF_DEFAULT);
 
 	protected:
 		friend class IndexBuffer;
@@ -165,7 +166,7 @@ namespace BansheeEngine
 			GpuDeviceFlags deviceMask = GDF_DEFAULT);
 
 		/** @copydoc createGpuParams */
-		virtual SPtr<GpuParamsCore> createGpuParamsInternal(const GPU_PARAMS_DESC& desc, 
+		virtual SPtr<GpuParamsCore> createGpuParamsInternal(const SPtr<GpuPipelineParamInfo>& paramInfo,
 			GpuDeviceFlags deviceMask = GDF_DEFAULT);
 	};
 

+ 7 - 5
Source/BansheeCore/Include/BsParamBlocks.h

@@ -5,6 +5,7 @@
 #include "BsCorePrerequisites.h"
 #include "BsGpuParamDesc.h"
 #include "BsGpuParams.h"
+#include "BsGpuPipelineState.h"
 #include "BsRenderAPI.h"
 #include "BsGpuParamBlockBuffer.h"
 
@@ -14,9 +15,9 @@ namespace BansheeEngine
 	 *  @{
 	 */
 
-/** 
+/**
  * Starts a new custom parameter block. Custom parameter blocks allow you to create C++ structures that map directly
- * to GPU program buffers (for example uniform buffer in OpenGL or constant buffer in DX). Must be followed by 
+ * to GPU program buffers (for example uniform buffer in OpenGL or constant buffer in DX). Must be followed by
  * BS_PARAM_BLOCK_END.
  */
 #define BS_PARAM_BLOCK_BEGIN(Name)																							\
@@ -34,9 +35,10 @@ namespace BansheeEngine
 			for (auto& param : params)																						\
 				paramsDesc->params[param.name] = param;																		\
 																															\
-			GPU_PARAMS_DESC desc;																							\
-			desc.vertexParams = paramsDesc;																					\
-			mParams = GpuParamsCore::create(desc);																			\
+			GPU_PIPELINE_PARAMS_DESC pipelineParamDesc;																		\
+			pipelineParamDesc.vertexParams = paramsDesc;																	\
+			SPtr<GpuPipelineParamInfo> paramInfo = GpuPipelineParamInfo::create(pipelineParamDesc);							\
+			mParams = GpuParamsCore::create(paramInfo);																		\
 																															\
 			mBuffer = GpuParamBlockBufferCore::create(mBlockDesc.blockSize * sizeof(UINT32));								\
 			mParams->setParamBlockBuffer(GPT_VERTEX_PROGRAM, #Name, mBuffer);												\

+ 123 - 259
Source/BansheeCore/Source/BsGpuParams.cpp

@@ -3,6 +3,7 @@
 #include "BsGpuParams.h"
 #include "BsGpuParamDesc.h"
 #include "BsGpuParamBlockBuffer.h"
+#include "BsGpuPipelineState.h"
 #include "BsVector2.h"
 #include "BsTexture.h"
 #include "BsGpuBuffer.h"
@@ -16,20 +17,19 @@
 
 namespace BansheeEngine
 {
-	GpuParamsBase::GpuParamsBase(const GPU_PARAMS_DESC& desc)
-	{
-		mParamDescs[GPT_FRAGMENT_PROGRAM] = desc.fragmentParams;
-		mParamDescs[GPT_VERTEX_PROGRAM] = desc.vertexParams;
-		mParamDescs[GPT_GEOMETRY_PROGRAM] = desc.geometryParams;
-		mParamDescs[GPT_HULL_PROGRAM] = desc.hullParams;
-		mParamDescs[GPT_DOMAIN_PROGRAM] = desc.domainParams;
-		mParamDescs[GPT_COMPUTE_PROGRAM] = desc.computeParams;
-	}
+	GpuParamsBase::GpuParamsBase(const SPtr<GpuPipelineParamInfo>& paramInfo)
+		:mParamInfo(paramInfo)
+	{ }
 
 	GpuParamsBase::~GpuParamsBase()
 	{ }
 
-UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name) const
+	SPtr<GpuParamDesc> GpuParamsBase::getParamDesc(GpuProgramType type) const
+	{
+		return mParamInfo->getParamDesc(type);
+	}
+
+	UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name) const
 	{
 		GpuParamDataDesc* desc = getParamDesc(type, name);
 		if(desc != nullptr)
@@ -45,7 +45,7 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 
 	bool GpuParamsBase::hasTexture(GpuProgramType type, const String& name) const
 	{
-		const SPtr<GpuParamDesc>& paramDesc = mParamDescs[(int)type];
+		const SPtr<GpuParamDesc>& paramDesc = mParamInfo->getParamDesc(type);
 		if (paramDesc == nullptr)
 			return false;
 
@@ -58,7 +58,7 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 
 	bool GpuParamsBase::hasBuffer(GpuProgramType type, const String& name) const
 	{
-		const SPtr<GpuParamDesc>& paramDesc = mParamDescs[(int)type];
+		const SPtr<GpuParamDesc>& paramDesc = mParamInfo->getParamDesc(type);
 		if (paramDesc == nullptr)
 			return false;
 
@@ -71,7 +71,7 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 
 	bool GpuParamsBase::hasLoadStoreTexture(GpuProgramType type, const String& name) const
 	{
-		const SPtr<GpuParamDesc>& paramDesc = mParamDescs[(int)type];
+		const SPtr<GpuParamDesc>& paramDesc = mParamInfo->getParamDesc(type);
 		if (paramDesc == nullptr)
 			return false;
 
@@ -84,7 +84,7 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 
 	bool GpuParamsBase::hasSamplerState(GpuProgramType type, const String& name) const
 	{
-		const SPtr<GpuParamDesc>& paramDesc = mParamDescs[(int)type];
+		const SPtr<GpuParamDesc>& paramDesc = mParamInfo->getParamDesc(type);
 		if (paramDesc == nullptr)
 			return false;
 
@@ -97,7 +97,7 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 
 	bool GpuParamsBase::hasParamBlock(GpuProgramType type, const String& name) const
 	{
-		const SPtr<GpuParamDesc>& paramDesc = mParamDescs[(int)type];
+		const SPtr<GpuParamDesc>& paramDesc = mParamInfo->getParamDesc(type);
 		if (paramDesc == nullptr)
 			return false;
 
@@ -110,7 +110,7 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 
 	GpuParamDataDesc* GpuParamsBase::getParamDesc(GpuProgramType type, const String& name) const
 	{
-		const SPtr<GpuParamDesc>& paramDesc = mParamDescs[(int)type];
+		const SPtr<GpuParamDesc>& paramDesc = mParamInfo->getParamDesc(type);
 		if (paramDesc == nullptr)
 			return nullptr;
 
@@ -123,7 +123,7 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 
 	GpuParamBlockDesc* GpuParamsBase::getParamBlockDesc(GpuProgramType type, const String& name) const
 	{
-		const SPtr<GpuParamDesc>& paramDesc = mParamDescs[(int)type];
+		const SPtr<GpuParamDesc>& paramDesc = mParamInfo->getParamDesc(type);
 		if (paramDesc == nullptr)
 			return nullptr;
 
@@ -135,236 +135,93 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 	}
 
 	template<bool Core>
-	TGpuParams<Core>::TGpuParams(const GPU_PARAMS_DESC& desc)
-		: GpuParamsBase(desc)
-	{
-		for(UINT32 i = 0; i < (UINT32)ElementType::Count; i++)
-		{
-			mNumSets[i] = 0;
-			mNumElements[i] = 0;
-			mOffsets[i] = nullptr;
-		}
-
-		UINT32 numParamDescs = sizeof(mParamDescs) / sizeof(mParamDescs[0]);
-		for (UINT32 i = 0; i < numParamDescs; i++)
-		{
-			const SPtr<GpuParamDesc>& paramDesc = mParamDescs[i];
-			if (paramDesc == nullptr)
-				continue;
-
-			for (auto& paramBlock : paramDesc->paramBlocks)
-			{
-				if ((paramBlock.second.set + 1) > mNumSets[(int)ElementType::ParamBlock])
-					mNumSets[(int)ElementType::ParamBlock] = paramBlock.second.set + 1;
-			}
-
-			for (auto& texture : paramDesc->textures)
-			{
-				if ((texture.second.set + 1) > mNumSets[(int)ElementType::Texture])
-					mNumSets[(int)ElementType::Texture] = texture.second.set + 1;
-			}
-
-			for (auto& texture : paramDesc->loadStoreTextures)
-			{
-				if ((texture.second.set + 1) > mNumSets[(int)ElementType::LoadStoreTexture])
-					mNumSets[(int)ElementType::LoadStoreTexture] = texture.second.set + 1;
-			}
-
-			for (auto& buffer : paramDesc->buffers)
-			{
-				if ((buffer.second.set + 1) > mNumSets[(int)ElementType::Buffer])
-					mNumSets[(int)ElementType::Buffer] = buffer.second.set + 1;
-			}
-
-			for (auto& sampler : paramDesc->samplers)
-			{
-				if ((sampler.second.set + 1) > mNumSets[(int)ElementType::SamplerState])
-					mNumSets[(int)ElementType::SamplerState] = sampler.second.set + 1;
-			}
-		}
-
-		UINT32 totalNumSets = 0;
-		for (UINT32 i = 0; i < (UINT32)ElementType::Count; i++)
-			totalNumSets += mNumSets[i];
-
-		UINT32* slotsPerSetData = bs_stack_alloc<UINT32>(totalNumSets);
-		memset(slotsPerSetData, 0, sizeof(UINT32) * totalNumSets);
-
-		UINT32* slotsPerSet[(UINT32)ElementType::Count];
-		for (UINT32 i = 0; i < (UINT32)ElementType::Count; i++)
-		{
-			if (i == 0)
-				slotsPerSet[i] = slotsPerSetData;
-			else
-				slotsPerSet[i] = slotsPerSet[i - 1] + mNumSets[i - 1];
-		}
-
-		for (UINT32 i = 0; i < numParamDescs; i++)
-		{
-			const SPtr<GpuParamDesc>& paramDesc = mParamDescs[i];
-			if (paramDesc == nullptr)
-				continue;
-			
-			for (auto& paramBlock : paramDesc->paramBlocks)
-			{
-				UINT32* slots = slotsPerSet[(int)ElementType::ParamBlock];
-				slots[paramBlock.second.set] = std::max(slots[paramBlock.second.set], paramBlock.second.slot + 1);
-			}
-
-			for (auto& texture : paramDesc->textures)
-			{
-				UINT32* slots = slotsPerSet[(int)ElementType::Texture];
-				slots[texture.second.set] = std::max(slots[texture.second.set], texture.second.slot + 1);
-			}
-
-			for (auto& texture : paramDesc->loadStoreTextures)
-			{
-				UINT32* slots = slotsPerSet[(int)ElementType::LoadStoreTexture];
-				slots[texture.second.set] = std::max(slots[texture.second.set], texture.second.slot + 1);
-			}
-
-			for (auto& buffer : paramDesc->buffers)
-			{
-				UINT32* slots = slotsPerSet[(int)ElementType::Buffer];
-				slots[buffer.second.set] = std::max(slots[buffer.second.set], buffer.second.slot + 1);
-			}
-
-			for (auto& sampler : paramDesc->samplers)
-			{
-				UINT32* slots = slotsPerSet[(int)ElementType::SamplerState];
-				slots[sampler.second.set] = std::max(slots[sampler.second.set], sampler.second.slot + 1);
-			}
-		}
-
-		for (UINT32 i = 0; i < (UINT32)ElementType::Count; i++)
-		{
-			for (UINT32 j = 0; j < mNumSets[i]; j++)
-				mNumElements[i] += slotsPerSet[i][j];
-		}
-
-		UINT32 paramBlocksSize = sizeof(ParamsBufferType) * mNumElements[(int)ElementType::ParamBlock];
-		UINT32 texturesSize = sizeof(TextureType) * mNumElements[(int)ElementType::Texture];
-		UINT32 loadStoreTexturesSize = sizeof(TextureType) * mNumElements[(int)ElementType::LoadStoreTexture];
-		UINT32 loadStoreSurfacesSize = sizeof(TextureSurface) * mNumElements[(int)ElementType::LoadStoreTexture];
-		UINT32 buffersSize = sizeof(BufferType) * mNumElements[(int)ElementType::Buffer];
-		UINT32 samplerStatesSize = sizeof(SamplerType) * mNumElements[(int)ElementType::SamplerState];
-		UINT32 setOffsetsSize = sizeof(UINT32) * totalNumSets;
+	TGpuParams<Core>::TGpuParams(const SPtr<GpuPipelineParamInfo>& paramInfo)
+		: GpuParamsBase(paramInfo)
+	{
+		UINT32 numParamBlocks = mParamInfo->getNumElements(GpuPipelineParamInfo::ParamType::ParamBlock);
+		UINT32 numTextures = mParamInfo->getNumElements(GpuPipelineParamInfo::ParamType::Texture);
+		UINT32 numStorageTextures = mParamInfo->getNumElements(GpuPipelineParamInfo::ParamType::LoadStoreTexture);
+		UINT32 numBuffers = mParamInfo->getNumElements(GpuPipelineParamInfo::ParamType::Buffer);
+		UINT32 numSamplers = mParamInfo->getNumElements(GpuPipelineParamInfo::ParamType::SamplerState);
+		
+		UINT32 paramBlocksSize = sizeof(ParamsBufferType) * numParamBlocks;
+		UINT32 texturesSize = sizeof(TextureType) * numTextures;
+		UINT32 loadStoreTexturesSize = sizeof(TextureType) * numStorageTextures;
+		UINT32 loadStoreSurfacesSize = sizeof(TextureSurface) * numStorageTextures;
+		UINT32 buffersSize = sizeof(BufferType) * numBuffers;
+		UINT32 samplerStatesSize = sizeof(SamplerType) * numSamplers;
 
 		UINT32 totalSize = paramBlocksSize + texturesSize + loadStoreTexturesSize + loadStoreSurfacesSize +
-			buffersSize + samplerStatesSize + setOffsetsSize;
+			buffersSize + samplerStatesSize;
 
 		UINT8* data = (UINT8*)bs_alloc(totalSize);
 		mParamBlockBuffers = (ParamsBufferType*)data;
-		for (UINT32 i = 0; i < mNumElements[(int)ElementType::ParamBlock]; i++)
+		for (UINT32 i = 0; i < numParamBlocks; i++)
 			new (&mParamBlockBuffers[i]) ParamsBufferType();
 
-		data += sizeof(ParamsBufferType) * mNumElements[(int)ElementType::ParamBlock];
+		data += sizeof(ParamsBufferType) * numParamBlocks;
 		mTextures = (TextureType*)data;
-		for (UINT32 i = 0; i < mNumElements[(int)ElementType::Texture]; i++)
+		for (UINT32 i = 0; i < numTextures; i++)
 			new (&mTextures[i]) TextureType();
 
-		data += sizeof(TextureType) * mNumElements[(int)ElementType::Texture];
+		data += sizeof(TextureType) * numTextures;
 		mLoadStoreTextures = (TextureType*)data;
-		for (UINT32 i = 0; i < mNumElements[(int)ElementType::LoadStoreTexture]; i++)
+		for (UINT32 i = 0; i < numStorageTextures; i++)
 			new (&mLoadStoreTextures[i]) TextureType();
 
-		data += sizeof(TextureType) * mNumElements[(int)ElementType::LoadStoreTexture];
+		data += sizeof(TextureType) * numStorageTextures;
 		mLoadStoreSurfaces = (TextureSurface*)data;
-		for (UINT32 i = 0; i < mNumElements[(int)ElementType::LoadStoreTexture]; i++)
+		for (UINT32 i = 0; i < numStorageTextures; i++)
 			new (&mLoadStoreSurfaces[i]) TextureSurface();
 
-		data += sizeof(TextureSurface) * mNumElements[(int)ElementType::LoadStoreTexture];
+		data += sizeof(TextureSurface) * numStorageTextures;
 		mBuffers = (BufferType*)data;
-		for (UINT32 i = 0; i < mNumElements[(int)ElementType::Buffer]; i++)
+		for (UINT32 i = 0; i < numBuffers; i++)
 			new (&mBuffers[i]) BufferType();
 
-		data += sizeof(BufferType) * mNumElements[(int)ElementType::Buffer];
+		data += sizeof(BufferType) * numBuffers;
 		mSamplerStates = (SamplerType*)data;
-		for (UINT32 i = 0; i < mNumElements[(int)ElementType::SamplerState]; i++)
+		for (UINT32 i = 0; i < numSamplers; i++)
 			new (&mSamplerStates[i]) SamplerType();
 
-		data += sizeof(SamplerType) * mNumElements[(int)ElementType::SamplerState];
-
-		for (UINT32 i = 0; i < (UINT32)ElementType::Count; i++)
-		{
-			mOffsets[i] = (UINT32*)data;
-			data += sizeof(UINT32) * mNumSets[i];
-
-			if (mNumSets[i] == 0)
-				continue;
-
-			mOffsets[i][0] = 0;
-
-			for (UINT32 j = 0; j < mNumSets[i] - 1; j++)
-				mOffsets[i][j + 1] = mOffsets[i][j] + slotsPerSet[i][j];
-		}
-
-		bs_stack_free(slotsPerSetData);
+		data += sizeof(SamplerType) * numSamplers;
 	}
 
 	template<bool Core>
 	TGpuParams<Core>::~TGpuParams()
 	{
-		for (UINT32 i = 0; i < mNumElements[(int)ElementType::ParamBlock]; i++)
+		UINT32 numParamBlocks = mParamInfo->getNumElements(GpuPipelineParamInfo::ParamType::ParamBlock);
+		UINT32 numTextures = mParamInfo->getNumElements(GpuPipelineParamInfo::ParamType::Texture);
+		UINT32 numStorageTextures = mParamInfo->getNumElements(GpuPipelineParamInfo::ParamType::LoadStoreTexture);
+		UINT32 numBuffers = mParamInfo->getNumElements(GpuPipelineParamInfo::ParamType::Buffer);
+		UINT32 numSamplers = mParamInfo->getNumElements(GpuPipelineParamInfo::ParamType::SamplerState);
+
+		for (UINT32 i = 0; i < numParamBlocks; i++)
 			mParamBlockBuffers[i].~ParamsBufferType();
 
-		for (UINT32 i = 0; i <  mNumElements[(int)ElementType::Texture]; i++)
+		for (UINT32 i = 0; i <  numTextures; i++)
 			mTextures[i].~TextureType();
 
-		for (UINT32 i = 0; i <  mNumElements[(int)ElementType::LoadStoreTexture]; i++)
+		for (UINT32 i = 0; i <  numStorageTextures; i++)
 		{
 			mLoadStoreTextures[i].~TextureType();
 			mLoadStoreSurfaces[i].~TextureSurface();
 		}
 
-		for (UINT32 i = 0; i < mNumElements[(int)ElementType::Buffer]; i++)
+		for (UINT32 i = 0; i < numBuffers; i++)
 			mBuffers[i].~BufferType();
 
-		for (UINT32 i = 0; i < mNumElements[(int)ElementType::SamplerState]; i++)
+		for (UINT32 i = 0; i < numSamplers; i++)
 			mSamplerStates[i].~SamplerType();
 
 		// Everything is allocated in a single block, so it's enough to free the first element
 		bs_free(mParamBlockBuffers);
 	}
 
-	template<bool Core>
-	UINT32 TGpuParams<Core>::getGlobalSlot(ElementType type, UINT32 set, UINT32 slot) const
-	{
-#if BS_DEBUG_MODE
-		if (set >= mNumSets[(int)type])
-		{
-			LOGERR("Set index out of range: Valid range: 0 .. " +
-				toString(mNumSets[(int)type] - 1) + ". Requested: " + toString(set));
-			return (UINT32)-1;
-		}
-#endif
-
-		UINT32 globalSlot = mOffsets[(int)type][set] + slot;
-
-#if BS_DEBUG_MODE
-		if (globalSlot >= mNumElements[(int)type])
-		{
-			UINT32 maxSlot;
-			if (set < (mNumSets[(int)type] - 1))
-				maxSlot = mOffsets[(int)type][set + 1];
-			else
-				maxSlot = mNumElements[(int)type];
-
-			maxSlot -= mOffsets[(int)type][set];
-
-			LOGERR("Slot index out of range: Valid range: 0 .. " +
-				toString(maxSlot - 1) + ". Requested: " + toString(slot));
-			return (UINT32)-1;
-		}
-#endif
-
-		return globalSlot;
-	}
-
 	template<bool Core>
 	void TGpuParams<Core>::setParamBlockBuffer(UINT32 set, UINT32 slot, const ParamsBufferType& paramBlockBuffer)
 	{
-		UINT32 globalSlot = getGlobalSlot(ElementType::ParamBlock, set, slot);
+		UINT32 globalSlot = mParamInfo->getSequentialSlot(GpuPipelineParamInfo::ParamType::ParamBlock, set, slot);
 		if (globalSlot == (UINT32)-1)
 			return;
 
@@ -376,7 +233,7 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 	template<bool Core>
 	void TGpuParams<Core>::setParamBlockBuffer(GpuProgramType type, const String& name, const ParamsBufferType& paramBlockBuffer)
 	{
-		const SPtr<GpuParamDesc>& paramDescs = mParamDescs[(int)type];
+		const SPtr<GpuParamDesc>& paramDescs = mParamInfo->getParamDesc(type);
 		if(paramDescs == nullptr)
 		{
 			LOGWRN("Cannot find parameter block with the name: '" + name + "'");
@@ -397,7 +254,7 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 	template<class T> 
 	void TGpuParams<Core>::getParam(GpuProgramType type, const String& name, TGpuDataParam<T, Core>& output) const
 	{
-		const SPtr<GpuParamDesc>& paramDescs = mParamDescs[(int)type];
+		const SPtr<GpuParamDesc>& paramDescs = mParamInfo->getParamDesc(type);
 		if (paramDescs == nullptr)
 		{
 			output = TGpuDataParam<T, Core>(nullptr, nullptr);
@@ -418,7 +275,7 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 	template<bool Core>
 	void TGpuParams<Core>::getStructParam(GpuProgramType type, const String& name, TGpuParamStruct<Core>& output) const
 	{
-		const SPtr<GpuParamDesc>& paramDescs = mParamDescs[(int)type];
+		const SPtr<GpuParamDesc>& paramDescs = mParamInfo->getParamDesc(type);
 		if (paramDescs == nullptr)
 		{
 			output = TGpuParamStruct<Core>(nullptr, nullptr);
@@ -439,7 +296,7 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 	template<bool Core>
 	void TGpuParams<Core>::getTextureParam(GpuProgramType type, const String& name, TGpuParamTexture<Core>& output) const
 	{
-		const SPtr<GpuParamDesc>& paramDescs = mParamDescs[(int)type];
+		const SPtr<GpuParamDesc>& paramDescs = mParamInfo->getParamDesc(type);
 		if (paramDescs == nullptr)
 		{
 			output = TGpuParamTexture<Core>(nullptr, nullptr);
@@ -460,7 +317,7 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 	template<bool Core>
 	void TGpuParams<Core>::getLoadStoreTextureParam(GpuProgramType type, const String& name, TGpuParamLoadStoreTexture<Core>& output) const
 	{
-		const SPtr<GpuParamDesc>& paramDescs = mParamDescs[(int)type];
+		const SPtr<GpuParamDesc>& paramDescs = mParamInfo->getParamDesc(type);
 		if (paramDescs == nullptr)
 		{
 			output = TGpuParamLoadStoreTexture<Core>(nullptr, nullptr);
@@ -481,7 +338,7 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 	template<bool Core>
 	void TGpuParams<Core>::getBufferParam(GpuProgramType type, const String& name, TGpuParamBuffer<Core>& output) const
 	{
-		const SPtr<GpuParamDesc>& paramDescs = mParamDescs[(int)type];
+		const SPtr<GpuParamDesc>& paramDescs = mParamInfo->getParamDesc(type);
 		if (paramDescs == nullptr)
 		{
 			output = TGpuParamBuffer<Core>(nullptr, nullptr);
@@ -502,7 +359,7 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 	template<bool Core>
 	void TGpuParams<Core>::getSamplerStateParam(GpuProgramType type, const String& name, TGpuParamSampState<Core>& output) const
 	{
-		const SPtr<GpuParamDesc>& paramDescs = mParamDescs[(int)type];
+		const SPtr<GpuParamDesc>& paramDescs = mParamInfo->getParamDesc(type);
 		if (paramDescs == nullptr)
 		{
 			output = TGpuParamSampState<Core>(nullptr, nullptr);
@@ -523,7 +380,7 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 	template<bool Core>
 	typename TGpuParams<Core>::ParamsBufferType TGpuParams<Core>::getParamBlockBuffer(UINT32 set, UINT32 slot) const
 	{
-		UINT32 globalSlot = getGlobalSlot(ElementType::ParamBlock, set, slot);
+		UINT32 globalSlot = mParamInfo->getSequentialSlot(GpuPipelineParamInfo::ParamType::ParamBlock, set, slot);
 		if (globalSlot == (UINT32)-1)
 			return nullptr;
 
@@ -533,7 +390,7 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 	template<bool Core>
 	typename TGpuParams<Core>::TextureType TGpuParams<Core>::getTexture(UINT32 set, UINT32 slot) const
 	{
-		UINT32 globalSlot = getGlobalSlot(ElementType::Texture, set, slot);
+		UINT32 globalSlot = mParamInfo->getSequentialSlot(GpuPipelineParamInfo::ParamType::Texture, set, slot);
 		if (globalSlot == (UINT32)-1)
 			return TGpuParams<Core>::TextureType();
 
@@ -543,7 +400,7 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 	template<bool Core>
 	typename TGpuParams<Core>::TextureType TGpuParams<Core>::getLoadStoreTexture(UINT32 set, UINT32 slot) const
 	{
-		UINT32 globalSlot = getGlobalSlot(ElementType::LoadStoreTexture, set, slot);
+		UINT32 globalSlot = mParamInfo->getSequentialSlot(GpuPipelineParamInfo::ParamType::LoadStoreTexture, set, slot);
 		if (globalSlot == (UINT32)-1)
 			return TGpuParams<Core>::TextureType();
 
@@ -553,7 +410,7 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 	template<bool Core>
 	typename TGpuParams<Core>::BufferType TGpuParams<Core>::getBuffer(UINT32 set, UINT32 slot) const
 	{
-		UINT32 globalSlot = getGlobalSlot(ElementType::Buffer, set, slot);
+		UINT32 globalSlot = mParamInfo->getSequentialSlot(GpuPipelineParamInfo::ParamType::Buffer, set, slot);
 		if (globalSlot == (UINT32)-1)
 			return nullptr;
 
@@ -563,7 +420,7 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 	template<bool Core>
 	typename TGpuParams<Core>::SamplerType TGpuParams<Core>::getSamplerState(UINT32 set, UINT32 slot) const
 	{
-		UINT32 globalSlot = getGlobalSlot(ElementType::SamplerState, set, slot);
+		UINT32 globalSlot = mParamInfo->getSequentialSlot(GpuPipelineParamInfo::ParamType::SamplerState, set, slot);
 		if (globalSlot == (UINT32)-1)
 			return nullptr;
 
@@ -575,7 +432,7 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 	{
 		static TextureSurface emptySurface;
 
-		UINT32 globalSlot = getGlobalSlot(ElementType::LoadStoreTexture, set, slot);
+		UINT32 globalSlot = mParamInfo->getSequentialSlot(GpuPipelineParamInfo::ParamType::LoadStoreTexture, set, slot);
 		if (globalSlot == (UINT32)-1)
 			return emptySurface;
 
@@ -586,7 +443,7 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 	template<bool Core>
 	void TGpuParams<Core>::setTexture(UINT32 set, UINT32 slot, const TextureType& texture)
 	{
-		UINT32 globalSlot = getGlobalSlot(ElementType::Texture, set, slot);
+		UINT32 globalSlot = mParamInfo->getSequentialSlot(GpuPipelineParamInfo::ParamType::Texture, set, slot);
 		if (globalSlot == (UINT32)-1)
 			return;
 
@@ -599,7 +456,7 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 	template<bool Core>
 	void TGpuParams<Core>::setLoadStoreTexture(UINT32 set, UINT32 slot, const TextureType& texture, const TextureSurface& surface)
 	{
-		UINT32 globalSlot = getGlobalSlot(ElementType::LoadStoreTexture, set, slot);
+		UINT32 globalSlot = mParamInfo->getSequentialSlot(GpuPipelineParamInfo::ParamType::LoadStoreTexture, set, slot);
 		if (globalSlot == (UINT32)-1)
 			return;
 
@@ -612,7 +469,7 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 	template<bool Core>
 	void TGpuParams<Core>::setBuffer(UINT32 set, UINT32 slot, const BufferType& buffer)
 	{
-		UINT32 globalSlot = getGlobalSlot(ElementType::Buffer, set, slot);
+		UINT32 globalSlot = mParamInfo->getSequentialSlot(GpuPipelineParamInfo::ParamType::Buffer, set, slot);
 		if (globalSlot == (UINT32)-1)
 			return;
 
@@ -625,7 +482,7 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 	template<bool Core>
 	void TGpuParams<Core>::setSamplerState(UINT32 set, UINT32 slot, const SamplerType& sampler)
 	{
-		UINT32 globalSlot = getGlobalSlot(ElementType::SamplerState, set, slot);
+		UINT32 globalSlot = mParamInfo->getSequentialSlot(GpuPipelineParamInfo::ParamType::SamplerState, set, slot);
 		if (globalSlot == (UINT32)-1)
 			return;
 
@@ -638,7 +495,7 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 	template<bool Core>
 	void TGpuParams<Core>::setLoadStoreSurface(UINT32 set, UINT32 slot, const TextureSurface& surface)
 	{
-		UINT32 globalSlot = getGlobalSlot(ElementType::LoadStoreTexture, set, slot);
+		UINT32 globalSlot = mParamInfo->getSequentialSlot(GpuPipelineParamInfo::ParamType::LoadStoreTexture, set, slot);
 		if (globalSlot == (UINT32)-1)
 			return;
 
@@ -686,8 +543,8 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Matrix4x2>(GpuProgramType type, const String&, TGpuDataParam<Matrix4x2, true>&) const;
 	template BS_CORE_EXPORT void TGpuParams<true>::getParam<Matrix4x3>(GpuProgramType type, const String&, TGpuDataParam<Matrix4x3, true>&) const;
 
-	GpuParamsCore::GpuParamsCore(const GPU_PARAMS_DESC& desc, GpuDeviceFlags deviceMask)
-		: TGpuParams(desc)
+	GpuParamsCore::GpuParamsCore(const SPtr<GpuPipelineParamInfo>& paramInfo, GpuDeviceFlags deviceMask)
+		: TGpuParams(paramInfo)
 	{
 
 	}
@@ -699,12 +556,18 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 
 	void GpuParamsCore::syncToCore(const CoreSyncData& data)
 	{
-		UINT32 loadStoreSurfacesSize = mNumElements[(int)ElementType::LoadStoreTexture] * sizeof(TextureSurface);
-		UINT32 paramBufferSize = mNumElements[(int)ElementType::ParamBlock] * sizeof(SPtr<GpuParamBlockBufferCore>);
-		UINT32 textureArraySize = mNumElements[(int)ElementType::Texture] * sizeof(SPtr<TextureCore>);
-		UINT32 loadStoreTextureArraySize = mNumElements[(int)ElementType::LoadStoreTexture] * sizeof(SPtr<TextureCore>);
-		UINT32 bufferArraySize = mNumElements[(int)ElementType::Buffer] * sizeof(SPtr<GpuBufferCore>);
-		UINT32 samplerArraySize = mNumElements[(int)ElementType::SamplerState] * sizeof(SPtr<SamplerStateCore>);
+		UINT32 numParamBlocks = mParamInfo->getNumElements(GpuPipelineParamInfo::ParamType::ParamBlock);
+		UINT32 numTextures = mParamInfo->getNumElements(GpuPipelineParamInfo::ParamType::Texture);
+		UINT32 numStorageTextures = mParamInfo->getNumElements(GpuPipelineParamInfo::ParamType::LoadStoreTexture);
+		UINT32 numBuffers = mParamInfo->getNumElements(GpuPipelineParamInfo::ParamType::Buffer);
+		UINT32 numSamplers = mParamInfo->getNumElements(GpuPipelineParamInfo::ParamType::SamplerState);
+
+		UINT32 loadStoreSurfacesSize = numStorageTextures * sizeof(TextureSurface);
+		UINT32 paramBufferSize = numParamBlocks * sizeof(SPtr<GpuParamBlockBufferCore>);
+		UINT32 textureArraySize = numTextures * sizeof(SPtr<TextureCore>);
+		UINT32 loadStoreTextureArraySize = numStorageTextures * sizeof(SPtr<TextureCore>);
+		UINT32 bufferArraySize = numBuffers * sizeof(SPtr<GpuBufferCore>);
+		UINT32 samplerArraySize = numSamplers * sizeof(SPtr<SamplerStateCore>);
 
 		UINT32 totalSize = loadStoreSurfacesSize + paramBufferSize + textureArraySize + loadStoreTextureArraySize
 			+ bufferArraySize + samplerArraySize;
@@ -728,19 +591,19 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 		SPtr<SamplerStateCore>* samplers = (SPtr<SamplerStateCore>*)(dataPtr + samplerArrayOffset);
 
 		// Copy & destruct
-		for (UINT32 i = 0; i < mNumElements[(int)ElementType::ParamBlock]; i++)
+		for (UINT32 i = 0; i < numParamBlocks; i++)
 		{
 			mParamBlockBuffers[i] = paramBuffers[i];
 			paramBuffers[i].~SPtr<GpuParamBlockBufferCore>();
 		}
 
-		for (UINT32 i = 0; i < mNumElements[(int)ElementType::Texture]; i++)
+		for (UINT32 i = 0; i < numTextures; i++)
 		{
 			mTextures[i] = textures[i];
 			textures[i].~SPtr<TextureCore>();
 		}
 
-		for (UINT32 i = 0; i < mNumElements[(int)ElementType::LoadStoreTexture]; i++)
+		for (UINT32 i = 0; i < numStorageTextures; i++)
 		{
 			mLoadStoreSurfaces[i] = loadStoreSurfaces[i];
 			loadStoreSurfaces[i].~TextureSurface();
@@ -749,28 +612,28 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 			loadStoreTextures[i].~SPtr<TextureCore>();
 		}
 
-		for (UINT32 i = 0; i < mNumElements[(int)ElementType::Buffer]; i++)
+		for (UINT32 i = 0; i < numBuffers; i++)
 		{
 			mBuffers[i] = buffers[i];
 			buffers[i].~SPtr<GpuBufferCore>();
 		}
 
-		for (UINT32 i = 0; i < mNumElements[(int)ElementType::SamplerState]; i++)
+		for (UINT32 i = 0; i < numSamplers; i++)
 		{
 			mSamplerStates[i] = samplers[i];
 			samplers[i].~SPtr<SamplerStateCore>();
 		}
 	}
 
-	SPtr<GpuParamsCore> GpuParamsCore::create(const GPU_PARAMS_DESC& desc, GpuDeviceFlags deviceMask)
+	SPtr<GpuParamsCore> GpuParamsCore::create(const SPtr<GpuPipelineParamInfo>& paramInfo, GpuDeviceFlags deviceMask)
 	{
-		return HardwareBufferCoreManager::instance().createGpuParams(desc, deviceMask);
+		return HardwareBufferCoreManager::instance().createGpuParams(paramInfo, deviceMask);
 	}
 
 	const GpuDataParamInfos GpuParams::PARAM_SIZES;
 
-	GpuParams::GpuParams(const GPU_PARAMS_DESC& desc)
-		: TGpuParams(desc)
+	GpuParams::GpuParams(const SPtr<GpuPipelineParamInfo>& paramInfo)
+		: TGpuParams(paramInfo)
 	{
 
 	}
@@ -787,15 +650,7 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 
 	SPtr<CoreObjectCore> GpuParams::createCore() const
 	{
-		GPU_PARAMS_DESC desc;
-		desc.vertexParams = mParamDescs[GPT_VERTEX_PROGRAM];
-		desc.fragmentParams = mParamDescs[GPT_FRAGMENT_PROGRAM];
-		desc.geometryParams = mParamDescs[GPT_GEOMETRY_PROGRAM];
-		desc.hullParams = mParamDescs[GPT_HULL_PROGRAM];
-		desc.domainParams = mParamDescs[GPT_DOMAIN_PROGRAM];
-		desc.computeParams = mParamDescs[GPT_COMPUTE_PROGRAM];
-
-		return HardwareBufferCoreManager::instance().createGpuParams(desc);
+		return HardwareBufferCoreManager::instance().createGpuParams(mParamInfo);
 	}
 
 	void GpuParams::_markCoreDirty()
@@ -808,19 +663,25 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 		markListenerResourcesDirty();
 	}
 
-	SPtr<GpuParams> GpuParams::create(const GPU_PARAMS_DESC& desc)
+	SPtr<GpuParams> GpuParams::create(const SPtr<GpuPipelineParamInfo>& paramInfo)
 	{
-		return HardwareBufferManager::instance().createGpuParams(desc);
+		return HardwareBufferManager::instance().createGpuParams(paramInfo);
 	}
 
 	CoreSyncData GpuParams::syncToCore(FrameAlloc* allocator)
 	{
-		UINT32 loadStoreSurfacesSize = mNumElements[(int)ElementType::LoadStoreTexture] * sizeof(TextureSurface);
-		UINT32 paramBufferSize = mNumElements[(int)ElementType::ParamBlock] * sizeof(SPtr<GpuParamBlockBufferCore>);
-		UINT32 textureArraySize = mNumElements[(int)ElementType::Texture] * sizeof(SPtr<TextureCore>);
-		UINT32 loadStoreTextureArraySize = mNumElements[(int)ElementType::LoadStoreTexture] * sizeof(SPtr<TextureCore>);
-		UINT32 bufferArraySize = mNumElements[(int)ElementType::Buffer] * sizeof(SPtr<GpuBufferCore>);
-		UINT32 samplerArraySize = mNumElements[(int)ElementType::SamplerState] * sizeof(SPtr<SamplerStateCore>);
+		UINT32 numParamBlocks = mParamInfo->getNumElements(GpuPipelineParamInfo::ParamType::ParamBlock);
+		UINT32 numTextures = mParamInfo->getNumElements(GpuPipelineParamInfo::ParamType::Texture);
+		UINT32 numStorageTextures = mParamInfo->getNumElements(GpuPipelineParamInfo::ParamType::LoadStoreTexture);
+		UINT32 numBuffers = mParamInfo->getNumElements(GpuPipelineParamInfo::ParamType::Buffer);
+		UINT32 numSamplers = mParamInfo->getNumElements(GpuPipelineParamInfo::ParamType::SamplerState);
+
+		UINT32 loadStoreSurfacesSize = numStorageTextures * sizeof(TextureSurface);
+		UINT32 paramBufferSize = numParamBlocks * sizeof(SPtr<GpuParamBlockBufferCore>);
+		UINT32 textureArraySize = numTextures * sizeof(SPtr<TextureCore>);
+		UINT32 loadStoreTextureArraySize = numStorageTextures * sizeof(SPtr<TextureCore>);
+		UINT32 bufferArraySize = numBuffers * sizeof(SPtr<GpuBufferCore>);
+		UINT32 samplerArraySize = numSamplers * sizeof(SPtr<SamplerStateCore>);
 
 		UINT32 totalSize = loadStoreSurfacesSize + paramBufferSize + textureArraySize + loadStoreTextureArraySize 
 			+ bufferArraySize + samplerArraySize;
@@ -842,7 +703,7 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 		SPtr<SamplerStateCore>* samplers = (SPtr<SamplerStateCore>*)(data + samplerArrayOffset);
 
 		// Construct & copy
-		for (UINT32 i = 0; i < mNumElements[(int)ElementType::ParamBlock]; i++)
+		for (UINT32 i = 0; i < numParamBlocks; i++)
 		{
 			new (&paramBuffers[i]) SPtr<GpuParamBlockBufferCore>();
 
@@ -850,7 +711,7 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 				paramBuffers[i] = mParamBlockBuffers[i]->getCore();
 		}
 
-		for (UINT32 i = 0; i < mNumElements[(int)ElementType::Texture]; i++)
+		for (UINT32 i = 0; i < numTextures; i++)
 		{
 			new (&textures[i]) SPtr<TextureCore>();
 
@@ -860,7 +721,7 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 				textures[i] = nullptr;
 		}
 
-		for (UINT32 i = 0; i < mNumElements[(int)ElementType::LoadStoreTexture]; i++)
+		for (UINT32 i = 0; i < numStorageTextures; i++)
 		{
 			new (&loadStoreSurfaces[i]) TextureSurface();
 			loadStoreSurfaces[i] = mLoadStoreSurfaces[i];
@@ -873,7 +734,7 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 				loadStoreTextures[i] = nullptr;
 		}
 
-		for (UINT32 i = 0; i < mNumElements[(int)ElementType::Buffer]; i++)
+		for (UINT32 i = 0; i < numBuffers; i++)
 		{
 			new (&buffers[i]) SPtr<GpuBufferCore>();
 
@@ -883,7 +744,7 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 				buffers[i] = nullptr;
 		}
 
-		for (UINT32 i = 0; i < mNumElements[(int)ElementType::SamplerState]; i++)
+		for (UINT32 i = 0; i < numSamplers; i++)
 		{
 			new (&samplers[i]) SPtr<SamplerStateCore>();
 
@@ -898,13 +759,16 @@ UINT32 GpuParamsBase::getDataParamSize(GpuProgramType type, const String& name)
 
 	void GpuParams::getListenerResources(Vector<HResource>& resources)
 	{
-		for (UINT32 i = 0; i < mNumElements[(int)ElementType::Texture]; i++)
+		UINT32 numTextures = mParamInfo->getNumElements(GpuPipelineParamInfo::ParamType::Texture);
+		UINT32 numStorageTextures = mParamInfo->getNumElements(GpuPipelineParamInfo::ParamType::LoadStoreTexture);
+
+		for (UINT32 i = 0; i < numTextures; i++)
 		{
 			if (mTextures[i] != nullptr)
 				resources.push_back(mTextures[i]);
 		}
 
-		for (UINT32 i = 0; i < mNumElements[(int)ElementType::LoadStoreTexture]; i++)
+		for (UINT32 i = 0; i < numStorageTextures; i++)
 		{
 			if (mLoadStoreTextures[i] != nullptr)
 				resources.push_back(mLoadStoreTextures[i]);

+ 3 - 27
Source/BansheeCore/Source/BsGpuParamsSet.cpp

@@ -5,6 +5,7 @@
 #include "BsTechnique.h"
 #include "BsPass.h"
 #include "BsGpuProgram.h"
+#include "BsGpuPipelineState.h"
 #include "BsMaterialParams.h"
 #include "BsGpuParamDesc.h"
 #include "BsRenderAPI.h"
@@ -473,34 +474,9 @@ namespace BansheeEngine
 		for (UINT32 i = 0; i < numPasses; i++)
 		{
 			SPtr<PassType> curPass = technique->getPass(i);
+			GpuPipelineStateType pipeline = curPass->getPipelineState();
 
-			GPU_PARAMS_DESC paramsDesc;
-			
-			GpuProgramPtrType vertProgram = curPass->getVertexProgram();
-			if (vertProgram)
-				paramsDesc.vertexParams = vertProgram->getParamDesc();
-
-			GpuProgramPtrType fragProgram = curPass->getFragmentProgram();
-			if (fragProgram)
-				paramsDesc.fragmentParams = fragProgram->getParamDesc();
-
-			GpuProgramPtrType geomProgram = curPass->getGeometryProgram();
-			if (geomProgram)
-				paramsDesc.geometryParams = geomProgram->getParamDesc();
-
-			GpuProgramPtrType hullProgram = curPass->getHullProgram();
-			if (hullProgram)
-				paramsDesc.hullParams = hullProgram->getParamDesc();
-
-			GpuProgramPtrType domainProgram = curPass->getDomainProgram();
-			if (domainProgram)
-				paramsDesc.domainParams = domainProgram->getParamDesc();
-
-			GpuProgramPtrType computeProgram = curPass->getComputeProgram();
-			if (computeProgram)
-				paramsDesc.computeParams = computeProgram->getParamDesc();
-
-			mPassParams[i] = GpuParamsType::create(paramsDesc);
+			mPassParams[i] = GpuParamsType::create(pipeline->getParamInfo());
 		}
 
 		// Create and assign parameter block buffers

+ 196 - 1
Source/BansheeCore/Source/BsGpuPipelineState.cpp

@@ -5,6 +5,7 @@
 #include "BsBlendState.h"
 #include "BsDepthStencilState.h"
 #include "BsGpuProgram.h"
+#include "BsGpuParamDesc.h"
 #include "BsRenderStateManager.h"
 
 namespace BansheeEngine
@@ -29,7 +30,25 @@ namespace BansheeEngine
 	template<bool Core>
 	TGpuPipelineState<Core>::TGpuPipelineState(const StateDescType& data)
 		:mData(data)
-	{ }
+	{
+		GPU_PIPELINE_PARAMS_DESC paramsDesc;
+		if (data.vertexProgram != nullptr)
+			paramsDesc.vertexParams = data.vertexProgram->getParamDesc();
+
+		if (data.fragmentProgram != nullptr)
+			paramsDesc.fragmentParams = data.fragmentProgram->getParamDesc();
+
+		if (data.geometryProgram != nullptr)
+			paramsDesc.geometryParams = data.geometryProgram->getParamDesc();
+
+		if (data.hullProgram != nullptr)
+			paramsDesc.hullParams = data.hullProgram->getParamDesc();
+
+		if (data.domainProgram != nullptr)
+			paramsDesc.domainParams = data.domainProgram->getParamDesc();
+
+		mParamInfo = GpuPipelineParamInfo::create(paramsDesc);
+	}
 
 	template class TGpuPipelineState < false > ;
 	template class TGpuPipelineState < true >;
@@ -64,4 +83,180 @@ namespace BansheeEngine
 	{
 		return RenderStateManager::instance().createPipelineState(desc);
 	}
+
+	GpuPipelineParamInfo::GpuPipelineParamInfo(const GPU_PIPELINE_PARAMS_DESC& desc)
+		:mTotalNumSets(0)
+	{
+		mParamDescs[GPT_FRAGMENT_PROGRAM] = desc.fragmentParams;
+		mParamDescs[GPT_VERTEX_PROGRAM] = desc.vertexParams;
+		mParamDescs[GPT_GEOMETRY_PROGRAM] = desc.geometryParams;
+		mParamDescs[GPT_HULL_PROGRAM] = desc.hullParams;
+		mParamDescs[GPT_DOMAIN_PROGRAM] = desc.domainParams;
+		mParamDescs[GPT_COMPUTE_PROGRAM] = desc.computeParams;
+
+		for (UINT32 i = 0; i < (UINT32)ParamType::Count; i++)
+		{
+			mNumSets[i] = 0;
+			mNumElements[i] = 0;
+			mOffsets[i] = nullptr;
+		}
+
+		UINT32 numParamDescs = sizeof(mParamDescs) / sizeof(mParamDescs[0]);
+		for (UINT32 i = 0; i < numParamDescs; i++)
+		{
+			const SPtr<GpuParamDesc>& paramDesc = mParamDescs[i];
+			if (paramDesc == nullptr)
+				continue;
+
+			for (auto& paramBlock : paramDesc->paramBlocks)
+			{
+				if ((paramBlock.second.set + 1) > mNumSets[(int)ParamType::ParamBlock])
+					mNumSets[(int)ParamType::ParamBlock] = paramBlock.second.set + 1;
+			}
+
+			for (auto& texture : paramDesc->textures)
+			{
+				if ((texture.second.set + 1) > mNumSets[(int)ParamType::Texture])
+					mNumSets[(int)ParamType::Texture] = texture.second.set + 1;
+			}
+
+			for (auto& texture : paramDesc->loadStoreTextures)
+			{
+				if ((texture.second.set + 1) > mNumSets[(int)ParamType::LoadStoreTexture])
+					mNumSets[(int)ParamType::LoadStoreTexture] = texture.second.set + 1;
+			}
+
+			for (auto& buffer : paramDesc->buffers)
+			{
+				if ((buffer.second.set + 1) > mNumSets[(int)ParamType::Buffer])
+					mNumSets[(int)ParamType::Buffer] = buffer.second.set + 1;
+			}
+
+			for (auto& sampler : paramDesc->samplers)
+			{
+				if ((sampler.second.set + 1) > mNumSets[(int)ParamType::SamplerState])
+					mNumSets[(int)ParamType::SamplerState] = sampler.second.set + 1;
+			}
+		}
+
+		UINT32 totalNumSets = 0;
+		for (UINT32 i = 0; i < (UINT32)ParamType::Count; i++)
+		{
+			totalNumSets += mNumSets[i];
+			mTotalNumSets = std::max(mTotalNumSets, mNumSets[i]);
+		}
+
+		UINT32* slotsPerSetData = bs_stack_alloc<UINT32>(totalNumSets);
+		memset(slotsPerSetData, 0, sizeof(UINT32) * totalNumSets);
+
+		UINT32* slotsPerSet[(UINT32)ParamType::Count];
+		for (UINT32 i = 0; i < (UINT32)ParamType::Count; i++)
+		{
+			if (i == 0)
+				slotsPerSet[i] = slotsPerSetData;
+			else
+				slotsPerSet[i] = slotsPerSet[i - 1] + mNumSets[i - 1];
+		}
+
+		for (UINT32 i = 0; i < numParamDescs; i++)
+		{
+			const SPtr<GpuParamDesc>& paramDesc = mParamDescs[i];
+			if (paramDesc == nullptr)
+				continue;
+
+			for (auto& paramBlock : paramDesc->paramBlocks)
+			{
+				UINT32* slots = slotsPerSet[(int)ParamType::ParamBlock];
+				slots[paramBlock.second.set] = std::max(slots[paramBlock.second.set], paramBlock.second.slot + 1);
+			}
+
+			for (auto& texture : paramDesc->textures)
+			{
+				UINT32* slots = slotsPerSet[(int)ParamType::Texture];
+				slots[texture.second.set] = std::max(slots[texture.second.set], texture.second.slot + 1);
+			}
+
+			for (auto& texture : paramDesc->loadStoreTextures)
+			{
+				UINT32* slots = slotsPerSet[(int)ParamType::LoadStoreTexture];
+				slots[texture.second.set] = std::max(slots[texture.second.set], texture.second.slot + 1);
+			}
+
+			for (auto& buffer : paramDesc->buffers)
+			{
+				UINT32* slots = slotsPerSet[(int)ParamType::Buffer];
+				slots[buffer.second.set] = std::max(slots[buffer.second.set], buffer.second.slot + 1);
+			}
+
+			for (auto& sampler : paramDesc->samplers)
+			{
+				UINT32* slots = slotsPerSet[(int)ParamType::SamplerState];
+				slots[sampler.second.set] = std::max(slots[sampler.second.set], sampler.second.slot + 1);
+			}
+		}
+
+		for (UINT32 i = 0; i < (UINT32)ParamType::Count; i++)
+		{
+			for (UINT32 j = 0; j < mNumSets[i]; j++)
+				mNumElements[i] += slotsPerSet[i][j];
+		}
+
+		UINT32 setOffsetsSize = sizeof(UINT32) * totalNumSets;
+		mData = (UINT8*)bs_alloc(setOffsetsSize);
+
+		UINT8* dataPtr = mData;
+		for (UINT32 i = 0; i < (UINT32)ParamType::Count; i++)
+		{
+			mOffsets[i] = (UINT32*)dataPtr;
+			dataPtr += sizeof(UINT32) * mNumSets[i];
+
+			if (mNumSets[i] == 0)
+				continue;
+
+			mOffsets[i][0] = 0;
+
+			for (UINT32 j = 0; j < mNumSets[i] - 1; j++)
+				mOffsets[i][j + 1] = mOffsets[i][j] + slotsPerSet[i][j];
+		}
+
+		bs_stack_free(slotsPerSetData);
+	}
+
+	GpuPipelineParamInfo::~GpuPipelineParamInfo()
+	{
+		bs_free(mData);
+	}
+
+	UINT32 GpuPipelineParamInfo::getSequentialSlot(ParamType type, UINT32 set, UINT32 slot) const
+	{
+#if BS_DEBUG_MODE
+		if (set >= mNumSets[(int)type])
+		{
+			LOGERR("Set index out of range: Valid range: 0 .. " +
+				   toString(mNumSets[(int)type] - 1) + ". Requested: " + toString(set));
+			return (UINT32)-1;
+		}
+#endif
+
+		UINT32 globalSlot = mOffsets[(int)type][set] + slot;
+
+#if BS_DEBUG_MODE
+		if (globalSlot >= mNumElements[(int)type])
+		{
+			UINT32 maxSlot;
+			if (set < (mNumSets[(int)type] - 1))
+				maxSlot = mOffsets[(int)type][set + 1];
+			else
+				maxSlot = mNumElements[(int)type];
+
+			maxSlot -= mOffsets[(int)type][set];
+
+			LOGERR("Slot index out of range: Valid range: 0 .. " +
+				   toString(maxSlot - 1) + ". Requested: " + toString(slot));
+			return (UINT32)-1;
+		}
+#endif
+
+		return globalSlot;
+	}
 }

+ 6 - 6
Source/BansheeCore/Source/BsHardwareBufferManager.cpp

@@ -63,9 +63,9 @@ namespace BansheeEngine
 		return gbuf;
 	}
 
-	SPtr<GpuParams> HardwareBufferManager::createGpuParams(const GPU_PARAMS_DESC& desc)
+	SPtr<GpuParams> HardwareBufferManager::createGpuParams(const SPtr<GpuPipelineParamInfo>& paramInfo)
     {
-		GpuParams* params = new (bs_alloc<GpuParams>()) GpuParams(desc);
+		GpuParams* params = new (bs_alloc<GpuParams>()) GpuParams(paramInfo);
 		SPtr<GpuParams> paramsPtr = bs_core_ptr<GpuParams>(params);
 		paramsPtr->_setThisPtr(paramsPtr);
 		paramsPtr->initialize();
@@ -99,10 +99,10 @@ namespace BansheeEngine
 		return declPtr;
 	}
 
-	SPtr<GpuParamsCore> HardwareBufferCoreManager::createGpuParams(const GPU_PARAMS_DESC& desc, 
+	SPtr<GpuParamsCore> HardwareBufferCoreManager::createGpuParams(const SPtr<GpuPipelineParamInfo>& paramInfo,
 		GpuDeviceFlags deviceMask)
     {
-		SPtr<GpuParamsCore> params = createGpuParamsInternal(desc, deviceMask);
+		SPtr<GpuParamsCore> params = createGpuParamsInternal(paramInfo, deviceMask);
 		params->initialize();
 
 		return params;
@@ -146,10 +146,10 @@ namespace BansheeEngine
 		return ret;
 	}
 
-	SPtr<GpuParamsCore> HardwareBufferCoreManager::createGpuParamsInternal(const GPU_PARAMS_DESC& desc, 
+	SPtr<GpuParamsCore> HardwareBufferCoreManager::createGpuParamsInternal(const SPtr<GpuPipelineParamInfo>& paramInfo,
 		GpuDeviceFlags deviceMask)
     {
-		GpuParamsCore* params = new (bs_alloc<GpuParamsCore>()) GpuParamsCore(desc, deviceMask);
+		GpuParamsCore* params = new (bs_alloc<GpuParamsCore>()) GpuParamsCore(paramInfo, deviceMask);
 		SPtr<GpuParamsCore> paramsPtr = bs_shared_ptr<GpuParamsCore>(params);
 		paramsPtr->_setThisPtr(paramsPtr);
 

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

@@ -76,7 +76,7 @@ namespace BansheeEngine
 
 		friend class VulkanHardwareBufferCoreManager;
 
-		VulkanGpuParams(const GPU_PARAMS_DESC& desc, GpuDeviceFlags deviceMask);
+		VulkanGpuParams(const SPtr<GpuPipelineParamInfo>& paramInfo, GpuDeviceFlags deviceMask);
 
 		PerDeviceData mPerDeviceData[BS_MAX_DEVICES];
 		GpuDeviceFlags mDeviceMask;

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

@@ -35,7 +35,7 @@ namespace BansheeEngine
 			GpuDeviceFlags deviceMask = GDF_DEFAULT) override;
 
 		/** @copydoc HardwareBufferCoreManager::createGpuParamsInternal */
-		SPtr<GpuParamsCore> createGpuParamsInternal(const GPU_PARAMS_DESC& desc, 
+		SPtr<GpuParamsCore> createGpuParamsInternal(const SPtr<GpuPipelineParamInfo>& paramInfo,
 			GpuDeviceFlags deviceMask = GDF_DEFAULT) override;
 	};
 

+ 2 - 2
Source/BansheeVulkanRenderAPI/Source/BsVulkanGpuParams.cpp

@@ -17,8 +17,8 @@
 
 namespace BansheeEngine
 {
-	VulkanGpuParams::VulkanGpuParams(const GPU_PARAMS_DESC& desc, GpuDeviceFlags deviceMask)
-		: GpuParamsCore(desc, deviceMask), mPerDeviceData(), mDeviceMask(deviceMask), mData(nullptr), mSetsDirty(nullptr)
+	VulkanGpuParams::VulkanGpuParams(const SPtr<GpuPipelineParamInfo>& paramInfo, GpuDeviceFlags deviceMask)
+		: GpuParamsCore(paramInfo, deviceMask), mPerDeviceData(), mDeviceMask(deviceMask), mData(nullptr), mSetsDirty(nullptr)
 	{
 		// Generate all required bindings
 		UINT32 numBindings = 0;

+ 3 - 3
Source/BansheeVulkanRenderAPI/Source/BsVulkanHardwareBufferManager.cpp

@@ -54,10 +54,10 @@ namespace BansheeEngine
 		return bufferPtr;
 	}
 
-	SPtr<GpuParamsCore> VulkanHardwareBufferCoreManager::createGpuParamsInternal(const GPU_PARAMS_DESC& desc,
-		GpuDeviceFlags deviceMask)
+	SPtr<GpuParamsCore> VulkanHardwareBufferCoreManager::createGpuParamsInternal(
+		const SPtr<GpuPipelineParamInfo>& paramInfo, GpuDeviceFlags deviceMask)
 	{
-		VulkanGpuParams* params = new (bs_alloc<VulkanGpuParams>()) VulkanGpuParams(desc, deviceMask);
+		VulkanGpuParams* params = new (bs_alloc<VulkanGpuParams>()) VulkanGpuParams(paramInfo, deviceMask);
 		SPtr<GpuParamsCore> paramsPtr = bs_shared_ptr<GpuParamsCore>(params);
 		paramsPtr->_setThisPtr(paramsPtr);