Bläddra i källkod

Refactored load/store textures so they're properly parsed and determined at shader compile time instead at runtime
- Solves an issue where normal and load-store textures were sharing bind slots, which is not correct

BearishSun 9 år sedan
förälder
incheckning
c1415b4883

+ 6 - 2
Documentation/Manuals/Native/bslfx.md

@@ -116,10 +116,14 @@ Types supported in this block are:
  - Texture3D - 3D texture
  - TextureCUBE - Cube texture
  - Texture2DMS - Multi-sampled 2D texture
+ - RWTexture1D - 1D texture (UAV/load-store texture)
+ - RWTexture2D - 2D texture (UAV/load-store texture)
+ - RWTexture3D - 3D texture (UAV/load-store texture)
+ - RWTexture2DMS - Multi-sampled 2D texture (UAV/load-store texture)
  - ByteBuffer - Readable buffer of raw bytes
  - StructBuffer - Readable buffer of structs
- - ByteBufferRW - Read/Write buffer of raw bytes (UAV/load-store buffer)
- - StructBufferRW  - Read/Write buffer of structs (UAV/load-store buffer)
+ - RWByteBuffer - Read/write buffer of raw bytes (UAV/load-store buffer)
+ - RWStructBuffer  - Read/write buffer of structs (UAV/load-store buffer)
  - AppendBuffer - Buffer that is used for appending data in a stack-like fashion
  - ConsumeBuffer - Buffer that is used for consuming data in a stack-like fashion
  

+ 4 - 0
Source/BansheeCore/Include/BsCommonTypes.h

@@ -292,6 +292,10 @@ namespace BansheeEngine
 		GPOT_RWSTRUCTURED_BUFFER_WITH_COUNTER = 44, /**< Read-write buffer containing a set of structures, with a counter. */
 		GPOT_RWAPPEND_BUFFER = 45, /**< Buffer that can be used for appending data in a stack-like fashion. */
 		GPOT_RWCONSUME_BUFFER = 46, /**< Buffer that can be used for consuming data in a stack-like fashion. */
+		GPOT_RWTEXTURE1D = 50, /**< 1D texture with unordered read/writes. */
+		GPOT_RWTEXTURE2D = 51, /**< 2D texture with unordered read/writes. */
+		GPOT_RWTEXTURE3D = 52, /**< 3D texture with unordered read/writes. */
+		GPOT_RWTEXTURE2DMS = 53, /**< 2D texture with multiple samples and unordered read/writes. */
 		GPOT_UNKNOWN = 0xffff
 	};
 

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

@@ -50,6 +50,7 @@ namespace BansheeEngine
 
 		Map<String, GpuParamObjectDesc> samplers;
 		Map<String, GpuParamObjectDesc> textures;
+		Map<String, GpuParamObjectDesc> loadStoreTextures;
 		Map<String, GpuParamObjectDesc> buffers;
 	};
 

+ 12 - 21
Source/BansheeCore/Include/BsGpuParams.h

@@ -15,17 +15,6 @@ namespace BansheeEngine
 	 *  @{
 	 */
 
-	/** Stores information needed for binding a texture to the pipeline. */
-	struct BoundTextureInfo
-	{
-		BoundTextureInfo()
-			:isLoadStore(false)
-		{ }
-
-		bool isLoadStore;
-		TextureSurface surface;
-	};
-
 	/**	Helper structure whose specializations convert an engine data type into a GPU program data parameter type.  */
 	template<class T> struct TGpuDataParamInfo { };
 	template<> struct TGpuDataParamInfo < float > { enum { TypeId = GPDT_FLOAT1 }; };
@@ -83,21 +72,15 @@ namespace BansheeEngine
 		/**	Checks if texture parameter with the specified name exists. */
 		bool hasTexture(const String& name) const;
 
+		/**	Checks if load/store texture parameter with the specified name exists. */
+		bool hasLoadStoreTexture(const String& name) const;
+
 		/**	Checks if sampler state parameter with the specified name exists. */
 		bool hasSamplerState(const String& name) const;
 
 		/** Checks if a parameter block with the specified name exists. */
 		bool hasParamBlock(const String& name) const;
 
-		/**
-		 * Checks is the texture at the specified slot to be bound as random load/store texture instead of a normal sampled
-		 * texture.
-		 */
-		bool isLoadStoreTexture(UINT32 slot) const;
-
-		/** Changes the type of the texture at the specified slot. */
-		void setIsLoadStoreTexture(UINT32 slot, bool isLoadStore);
-
 		/** Returns information that determines which texture surfaces to bind as load/store parameters. */
 		const TextureSurface& getLoadStoreSurface(UINT32 slot) const;
 
@@ -121,9 +104,10 @@ namespace BansheeEngine
 
 		UINT32 mNumParamBlocks;
 		UINT32 mNumTextures;
+		UINT32 mNumLoadStoreTextures;
 		UINT32 mNumSamplerStates;
 
-		BoundTextureInfo* mTextureInfo;
+		TextureSurface* mLoadStoreSurfaces;
 
 		bool mTransposeMatrices;
 	};
@@ -211,12 +195,18 @@ namespace BansheeEngine
 		/**	Gets a texture bound to the specified slot. */
 		TextureType getTexture(UINT32 slot);
 
+		/**	Gets a load/store texture bound to the specified slot. */
+		TextureType getLoadStoreTexture(UINT32 slot);
+
 		/**	Gets a sampler state bound to the specified slot. */
 		SamplerType getSamplerState(UINT32 slot);
 
 		/**	Sets a texture at the specified slot. */
 		void setTexture(UINT32 slot, const TextureType& texture);
 
+		/**	Sets a load/store texture at the specified slot. */
+		void setLoadStoreTexture(UINT32 slot, const TextureType& texture, const TextureSurface& surface);
+
 		/**	Sets a sampler state at the specified slot. */
 		void setSamplerState(UINT32 slot, const SamplerType& sampler);
 
@@ -226,6 +216,7 @@ namespace BansheeEngine
 
 		ParamsBufferType* mParamBlockBuffers;
 		TextureType* mTextures;
+		TextureType* mLoadStoreTextures;
 		SamplerType* mSamplerStates;
 	};
 

+ 3 - 0
Source/BansheeCore/Include/BsShader.h

@@ -413,6 +413,9 @@ namespace BansheeEngine
 		/**	Checks is the provided object type a texture. */
 		static bool isTexture(GpuParamObjectType type);
 
+		/**	Checks is the provided object type a load/store (unordered read/write) texture. */
+		static bool isLoadStoreTexture(GpuParamObjectType type);
+
 		/** Checks is the provided object type a buffer. */
 		static bool isBuffer(GpuParamObjectType type);
 

+ 1 - 4
Source/BansheeCore/Source/BsGpuParam.cpp

@@ -196,7 +196,6 @@ namespace BansheeEngine
 			return;
 
 		mParent->setTexture(mParamDesc->slot, texture);
-		mParent->setIsLoadStoreTexture(mParamDesc->slot, false);
 
 		mParent->_markResourcesDirty();
 		mParent->_markCoreDirty();
@@ -227,9 +226,7 @@ namespace BansheeEngine
 		if (mParent == nullptr)
 			return;
 
-		mParent->setTexture(mParamDesc->slot, texture);
-		mParent->setIsLoadStoreTexture(mParamDesc->slot, true);
-		mParent->setLoadStoreSurface(mParamDesc->slot, surface);
+		mParent->setLoadStoreTexture(mParamDesc->slot, texture, surface);
 
 		mParent->_markResourcesDirty();
 		mParent->_markCoreDirty();

+ 108 - 52
Source/BansheeCore/Source/BsGpuParams.cpp

@@ -15,8 +15,8 @@
 namespace BansheeEngine
 {
 	GpuParamsBase::GpuParamsBase(const SPtr<GpuParamDesc>& paramDesc, bool transposeMatrices)
-		: mParamDesc(paramDesc), mNumParamBlocks(0), mNumTextures(0), mNumSamplerStates(0), mTextureInfo(nullptr)
-		, mTransposeMatrices(transposeMatrices)
+		: mParamDesc(paramDesc), mNumParamBlocks(0), mNumTextures(0), mNumLoadStoreTextures(0), mNumSamplerStates(0)
+		, mLoadStoreSurfaces(nullptr), mTransposeMatrices(transposeMatrices)
 	{
 		for (auto& paramBlock : mParamDesc->paramBlocks)
 		{
@@ -30,18 +30,24 @@ namespace BansheeEngine
 				mNumTextures = texture.second.slot + 1;
 		}
 
+		for (auto& texture : mParamDesc->loadStoreTextures)
+		{
+			if ((texture.second.slot + 1) > mNumLoadStoreTextures)
+				mNumLoadStoreTextures = texture.second.slot + 1;
+		}
+
 		for (auto& sampler : mParamDesc->samplers)
 		{
 			if ((sampler.second.slot + 1) > mNumSamplerStates)
 				mNumSamplerStates = sampler.second.slot + 1;
 		}
 
-		mTextureInfo = bs_newN<BoundTextureInfo>(mNumTextures);
+		mLoadStoreSurfaces = bs_newN<TextureSurface>(mNumLoadStoreTextures);
 	}
 
 	GpuParamsBase::~GpuParamsBase()
 	{
-		bs_deleteN(mTextureInfo, mNumTextures);
+		bs_deleteN(mLoadStoreSurfaces, mNumLoadStoreTextures);
 	}
 
 UINT32 GpuParamsBase::getDataParamSize(const String& name) const
@@ -67,6 +73,15 @@ UINT32 GpuParamsBase::getDataParamSize(const String& name) const
 		return false;
 	}
 
+	bool GpuParamsBase::hasLoadStoreTexture(const String& name) const
+	{
+		auto paramIter = mParamDesc->loadStoreTextures.find(name);
+		if (paramIter != mParamDesc->loadStoreTextures.end())
+			return true;
+
+		return false;
+	}
+
 	bool GpuParamsBase::hasSamplerState(const String& name) const
 	{
 		auto paramIter = mParamDesc->samplers.find(name);
@@ -94,54 +109,32 @@ UINT32 GpuParamsBase::getDataParamSize(const String& name) const
 		return nullptr;
 	}
 
-	bool GpuParamsBase::isLoadStoreTexture(UINT32 slot) const
-	{
-		if (slot >= mNumTextures)
-		{
-			BS_EXCEPT(InvalidParametersException, "Index out of range: Valid range: 0 .. " +
-				toString(mNumTextures - 1) + ". Requested: " + toString(slot));
-		}
-
-		return mTextureInfo[slot].isLoadStore;
-	}
-
-	void GpuParamsBase::setIsLoadStoreTexture(UINT32 slot, bool isLoadStore)
-	{
-		if (slot >= mNumTextures)
-		{
-			BS_EXCEPT(InvalidParametersException, "Index out of range: Valid range: 0 .. " +
-				toString(mNumTextures - 1) + ". Requested: " + toString(slot));
-		}
-
-		mTextureInfo[slot].isLoadStore = isLoadStore;
-	}
-
 	const TextureSurface& GpuParamsBase::getLoadStoreSurface(UINT32 slot) const
 	{
-		if (slot >= mNumTextures)
+		if (slot >= mNumLoadStoreTextures)
 		{
 			BS_EXCEPT(InvalidParametersException, "Index out of range: Valid range: 0 .. " +
-				toString(mNumTextures - 1) + ". Requested: " + toString(slot));
+				toString(mNumLoadStoreTextures - 1) + ". Requested: " + toString(slot));
 		}
 
-		return mTextureInfo[slot].surface;
+		return mLoadStoreSurfaces[slot];
 	}
 
 	void GpuParamsBase::setLoadStoreSurface(UINT32 slot, const TextureSurface& surface) const
 	{
-		if (slot >= mNumTextures)
+		if (slot >= mNumLoadStoreTextures)
 		{
 			BS_EXCEPT(InvalidParametersException, "Index out of range: Valid range: 0 .. " +
-				toString(mNumTextures - 1) + ". Requested: " + toString(slot));
+				toString(mNumLoadStoreTextures - 1) + ". Requested: " + toString(slot));
 		}
 
-		mTextureInfo[slot].surface = surface;
+		mLoadStoreSurfaces[slot] = surface;
 	}
 
 	template<bool Core>
 	TGpuParams<Core>::TGpuParams(const SPtr<GpuParamDesc>& paramDesc, bool transposeMatrices)
-		:GpuParamsBase(paramDesc, transposeMatrices), mParamBlockBuffers(nullptr), mTextures(nullptr),
-		mSamplerStates(nullptr)
+		: GpuParamsBase(paramDesc, transposeMatrices), mParamBlockBuffers(nullptr), mTextures(nullptr)
+		, mLoadStoreTextures(nullptr), mSamplerStates(nullptr)
 	{
 		if (mNumParamBlocks > 0)
 			mParamBlockBuffers = bs_newN<ParamsBufferType>(mNumParamBlocks);
@@ -149,6 +142,9 @@ UINT32 GpuParamsBase::getDataParamSize(const String& name) const
 		if (mNumTextures > 0)
 			mTextures = bs_newN<TextureType>(mNumTextures);
 
+		if (mNumLoadStoreTextures > 0)
+			mLoadStoreTextures = bs_newN<TextureType>(mNumLoadStoreTextures);
+
 		if (mNumSamplerStates > 0)
 			mSamplerStates = bs_newN<SamplerType>(mNumSamplerStates);
 	}
@@ -162,6 +158,9 @@ UINT32 GpuParamsBase::getDataParamSize(const String& name) const
 		if (mTextures != nullptr)
 			bs_deleteN(mTextures, mNumTextures);
 
+		if (mLoadStoreTextures != nullptr)
+			bs_deleteN(mLoadStoreTextures, mNumLoadStoreTextures);
+
 		if (mSamplerStates != nullptr)
 			bs_deleteN(mSamplerStates, mNumSamplerStates);
 	}
@@ -242,9 +241,9 @@ UINT32 GpuParamsBase::getDataParamSize(const String& name) const
 	template<bool Core>
 	void TGpuParams<Core>::getLoadStoreTextureParam(const String& name, TGpuParamLoadStoreTexture<Core>& output) const
 	{
-		auto iterFind = mParamDesc->textures.find(name);
+		auto iterFind = mParamDesc->loadStoreTextures.find(name);
 
-		if (iterFind == mParamDesc->textures.end())
+		if (iterFind == mParamDesc->loadStoreTextures.end())
 		{
 			output = TGpuParamLoadStoreTexture<Core>(nullptr, nullptr);
 			LOGWRN("Cannot find texture parameter with the name '" + name + "'");
@@ -291,6 +290,18 @@ UINT32 GpuParamsBase::getDataParamSize(const String& name) const
 		return mTextures[slot];
 	}
 
+	template<bool Core>
+	typename TGpuParams<Core>::TextureType TGpuParams<Core>::getLoadStoreTexture(UINT32 slot)
+	{
+		if (slot < 0 || slot >= mNumLoadStoreTextures)
+		{
+			BS_EXCEPT(InvalidParametersException, "Index out of range: Valid range: 0 .. " +
+				toString(mNumLoadStoreTextures - 1) + ". Requested: " + toString(slot));
+		}
+
+		return mLoadStoreTextures[slot];
+	}
+
 	template<bool Core>
 	typename TGpuParams<Core>::SamplerType TGpuParams<Core>::getSamplerState(UINT32 slot)
 	{
@@ -318,6 +329,21 @@ UINT32 GpuParamsBase::getDataParamSize(const String& name) const
 		_markCoreDirty();
 	}
 
+	template<bool Core>
+	void TGpuParams<Core>::setLoadStoreTexture(UINT32 slot, const TextureType& texture, const TextureSurface& surface)
+	{
+		if (slot < 0 || slot >= mNumLoadStoreTextures)
+		{
+			BS_EXCEPT(InvalidParametersException, "Index out of range: Valid range: 0 .. " +
+				toString(mNumLoadStoreTextures - 1) + ". Requested: " + toString(slot));
+		}
+
+		mLoadStoreTextures[slot] = texture;
+
+		_markResourcesDirty();
+		_markCoreDirty();
+	}
+
 	template<bool Core>
 	void TGpuParams<Core>::setSamplerState(UINT32 slot, const SamplerType& sampler)
 	{
@@ -398,25 +424,29 @@ UINT32 GpuParamsBase::getDataParamSize(const String& name) const
 
 	void GpuParamsCore::syncToCore(const CoreSyncData& data)
 	{
-		UINT32 textureInfoSize = mNumTextures * sizeof(BoundTextureInfo);
+		UINT32 loadStoreSurfacesSize = mNumLoadStoreTextures * sizeof(TextureSurface);
 		UINT32 paramBufferSize = mNumParamBlocks * sizeof(SPtr<GpuParamBlockBufferCore>);
 		UINT32 textureArraySize = mNumTextures * sizeof(SPtr<TextureCore>);
+		UINT32 loadStoreTextureArraySize = mNumLoadStoreTextures * sizeof(SPtr<TextureCore>);
 		UINT32 samplerArraySize = mNumSamplerStates * sizeof(SPtr<SamplerStateCore>);
 
-		UINT32 totalSize = textureInfoSize + paramBufferSize + textureArraySize + samplerArraySize;
+		UINT32 totalSize = loadStoreSurfacesSize + paramBufferSize + textureArraySize + loadStoreTextureArraySize
+			+ samplerArraySize;
 
 		UINT32 textureInfoOffset = 0;
-		UINT32 paramBufferOffset = textureInfoOffset + textureInfoSize;
+		UINT32 paramBufferOffset = textureInfoOffset + loadStoreSurfacesSize;
 		UINT32 textureArrayOffset = paramBufferOffset + paramBufferSize;
-		UINT32 samplerArrayOffset = textureArrayOffset + textureArraySize;
+		UINT32 loadStoreTextureArrayOffset = textureArrayOffset + textureArraySize;
+		UINT32 samplerArrayOffset = loadStoreTextureArrayOffset + loadStoreTextureArraySize;
 
 		assert(data.getBufferSize() == totalSize);
 
 		UINT8* dataPtr = data.getBuffer();
 
-		BoundTextureInfo* textureInfos = (BoundTextureInfo*)(dataPtr + textureInfoOffset);
+		TextureSurface* loadStoreSurfaces = (TextureSurface*)(dataPtr + textureInfoOffset);
 		SPtr<GpuParamBlockBufferCore>* paramBuffers = (SPtr<GpuParamBlockBufferCore>*)(dataPtr + paramBufferOffset);
 		SPtr<TextureCore>* textures = (SPtr<TextureCore>*)(dataPtr + textureArrayOffset);
+		SPtr<TextureCore>* loadStoreTextures = (SPtr<TextureCore>*)(dataPtr + loadStoreTextureArrayOffset);
 		SPtr<SamplerStateCore>* samplers = (SPtr<SamplerStateCore>*)(dataPtr + samplerArrayOffset);
 
 		// Copy & destruct
@@ -428,13 +458,19 @@ UINT32 GpuParamsBase::getDataParamSize(const String& name) const
 
 		for (UINT32 i = 0; i < mNumTextures; i++)
 		{
-			mTextureInfo[i] = textureInfos[i];
-			textureInfos[i].~BoundTextureInfo();
-
 			mTextures[i] = textures[i];
 			textures[i].~SPtr<TextureCore>();
 		}
 
+		for (UINT32 i = 0; i < mNumLoadStoreTextures; i++)
+		{
+			mLoadStoreSurfaces[i] = loadStoreSurfaces[i];
+			loadStoreSurfaces[i].~TextureSurface();
+
+			mLoadStoreTextures[i] = loadStoreTextures[i];
+			loadStoreTextures[i].~SPtr<TextureCore>();
+		}
+
 		for (UINT32 i = 0; i < mNumSamplerStates; i++)
 		{
 			mSamplerStates[i] = samplers[i];
@@ -501,23 +537,27 @@ UINT32 GpuParamsBase::getDataParamSize(const String& name) const
 
 	CoreSyncData GpuParams::syncToCore(FrameAlloc* allocator)
 	{
-		UINT32 textureInfoSize = mNumTextures * sizeof(BoundTextureInfo);
+		UINT32 loadStoreSurfacesSize = mNumLoadStoreTextures * sizeof(TextureSurface);
 		UINT32 paramBufferSize = mNumParamBlocks * sizeof(SPtr<GpuParamBlockBufferCore>);
 		UINT32 textureArraySize = mNumTextures * sizeof(SPtr<TextureCore>);
+		UINT32 loadStoreTextureArraySize = mNumLoadStoreTextures * sizeof(SPtr<TextureCore>);
 		UINT32 samplerArraySize = mNumSamplerStates * sizeof(SPtr<SamplerStateCore>);
 
-		UINT32 totalSize = textureInfoSize + paramBufferSize + textureArraySize + samplerArraySize;
+		UINT32 totalSize = loadStoreSurfacesSize + paramBufferSize + textureArraySize + loadStoreTextureArraySize 
+			+ samplerArraySize;
 
 		UINT32 textureInfoOffset = 0;
-		UINT32 paramBufferOffset = textureInfoOffset + textureInfoSize;
+		UINT32 paramBufferOffset = textureInfoOffset + loadStoreSurfacesSize;
 		UINT32 textureArrayOffset = paramBufferOffset + paramBufferSize;
-		UINT32 samplerArrayOffset = textureArrayOffset + textureArraySize;
+		UINT32 loadStoreTextureArrayOffset = textureArrayOffset + textureArraySize;
+		UINT32 samplerArrayOffset = loadStoreTextureArrayOffset + loadStoreTextureArraySize;
 
 		UINT8* data = allocator->alloc(totalSize);
 
-		BoundTextureInfo* textureInfos = (BoundTextureInfo*)(data + textureInfoOffset);
+		TextureSurface* loadStoreSurfaces = (TextureSurface*)(data + textureInfoOffset);
 		SPtr<GpuParamBlockBufferCore>* paramBuffers = (SPtr<GpuParamBlockBufferCore>*)(data + paramBufferOffset);
 		SPtr<TextureCore>* textures = (SPtr<TextureCore>*)(data + textureArrayOffset);
+		SPtr<TextureCore>* loadStoreTextures = (SPtr<TextureCore>*)(data + loadStoreTextureArrayOffset);
 		SPtr<SamplerStateCore>* samplers = (SPtr<SamplerStateCore>*)(data + samplerArrayOffset);
 
 		// Construct & copy
@@ -531,9 +571,6 @@ UINT32 GpuParamsBase::getDataParamSize(const String& name) const
 
 		for (UINT32 i = 0; i < mNumTextures; i++)
 		{
-			new (&textureInfos[i]) BoundTextureInfo();
-			textureInfos[i] = mTextureInfo[i];
-
 			new (&textures[i]) SPtr<TextureCore>();
 
 			if (mTextures[i].isLoaded())
@@ -542,6 +579,19 @@ UINT32 GpuParamsBase::getDataParamSize(const String& name) const
 				textures[i] = nullptr;
 		}
 
+		for (UINT32 i = 0; i < mNumLoadStoreTextures; i++)
+		{
+			new (&loadStoreSurfaces[i]) TextureSurface();
+			loadStoreSurfaces[i] = mLoadStoreSurfaces[i];
+
+			new (&loadStoreTextures[i]) SPtr<TextureCore>();
+
+			if (mLoadStoreTextures[i].isLoaded())
+				loadStoreTextures[i] = mLoadStoreTextures[i]->getCore();
+			else
+				loadStoreTextures[i] = nullptr;
+		}
+
 		for (UINT32 i = 0; i < mNumSamplerStates; i++)
 		{
 			new (&samplers[i]) SPtr<SamplerStateCore>();
@@ -562,5 +612,11 @@ UINT32 GpuParamsBase::getDataParamSize(const String& name) const
 			if (mTextures[i] != nullptr)
 				resources.push_back(mTextures[i]);
 		}
+
+		for (UINT32 i = 0; i < mNumLoadStoreTextures; i++)
+		{
+			if (mLoadStoreTextures[i] != nullptr)
+				resources.push_back(mLoadStoreTextures[i]);
+		}
 	}
 }

+ 7 - 1
Source/BansheeCore/Source/BsMaterial.cpp

@@ -148,6 +148,12 @@ namespace BansheeEngine
 				validParams.push_back(&iter2->second);
 			}
 
+			// Check load-store texture params
+			for (auto iter2 = curDesc.loadStoreTextures.begin(); iter2 != curDesc.loadStoreTextures.end(); ++iter2)
+			{
+				validParams.push_back(&iter2->second);
+			}
+
 			// Check buffer params
 			for (auto iter2 = curDesc.buffers.begin(); iter2 != curDesc.buffers.end(); ++iter2)
 			{
@@ -578,7 +584,7 @@ namespace BansheeEngine
 					GpuParamsType& paramPtr = params->getParamByIdx(i);
 					if (paramPtr)
 					{
-						if (paramPtr->hasTexture(gpuVarName))
+						if (paramPtr->hasLoadStoreTexture(gpuVarName))
 						{
 							gpuParams->push_back(TGpuParamLoadStoreTexture<Core>());
 							paramPtr->getLoadStoreTextureParam(gpuVarName, gpuParams->back());

+ 15 - 15
Source/BansheeCore/Source/BsRenderAPI.cpp

@@ -14,6 +14,7 @@
 #include "BsDepthStencilState.h"
 #include "BsRasterizerState.h"
 #include "BsGpuParamDesc.h"
+#include "BsShader.h"
 
 using namespace std::placeholders;
 
@@ -409,22 +410,21 @@ namespace BansheeEngine
 		{
 			SPtr<TextureCore> texture = params->getTexture(iter->second.slot);
 
-			if (!params->isLoadStoreTexture(iter->second.slot))
-			{
-				if (texture == nullptr)
-					setTexture(gptype, iter->second.slot, false, nullptr);
-				else
-					setTexture(gptype, iter->second.slot, true, texture);
-			}
+			if (texture == nullptr)
+				setTexture(gptype, iter->second.slot, false, nullptr);
 			else
-			{
-				const TextureSurface& surface = params->getLoadStoreSurface(iter->second.slot);
-
-				if (texture == nullptr)
-					setLoadStoreTexture(gptype, iter->second.slot, false, nullptr, surface);
-				else
-					setLoadStoreTexture(gptype, iter->second.slot, true, texture, surface);
-			}
+				setTexture(gptype, iter->second.slot, true, texture);
+		}
+
+		for (auto iter = paramDesc.loadStoreTextures.begin(); iter != paramDesc.loadStoreTextures.end(); ++iter)
+		{
+			SPtr<TextureCore> texture = params->getLoadStoreTexture(iter->second.slot);
+			const TextureSurface& surface = params->getLoadStoreSurface(iter->second.slot);
+
+			if (texture == nullptr)
+				setLoadStoreTexture(gptype, iter->second.slot, false, nullptr, surface);
+			else
+				setLoadStoreTexture(gptype, iter->second.slot, true, texture, surface);
 		}
 
 		setConstantBuffers(gptype, params);

+ 14 - 0
Source/BansheeCore/Source/BsShader.cpp

@@ -417,6 +417,20 @@ namespace BansheeEngine
 		}
 	}
 
+	bool Shader::isLoadStoreTexture(GpuParamObjectType type)
+	{
+		switch (type)
+		{
+		case GPOT_RWTEXTURE1D:
+		case GPOT_RWTEXTURE2D:
+		case GPOT_RWTEXTURE3D:
+		case GPOT_RWTEXTURE2DMS:
+			return true;
+		default:
+			return false;
+		}
+	}
+
 	bool Shader::isBuffer(GpuParamObjectType type)
 	{
 		switch(type)

+ 9 - 9
Source/BansheeD3D11RenderAPI/Source/BsD3D11HLSLParamParser.cpp

@@ -150,20 +150,20 @@ namespace BansheeEngine
 					switch (resourceDesc.Dimension)
 					{
 					case D3D_SRV_DIMENSION_TEXTURE1D:
-						memberDesc.type = GPOT_TEXTURE1D;
-						desc.textures.insert(std::make_pair(memberDesc.name, memberDesc));
+						memberDesc.type = GPOT_RWTEXTURE1D;
+						desc.loadStoreTextures.insert(std::make_pair(memberDesc.name, memberDesc));
 						break;
 					case D3D_SRV_DIMENSION_TEXTURE2D:
-						memberDesc.type = GPOT_TEXTURE2D;
-						desc.textures.insert(std::make_pair(memberDesc.name, memberDesc));
+						memberDesc.type = GPOT_RWTEXTURE2D;
+						desc.loadStoreTextures.insert(std::make_pair(memberDesc.name, memberDesc));
 						break;
 					case D3D_SRV_DIMENSION_TEXTURE3D:
-						memberDesc.type = GPOT_TEXTURE3D;
-						desc.textures.insert(std::make_pair(memberDesc.name, memberDesc));
+						memberDesc.type = GPOT_RWTEXTURE3D;
+						desc.loadStoreTextures.insert(std::make_pair(memberDesc.name, memberDesc));
 						break;
-					case D3D_SRV_DIMENSION_TEXTURECUBE:
-						memberDesc.type = GPOT_TEXTURECUBE;
-						desc.textures.insert(std::make_pair(memberDesc.name, memberDesc));
+					case D3D_SRV_DIMENSION_TEXTURE2DMS:
+						memberDesc.type = GPOT_RWTEXTURE2DMS;
+						desc.loadStoreTextures.insert(std::make_pair(memberDesc.name, memberDesc));
 						break;
 					case D3D_SRV_DIMENSION_BUFFER:
 						memberDesc.type = GPOT_RWTYPED_BUFFER;

+ 0 - 3
Source/BansheeD3D11RenderAPI/Source/BsD3D11RenderAPI.cpp

@@ -318,9 +318,6 @@ namespace BansheeEngine
 	{
 		THROW_IF_NOT_CORE_THREAD;
 
-		// TODO - This hasn't bee tested and might be incorrect. I might need to set UAVs together with render targets,
-		// especially considering DX11 expects number of UAVs to match number of render targets.
-
 		ID3D11UnorderedAccessView* viewArray[1];
 		if (texPtr != nullptr && enabled)
 		{

+ 14 - 14
Source/BansheeEngine/Source/BsRendererUtility.cpp

@@ -13,6 +13,7 @@
 #include "BsGpuParamDesc.h"
 #include "BsShapeMeshes3D.h"
 #include "BsLight.h"
+#include "BsShader.h"
 
 namespace BansheeEngine
 {
@@ -248,22 +249,21 @@ namespace BansheeEngine
 			{
 				SPtr<TextureCore> texture = params->getTexture(iter->second.slot);
 
-				if (!params->isLoadStoreTexture(iter->second.slot))
-				{
-					if (texture == nullptr)
-						rs.setTexture(stage.type, iter->second.slot, false, nullptr);
-					else
-						rs.setTexture(stage.type, iter->second.slot, true, texture);
-				}
+				if (texture == nullptr)
+					rs.setTexture(stage.type, iter->second.slot, false, nullptr);
 				else
-				{
-					const TextureSurface& surface = params->getLoadStoreSurface(iter->second.slot);
+					rs.setTexture(stage.type, iter->second.slot, true, texture);
+			}
 
-					if (texture == nullptr)
-						rs.setLoadStoreTexture(stage.type, iter->second.slot, false, nullptr, surface);
-					else
-						rs.setLoadStoreTexture(stage.type, iter->second.slot, true, texture, surface);
-				}
+			for (auto iter = paramDesc.loadStoreTextures.begin(); iter != paramDesc.loadStoreTextures.end(); ++iter)
+			{
+				SPtr<TextureCore> texture = params->getLoadStoreTexture(iter->second.slot);
+				const TextureSurface& surface = params->getLoadStoreSurface(iter->second.slot);
+
+				if (texture == nullptr)
+					rs.setLoadStoreTexture(stage.type, iter->second.slot, false, nullptr, surface);
+				else
+					rs.setLoadStoreTexture(stage.type, iter->second.slot, true, texture, surface);
 			}
 
 			rs.setConstantBuffers(stage.type, params);

+ 7 - 4
Source/BansheeGLRenderAPI/Source/BsGLSLParamParser.cpp

@@ -330,17 +330,20 @@ namespace BansheeEngine
 				switch (uniformType)
 				{
 				case GL_IMAGE_1D:
-					textureParam.type = GPOT_TEXTURE1D;
+					textureParam.type = GPOT_RWTEXTURE1D;
 					break;
 				case GL_IMAGE_2D:
-					textureParam.type = GPOT_TEXTURE2D;
+					textureParam.type = GPOT_RWTEXTURE2D;
 					break;
 				case GL_IMAGE_3D:
-					textureParam.type = GPOT_TEXTURE3D;
+					textureParam.type = GPOT_RWTEXTURE3D;
+					break;
+				case GL_IMAGE_2D_MULTISAMPLE:
+					textureParam.type = GPOT_RWTEXTURE2DMS;
 					break;
 				}
 
-				returnParamDesc.textures.insert(std::make_pair(paramName, textureParam));
+				returnParamDesc.loadStoreTextures.insert(std::make_pair(paramName, textureParam));
 			}
 			else
 			{

+ 8 - 3
Source/BansheeSL/BsLexerFX.l

@@ -82,12 +82,17 @@ Texture3D		{ yylval->intValue = PT_Texture3D; return TOKEN_TEXTURE3D; }
 TextureCUBE		{ yylval->intValue = PT_TextureCUBE; return TOKEN_TEXTURECUBE; } 
 Texture2DMS		{ yylval->intValue = PT_Texture2DMS; return TOKEN_TEXTURE2DMS; }
 
+RWTexture1D		{ yylval->intValue = PT_RWTexture1D; return TOKEN_RWTEXTURE1D; } 
+RWTexture2D		{ yylval->intValue = PT_RWTexture2D; return TOKEN_RWTEXTURE2D; } 
+RWTexture3D		{ yylval->intValue = PT_RWTexture3D; return TOKEN_RWTEXTURE3D; } 
+RWTexture2DMS	{ yylval->intValue = PT_RWTexture2DMS; return TOKEN_RWTEXTURE2DMS; }
+
 ByteBuffer		{ yylval->intValue = PT_ByteBuffer; return TOKEN_BYTEBUFFER; } 
 StructBuffer	{ yylval->intValue = PT_StructBuffer; return TOKEN_STRUCTBUFFER; } 
 
-TypedBufferRW	{ yylval->intValue = PT_TypedBufferRW; return TOKEN_RWTYPEDBUFFER; } 
-ByteBufferRW	{ yylval->intValue = PT_ByteBufferRW; return TOKEN_RWBYTEBUFFER; }
-StructBufferRW	{ yylval->intValue = PT_StructBufferRW; return TOKEN_RWSTRUCTBUFFER; } 
+RWTypedBuffer	{ yylval->intValue = PT_TypedBufferRW; return TOKEN_RWTYPEDBUFFER; } 
+RWByteBuffer	{ yylval->intValue = PT_ByteBufferRW; return TOKEN_RWBYTEBUFFER; }
+RWStructBuffer	{ yylval->intValue = PT_StructBufferRW; return TOKEN_RWSTRUCTBUFFER; } 
 AppendBuffer	{ yylval->intValue = PT_AppendBuffer; return TOKEN_RWAPPENDBUFFER; } 
 ConsumeBuffer	{ yylval->intValue = PT_ConsumeBuffer; return TOKEN_RWCONSUMEBUFFER; }
 

+ 14 - 5
Source/BansheeSL/BsParserFX.y

@@ -132,6 +132,11 @@ typedef struct YYLTYPE {
 %token <intValue> TOKEN_TEXTURECUBE 
 %token <intValue> TOKEN_TEXTURE2DMS
 
+%token <intValue> TOKEN_RWTEXTURE1D 
+%token <intValue> TOKEN_RWTEXTURE2D 
+%token <intValue> TOKEN_RWTEXTURE3D 
+%token <intValue> TOKEN_RWTEXTURE2DMS
+
 %token <intValue> TOKEN_BYTEBUFFER 
 %token <intValue> TOKEN_STRUCTBUFFER 
 %token <intValue> TOKEN_RWTYPEDBUFFER 
@@ -811,11 +816,11 @@ param_header_mat4x4
 	;
 
 param_header_sampler
-	: TOKEN_SAMPLER1D TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_SAMPLER2D TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_SAMPLER3D TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_SAMPLERCUBE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_SAMPLER2DMS TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	: TOKEN_SAMPLER1D		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_SAMPLER2D		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_SAMPLER3D		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_SAMPLERCUBE		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_SAMPLER2DMS		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
 	;
 
 param_header_texture
@@ -824,6 +829,10 @@ param_header_texture
 	| TOKEN_TEXTURE3D		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
 	| TOKEN_TEXTURECUBE		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
 	| TOKEN_TEXTURE2DMS		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_RWTEXTURE1D		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_RWTEXTURE2D		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_RWTEXTURE3D		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_RWTEXTURE2DMS	TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
 	;
 
 param_header_buffer

+ 1 - 0
Source/BansheeSL/Include/BsASTFX.h

@@ -119,6 +119,7 @@ enum tagParamType
 	PT_Mat4x2, PT_Mat4x3, PT_Mat4x4,
 	PT_Sampler1D, PT_Sampler2D, PT_Sampler3D, PT_SamplerCUBE, PT_Sampler2DMS,
 	PT_Texture1D, PT_Texture2D, PT_Texture3D, PT_TextureCUBE, PT_Texture2DMS,
+	PT_RWTexture1D, PT_RWTexture2D, PT_RWTexture3D, PT_RWTexture2DMS,
 	PT_ByteBuffer, PT_StructBuffer, PT_ByteBufferRW, PT_StructBufferRW,
 	PT_TypedBufferRW, PT_AppendBuffer, PT_ConsumeBuffer,
 	PT_Count // Keep at end

+ 1 - 1
Source/BansheeSL/Include/BsLexerFX.h

@@ -349,7 +349,7 @@ extern int yylex \
 #undef YY_DECL
 #endif
 
-#line 390 "..\\..\\Source\\BansheeSL\\BsLexerFX.l"
+#line 395 "..\\..\\Source\\BansheeSL\\BsLexerFX.l"
 
 
 #line 356 "BsLexerFX.h"

+ 76 - 72
Source/BansheeSL/Include/BsParserFX.h

@@ -148,77 +148,81 @@ typedef struct YYLTYPE {
      TOKEN_TEXTURE3D = 298,
      TOKEN_TEXTURECUBE = 299,
      TOKEN_TEXTURE2DMS = 300,
-     TOKEN_BYTEBUFFER = 301,
-     TOKEN_STRUCTBUFFER = 302,
-     TOKEN_RWTYPEDBUFFER = 303,
-     TOKEN_RWBYTEBUFFER = 304,
-     TOKEN_RWSTRUCTBUFFER = 305,
-     TOKEN_RWAPPENDBUFFER = 306,
-     TOKEN_RWCONSUMEBUFFER = 307,
-     TOKEN_PARAMSBLOCK = 308,
-     TOKEN_AUTO = 309,
-     TOKEN_ALIAS = 310,
-     TOKEN_SHARED = 311,
-     TOKEN_USAGE = 312,
-     TOKEN_SEPARABLE = 313,
-     TOKEN_SORT = 314,
-     TOKEN_PRIORITY = 315,
-     TOKEN_TRANSPARENT = 316,
-     TOKEN_PARAMETERS = 317,
-     TOKEN_BLOCKS = 318,
-     TOKEN_TECHNIQUE = 319,
-     TOKEN_RENDERER = 320,
-     TOKEN_LANGUAGE = 321,
-     TOKEN_PASS = 322,
-     TOKEN_VERTEX = 323,
-     TOKEN_FRAGMENT = 324,
-     TOKEN_GEOMETRY = 325,
-     TOKEN_HULL = 326,
-     TOKEN_DOMAIN = 327,
-     TOKEN_COMPUTE = 328,
-     TOKEN_COMMON = 329,
-     TOKEN_STENCILREF = 330,
-     TOKEN_FILLMODE = 331,
-     TOKEN_CULLMODE = 332,
-     TOKEN_DEPTHBIAS = 333,
-     TOKEN_SDEPTHBIAS = 334,
-     TOKEN_DEPTHCLIP = 335,
-     TOKEN_SCISSOR = 336,
-     TOKEN_MULTISAMPLE = 337,
-     TOKEN_AALINE = 338,
-     TOKEN_DEPTHREAD = 339,
-     TOKEN_DEPTHWRITE = 340,
-     TOKEN_COMPAREFUNC = 341,
-     TOKEN_STENCIL = 342,
-     TOKEN_STENCILREADMASK = 343,
-     TOKEN_STENCILWRITEMASK = 344,
-     TOKEN_STENCILOPFRONT = 345,
-     TOKEN_STENCILOPBACK = 346,
-     TOKEN_FAIL = 347,
-     TOKEN_ZFAIL = 348,
-     TOKEN_ALPHATOCOVERAGE = 349,
-     TOKEN_INDEPENDANTBLEND = 350,
-     TOKEN_TARGET = 351,
-     TOKEN_INDEX = 352,
-     TOKEN_BLEND = 353,
-     TOKEN_COLOR = 354,
-     TOKEN_ALPHA = 355,
-     TOKEN_WRITEMASK = 356,
-     TOKEN_SOURCE = 357,
-     TOKEN_DEST = 358,
-     TOKEN_OP = 359,
-     TOKEN_ADDRMODE = 360,
-     TOKEN_MINFILTER = 361,
-     TOKEN_MAGFILTER = 362,
-     TOKEN_MIPFILTER = 363,
-     TOKEN_MAXANISO = 364,
-     TOKEN_MIPBIAS = 365,
-     TOKEN_MIPMIN = 366,
-     TOKEN_MIPMAX = 367,
-     TOKEN_BORDERCOLOR = 368,
-     TOKEN_U = 369,
-     TOKEN_V = 370,
-     TOKEN_W = 371
+     TOKEN_RWTEXTURE1D = 301,
+     TOKEN_RWTEXTURE2D = 302,
+     TOKEN_RWTEXTURE3D = 303,
+     TOKEN_RWTEXTURE2DMS = 304,
+     TOKEN_BYTEBUFFER = 305,
+     TOKEN_STRUCTBUFFER = 306,
+     TOKEN_RWTYPEDBUFFER = 307,
+     TOKEN_RWBYTEBUFFER = 308,
+     TOKEN_RWSTRUCTBUFFER = 309,
+     TOKEN_RWAPPENDBUFFER = 310,
+     TOKEN_RWCONSUMEBUFFER = 311,
+     TOKEN_PARAMSBLOCK = 312,
+     TOKEN_AUTO = 313,
+     TOKEN_ALIAS = 314,
+     TOKEN_SHARED = 315,
+     TOKEN_USAGE = 316,
+     TOKEN_SEPARABLE = 317,
+     TOKEN_SORT = 318,
+     TOKEN_PRIORITY = 319,
+     TOKEN_TRANSPARENT = 320,
+     TOKEN_PARAMETERS = 321,
+     TOKEN_BLOCKS = 322,
+     TOKEN_TECHNIQUE = 323,
+     TOKEN_RENDERER = 324,
+     TOKEN_LANGUAGE = 325,
+     TOKEN_PASS = 326,
+     TOKEN_VERTEX = 327,
+     TOKEN_FRAGMENT = 328,
+     TOKEN_GEOMETRY = 329,
+     TOKEN_HULL = 330,
+     TOKEN_DOMAIN = 331,
+     TOKEN_COMPUTE = 332,
+     TOKEN_COMMON = 333,
+     TOKEN_STENCILREF = 334,
+     TOKEN_FILLMODE = 335,
+     TOKEN_CULLMODE = 336,
+     TOKEN_DEPTHBIAS = 337,
+     TOKEN_SDEPTHBIAS = 338,
+     TOKEN_DEPTHCLIP = 339,
+     TOKEN_SCISSOR = 340,
+     TOKEN_MULTISAMPLE = 341,
+     TOKEN_AALINE = 342,
+     TOKEN_DEPTHREAD = 343,
+     TOKEN_DEPTHWRITE = 344,
+     TOKEN_COMPAREFUNC = 345,
+     TOKEN_STENCIL = 346,
+     TOKEN_STENCILREADMASK = 347,
+     TOKEN_STENCILWRITEMASK = 348,
+     TOKEN_STENCILOPFRONT = 349,
+     TOKEN_STENCILOPBACK = 350,
+     TOKEN_FAIL = 351,
+     TOKEN_ZFAIL = 352,
+     TOKEN_ALPHATOCOVERAGE = 353,
+     TOKEN_INDEPENDANTBLEND = 354,
+     TOKEN_TARGET = 355,
+     TOKEN_INDEX = 356,
+     TOKEN_BLEND = 357,
+     TOKEN_COLOR = 358,
+     TOKEN_ALPHA = 359,
+     TOKEN_WRITEMASK = 360,
+     TOKEN_SOURCE = 361,
+     TOKEN_DEST = 362,
+     TOKEN_OP = 363,
+     TOKEN_ADDRMODE = 364,
+     TOKEN_MINFILTER = 365,
+     TOKEN_MAGFILTER = 366,
+     TOKEN_MIPFILTER = 367,
+     TOKEN_MAXANISO = 368,
+     TOKEN_MIPBIAS = 369,
+     TOKEN_MIPMIN = 370,
+     TOKEN_MIPMAX = 371,
+     TOKEN_BORDERCOLOR = 372,
+     TOKEN_U = 373,
+     TOKEN_V = 374,
+     TOKEN_W = 375
    };
 #endif
 
@@ -238,7 +242,7 @@ typedef union YYSTYPE
 
 
 /* Line 2579 of glr.c  */
-#line 242 "BsParserFX.h"
+#line 246 "BsParserFX.h"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 530 - 511
Source/BansheeSL/Source/BsLexerFX.c


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 517 - 508
Source/BansheeSL/Source/BsParserFX.c


+ 5 - 0
Source/BansheeSL/Source/BsSLFXCompiler.cpp

@@ -446,6 +446,11 @@ namespace BansheeEngine
 			lookup[PT_TextureCUBE] = { GPOT_TEXTURECUBE, true };
 			lookup[PT_Texture2DMS] = { GPOT_TEXTURE2DMS, true };
 
+			lookup[PT_RWTexture1D] = { GPOT_RWTEXTURE1D, true };
+			lookup[PT_RWTexture2D] = { GPOT_RWTEXTURE2D, true };
+			lookup[PT_RWTexture3D] = { GPOT_RWTEXTURE3D, true };
+			lookup[PT_RWTexture2DMS] = { GPOT_RWTEXTURE2DMS, true };
+
 			lookup[PT_ByteBuffer] = { GPOT_BYTE_BUFFER, true };
 			lookup[PT_StructBuffer] = { GPOT_STRUCTURED_BUFFER, true };
 			lookup[PT_TypedBufferRW] = { GPOT_RWTYPED_BUFFER, true };

+ 13 - 14
Source/RenderBeast/Source/BsRenderBeast.cpp

@@ -1067,22 +1067,21 @@ namespace BansheeEngine
 			{
 				SPtr<TextureCore> texture = params->getTexture(iter->second.slot);
 
-				if (!params->isLoadStoreTexture(iter->second.slot))
-				{
-					if (texture == nullptr)
-						rs.setTexture(stage.type, iter->second.slot, false, nullptr);
-					else
-						rs.setTexture(stage.type, iter->second.slot, true, texture);
-				}
+				if (texture == nullptr)
+					rs.setTexture(stage.type, iter->second.slot, false, nullptr);
 				else
-				{
-					const TextureSurface& surface = params->getLoadStoreSurface(iter->second.slot);
+					rs.setTexture(stage.type, iter->second.slot, true, texture);
+			}
 
-					if (texture == nullptr)
-						rs.setLoadStoreTexture(stage.type, iter->second.slot, false, nullptr, surface);
-					else
-						rs.setLoadStoreTexture(stage.type, iter->second.slot, true, texture, surface);
-				}
+			for (auto iter = paramDesc.loadStoreTextures.begin(); iter != paramDesc.loadStoreTextures.end(); ++iter)
+			{
+				SPtr<TextureCore> texture = params->getLoadStoreTexture(iter->second.slot);
+				const TextureSurface& surface = params->getLoadStoreSurface(iter->second.slot);
+
+				if (texture == nullptr)
+					rs.setLoadStoreTexture(stage.type, iter->second.slot, false, nullptr, surface);
+				else
+					rs.setLoadStoreTexture(stage.type, iter->second.slot, true, texture, surface);
 			}
 
 			rs.setConstantBuffers(stage.type, params);

Vissa filer visades inte eftersom för många filer har ändrats