Browse Source

Refactored GUI so it generates all of it's GPU param buffers before rendering, instead of updating them before every draw call
Fixed OpenGL GPU param unit binding assigments

BearishSun 9 years ago
parent
commit
23561ee03b

+ 47 - 38
Data/Raw/Engine/Includes/SpriteImage.bslinc

@@ -1,13 +1,17 @@
 Parameters =
 {
-	mat4x4 	worldTransform;
-	float	invViewportWidth;
-	float	invViewportHeight;
+	mat4x4 	gWorldTransform;
+	float	gInvViewportWidth;
+	float	gInvViewportHeight;
+	color	gTint;
 	
-	Sampler2D	mainTexSamp : alias("mainTexture");
-	Texture2D	mainTexture;
-	
-	color		tint;
+	Sampler2D	gMainTexSamp : alias("gMainTexture");
+	Texture2D	gMainTexture;
+};
+
+Blocks = 
+{
+	Block GUIParams : auto("GUIParams");
 };
 
 Technique : base("SpriteImage") =
@@ -19,22 +23,29 @@ Technique : base("SpriteImage") =
 		DepthRead = false;
 		DepthWrite = false;
 		
+		Common =
+		{
+			cbuffer GUIParams
+			{
+				float4x4 gWorldTransform;
+				float gInvViewportWidth;
+				float gInvViewportHeight;
+				float4 gTint;
+			}	
+		};
+		
 		Vertex =
 		{
-			float invViewportWidth;
-			float invViewportHeight;
-			float4x4 worldTransform;
-
 			void main(
 				in float3 inPos : POSITION,
 				in float2 uv : TEXCOORD0,
 				out float4 oPosition : SV_Position,
 				out float2 oUv : TEXCOORD0)
 			{
-				float4 tfrmdPos = mul(worldTransform, float4(inPos.xy, 0, 1));
+				float4 tfrmdPos = mul(gWorldTransform, float4(inPos.xy, 0, 1));
 
-				float tfrmdX = -1.0f + (tfrmdPos.x * invViewportWidth);
-				float tfrmdY = 1.0f - (tfrmdPos.y * invViewportHeight);
+				float tfrmdX = -1.0f + (tfrmdPos.x * gInvViewportWidth);
+				float tfrmdY = 1.0f - (tfrmdPos.y * gInvViewportHeight);
 
 				oPosition = float4(tfrmdX, tfrmdY, 0, 1);
 				oUv = uv;
@@ -43,14 +54,13 @@ Technique : base("SpriteImage") =
 		
 		Fragment =
 		{
-			SamplerState mainTexSamp : register(s0);
-			Texture2D mainTexture : register(t0);
-			float4 tint;
-
+			SamplerState gMainTexSamp : register(s0);
+			Texture2D gMainTexture : register(t0);
+			
 			float4 main(in float4 inPos : SV_Position, float2 uv : TEXCOORD0) : SV_Target
 			{
-				float4 color = mainTexture.Sample(mainTexSamp, uv);
-				return color * tint;
+				float4 color = gMainTexture.Sample(gMainTexSamp, uv);
+				return color * gTint;
 			}
 		};
 	};
@@ -65,15 +75,19 @@ Technique : base("SpriteImage") =
 		DepthRead = false;
 		DepthWrite = false;
 		
-		Vertex =
+		Common =
 		{
-			layout (binding = 0) uniform VertUBO
+			layout (binding = 0, std140) uniform GUIParams
 			{
-				float invViewportWidth;
-				float invViewportHeight;
-				mat4 worldTransform;
-			};
-			
+				mat4 gWorldTransform;
+				float gInvViewportWidth;
+				float gInvViewportHeight;
+				vec4 gTint;
+			};			
+		};		
+		
+		Vertex =
+		{
 			layout (location = 0) in vec3 bs_position;
 			layout (location = 1) in vec2 bs_texcoord0;
 			
@@ -86,10 +100,10 @@ Technique : base("SpriteImage") =
 			
 			void main()
 			{
-				vec4 tfrmdPos = worldTransform * vec4(bs_position.xy, 0, 1);
+				vec4 tfrmdPos = gWorldTransform * vec4(bs_position.xy, 0, 1);
 
-				float tfrmdX = -1.0f + (tfrmdPos.x * invViewportWidth);
-				float tfrmdY = 1.0f - (tfrmdPos.y * invViewportHeight);	
+				float tfrmdX = -1.0f + (tfrmdPos.x * gInvViewportWidth);
+				float tfrmdY = 1.0f - (tfrmdPos.y * gInvViewportHeight);	
 
 				gl_Position = vec4(tfrmdX, tfrmdY, 0, 1);
 				texcoord0 = bs_texcoord0;
@@ -98,20 +112,15 @@ Technique : base("SpriteImage") =
 		
 		Fragment =
 		{
-			layout (binding = 1) uniform FragUBO
-			{
-				vec4 tint;
-			};
-			
-			layout (binding = 2) uniform sampler2D mainTexture;
+			layout (binding = 1) uniform sampler2D gMainTexture;
 			
 			layout (location = 0) in vec2 texcoord0;
 			layout (location = 0) out vec4 fragColor;
 
 			void main()
 			{
-				vec4 color = texture2D(mainTexture, texcoord0.st);
-				fragColor = color * tint;
+				vec4 color = texture2D(gMainTexture, texcoord0.st);
+				fragColor = color * gTint;
 			}
 		};
 	};

+ 44 - 35
Data/Raw/Engine/Shaders/SpriteText.bsl

@@ -1,13 +1,17 @@
 Parameters =
 {
-	mat4x4 	worldTransform;
-	float	invViewportWidth;
-	float	invViewportHeight;
+	mat4x4 	gWorldTransform;
+	float	gInvViewportWidth;
+	float	gInvViewportHeight;
+	color	gTint;
 	
-	Sampler2D	mainTexSamp : alias("mainTexture");
-	Texture2D	mainTexture;
-	
-	color		tint;
+	Sampler2D	gMainTexSamp : alias("gMainTexture");
+	Texture2D	gMainTexture;
+};
+
+Blocks = 
+{
+	Block GUIParams : auto("GUIParams");
 };
 
 Technique =
@@ -26,22 +30,29 @@ Technique =
 		DepthRead = false;
 		DepthWrite = false;
 		
+		Common =
+		{
+			cbuffer GUIParams
+			{
+				float4x4 gWorldTransform;
+				float gInvViewportWidth;
+				float gInvViewportHeight;
+				float4 gTint;
+			}	
+		};
+		
 		Vertex =
 		{
-			float invViewportWidth;
-			float invViewportHeight;
-			float4x4 worldTransform;
-
 			void main(
 				in float3 inPos : POSITION,
 				in float2 uv : TEXCOORD0,
 				out float4 oPosition : SV_Position,
 				out float2 oUv : TEXCOORD0)
 			{
-				float4 tfrmdPos = mul(worldTransform, float4(inPos.xy, 0, 1));
+				float4 tfrmdPos = mul(gWorldTransform, float4(inPos.xy, 0, 1));
 
-				float tfrmdX = -1.0f + (tfrmdPos.x * invViewportWidth);
-				float tfrmdY = 1.0f - (tfrmdPos.y * invViewportHeight);
+				float tfrmdX = -1.0f + (tfrmdPos.x * gInvViewportWidth);
+				float tfrmdY = 1.0f - (tfrmdPos.y * gInvViewportHeight);
 
 				oPosition = float4(tfrmdX, tfrmdY, 0, 1);
 				oUv = uv;
@@ -50,13 +61,12 @@ Technique =
 		
 		Fragment =
 		{
-			SamplerState mainTexSamp : register(s0);
-			Texture2D mainTexture : register(t0);
-			float4 tint;
+			SamplerState gMainTexSamp : register(s0);
+			Texture2D gMainTexture : register(t0);
 
 			float4 main(in float4 inPos : SV_Position, float2 uv : TEXCOORD0) : SV_Target
 			{
-				float4 color = float4(tint.rgb, mainTexture.Sample(mainTexSamp, uv).r * tint.a);
+				float4 color = float4(gTint.rgb, gMainTexture.Sample(gMainTexSamp, uv).r * gTint.a);
 				return color;
 			}
 		};
@@ -79,15 +89,19 @@ Technique =
 		DepthRead = false;
 		DepthWrite = false;
 		
-		Vertex =
+		Common =
 		{
-			layout (binding = 0) uniform VertUBO
+			layout (binding = 0, std140) uniform GUIParams
 			{
-				float invViewportWidth;
-				float invViewportHeight;
-				mat4 worldTransform;
-			};
-
+				mat4 gWorldTransform;
+				float gInvViewportWidth;
+				float gInvViewportHeight;
+				vec4 gTint;
+			};			
+		};			
+		
+		Vertex =
+		{
 			layout (location = 0) in vec3 bs_position;
 			layout (location = 1) in vec2 bs_texcoord0;
 			
@@ -100,10 +114,10 @@ Technique =
 			
 			void main()
 			{
-				vec4 tfrmdPos = worldTransform * vec4(bs_position.xy, 0, 1);
+				vec4 tfrmdPos = gWorldTransform * vec4(bs_position.xy, 0, 1);
 
-				float tfrmdX = -1.0f + (tfrmdPos.x * invViewportWidth);
-				float tfrmdY = 1.0f - (tfrmdPos.y * invViewportHeight);
+				float tfrmdX = -1.0f + (tfrmdPos.x * gInvViewportWidth);
+				float tfrmdY = 1.0f - (tfrmdPos.y * gInvViewportHeight);
 
 				gl_Position = vec4(tfrmdX, tfrmdY, 0, 1);
 				texcoord0 = bs_texcoord0;
@@ -112,19 +126,14 @@ Technique =
 		
 		Fragment =
 		{
-			layout (binding = 1) uniform FragUBO
-			{
-				vec4 tint;
-			};		
-		
-			layout (binding = 2) uniform sampler2D mainTexture;
+			layout (binding = 1) uniform sampler2D gMainTexture;
 			
 			layout (location = 0) in vec2 texcoord0;
 			layout (location = 0) out vec4 fragColor;
 
 			void main()
 			{
-				vec4 color = vec4(tint.rgb, texture2D(mainTexture, texcoord0.st).r * tint.a);
+				vec4 color = vec4(gTint.rgb, texture2D(gMainTexture, texcoord0.st).r * gTint.a);
 				fragColor = color;
 			}
 		};

+ 8 - 0
Source/BansheeCore/Include/BsParamBlocks.h

@@ -15,6 +15,9 @@ namespace bs
 	 *  @{
 	 */
 
+// Note: Every time one of these param blocks is instantiated we generate its descriptor. It would be better to generate
+// it once, and then just quickly instantiate for subsequent creations.
+
 /**
  * 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
@@ -46,6 +49,11 @@ namespace bs
 		}																													\
 																															\
 		const SPtr<GpuParamBlockBufferCore>& getBuffer() const { return mBuffer; }											\
+		void setBuffer(const SPtr<GpuParamBlockBufferCore>& buffer)															\
+		{																													\
+				mBuffer = buffer;																							\
+				mParams->setParamBlockBuffer(GPT_VERTEX_PROGRAM, #Name, mBuffer);											\
+		}																													\
 		const GpuParamBlockDesc& getDesc() const { return mBlockDesc; }														\
 		void flushToGPU(UINT32 queueIdx = 0) { mBuffer->flushToGPU(queueIdx); }												\
 																															\

+ 12 - 2
Source/BansheeEngine/Include/BsGUIManager.h

@@ -13,6 +13,7 @@
 #include "BsMatrix4.h"
 #include "BsEvent.h"
 #include "BsMaterialParam.h"
+#include "BsParamBlocks.h"
 
 namespace bs
 {
@@ -77,6 +78,7 @@ namespace bs
 			Color tint;
 			Matrix4 worldTransform;
 			SPtr<SpriteMaterialExtraInfo> additionalData;
+			UINT32 bufferIdx;
 		};
 
 		/**	Container for a GUI widget. */
@@ -419,6 +421,13 @@ namespace bs
 		HEvent mMouseLeftWindowConn;
 	};
 
+	BS_PARAM_BLOCK_BEGIN(GUISpriteParamBuffer)
+		BS_PARAM_BLOCK_ENTRY(Matrix4, gWorldTransform)
+		BS_PARAM_BLOCK_ENTRY(float, gInvViewportWidth)
+		BS_PARAM_BLOCK_ENTRY(float, gInvViewportHeight)
+		BS_PARAM_BLOCK_ENTRY(Color, gTint)
+	BS_PARAM_BLOCK_END
+
 	/**	Handles GUI rendering on the core thread. */
 	class BS_EXPORT GUIManagerCore
 	{
@@ -434,7 +443,7 @@ namespace bs
 		/**
 		 * Updates the internal data that determines what will be rendered on the next render() call.
 		 *
-		 * @param[in]	data	GUI mesh/material per viewport.
+		 * @param[in]	perCameraData	GUI mesh/material per viewport.
 		 */
 		void updateData(const UnorderedMap<SPtr<CameraCore>, Vector<GUIManager::GUICoreRenderData>>& perCameraData);
 
@@ -442,6 +451,7 @@ namespace bs
 		void render(const SPtr<CameraCore>& camera);
 
 		UnorderedMap<SPtr<CameraCore>, Vector<GUIManager::GUICoreRenderData>> mPerCameraData;
+		Vector<GUISpriteParamBuffer*> mParamBlocks;
 		SPtr<SamplerStateCore> mSamplerState;
 	};
 
@@ -449,4 +459,4 @@ namespace bs
 	BS_EXPORT GUIManager& gGUIManager();
 
 	/** @} */
-}
+}

+ 4 - 9
Source/BansheeEngine/Include/BsSpriteMaterial.h

@@ -89,14 +89,12 @@ namespace bs
 		 * @param[in]	mesh			Mesh to render, containing vertices in screen space.
 		 * @param[in]	texture			Optional texture to render the mesh with.
 		 * @param[in]	sampler			Optional sampler to render the texture with.
-		 * @param[in]	tint			Color tint to apply to the rendered mesh.
-		 * @param[in]	worldTransform	World transform to apply to the rendered mesh.
-		 * @param[in]	invViewportSize	Inverse size of the viewport the mesh will be rendered to.
+		 * @param[in]	paramBuffer		Buffer containing data GPU parameters.
 		 * @param[in]	additionalData	Optional additional data that might be required by the renderer.
 		 */
 		virtual void render(const SPtr<MeshCoreBase>& mesh, const SPtr<TextureCore>& texture,
-			const SPtr<SamplerStateCore>& sampler, const Color& tint, const Matrix4& worldTransform, 
-			const Vector2& invViewportSize, const SPtr<SpriteMaterialExtraInfo>& additionalData) const;
+			const SPtr<SamplerStateCore>& sampler, const SPtr<GpuParamBlockBufferCore>& paramBuffer, 
+			const SPtr<SpriteMaterialExtraInfo>& additionalData) const;
 
 	protected:
 		/** Perform initialization of core-thread specific objects. */
@@ -112,10 +110,7 @@ namespace bs
 		std::atomic<bool> mMaterialStored;
 
 		SPtr<GpuParamsSetCore> mParams;
-		mutable MaterialParamMat4Core mWorldTransformParam;
-		mutable MaterialParamFloatCore mInvViewportWidthParam;
-		mutable MaterialParamFloatCore mInvViewportHeightParam;
-		mutable MaterialParamColorCore mTintParam;
+		UINT32 mParamBufferIdx;
 		mutable MaterialParamTextureCore mTextureParam;
 		mutable MaterialParamSampStateCore mSamplerParam;
 	};

+ 46 - 3
Source/BansheeEngine/Source/BsGUIManager.cpp

@@ -1743,6 +1743,9 @@ namespace bs
 		SPtr<CoreRenderer> activeRenderer = RendererManager::instance().getActive();
 		for (auto& cameraData : mPerCameraData)
 			activeRenderer->unregisterRenderCallback(cameraData.first.get(), 30);
+
+		for(auto& entry : mParamBlocks)
+			bs_delete(entry);
 	}
 
 	void GUIManagerCore::initialize()
@@ -1760,6 +1763,7 @@ namespace bs
 		bs_frame_mark();
 
 		{
+			// Assign new per camera data, and find if any cameras were added or removed
 			FrameSet<SPtr<CameraCore>> validCameras;
 
 			SPtr<CoreRenderer> activeRenderer = RendererManager::instance().getActive();
@@ -1806,6 +1810,35 @@ namespace bs
 				activeRenderer->unregisterRenderCallback(camera.get(), 30);
 				mPerCameraData.erase(camera);
 			}
+
+			// Allocate GPU buffers containing the material parameters
+			UINT32 numBuffers = 0;
+			for (auto& cameraData : mPerCameraData)
+				numBuffers += (UINT32)cameraData.second.size();
+
+			UINT32 numAllocatedBuffers = (UINT32)mParamBlocks.size();
+			if (numBuffers > numAllocatedBuffers)
+			{
+				mParamBlocks.resize(numBuffers);
+
+				for (UINT32 i = numAllocatedBuffers; i < numBuffers; i++)
+					mParamBlocks[i] = bs_new<GUISpriteParamBuffer>();
+			}
+
+			UINT32 curBufferIdx = 0;
+			for (auto& cameraData : mPerCameraData)
+			{
+				for(auto& entry : cameraData.second)
+				{
+					GUISpriteParamBuffer* buffer = mParamBlocks[curBufferIdx];
+
+					buffer->gTint.set(entry.tint);
+					buffer->gWorldTransform.set(entry.worldTransform);
+
+					entry.bufferIdx = curBufferIdx;
+					curBufferIdx++;
+				}
+			}
 		}
 
 		bs_frame_clear();
@@ -1818,14 +1851,24 @@ namespace bs
 		float invViewportWidth = 1.0f / (camera->getViewport()->getWidth() * 0.5f);
 		float invViewportHeight = 1.0f / (camera->getViewport()->getHeight() * 0.5f);
 
-		Vector2 invViewportSize(invViewportWidth, invViewportHeight);
+		for (auto& entry : renderData)
+		{
+			GUISpriteParamBuffer* buffer = mParamBlocks[entry.bufferIdx];
+
+			buffer->gInvViewportWidth.set(invViewportWidth);
+			buffer->gInvViewportHeight.set(invViewportHeight);
+
+			buffer->getBuffer()->flushToGPU();
+		}
+
 		for (auto& entry : renderData)
 		{
 			// TODO - I shouldn't be re-applying the entire material for each entry, instead just check which programs
 			// changed, and apply only those + the modified constant buffers and/or texture.
 
-			entry.material->render(entry.mesh, entry.texture, mSamplerState, entry.tint, entry.worldTransform, 
-				invViewportSize, entry.additionalData);
+			GUISpriteParamBuffer* buffer = mParamBlocks[entry.bufferIdx];
+
+			entry.material->render(entry.mesh, entry.texture, mSamplerState, buffer->getBuffer(), entry.additionalData);
 		}
 	}
 }

+ 20 - 13
Source/BansheeEngine/Source/BsSpriteMaterial.cpp

@@ -6,6 +6,7 @@
 #include "BsMesh.h"
 #include "BsShader.h"
 #include "BsRendererUtility.h"
+#include "BsGpuParamsSet.h"
 #include "BsCoreThread.h"
 
 namespace bs
@@ -31,18 +32,25 @@ namespace bs
 		assert(materialStored == true);
 
 		mParams = mMaterial->createParamsSet();
+
 		SPtr<ShaderCore> shader = mMaterial->getShader();
+		if(shader->hasTextureParam("gMainTexture"))
+		{
+			mTextureParam = mMaterial->getParamTexture("gMainTexture");
+			mSamplerParam = mMaterial->getParamSamplerState("gMainTexSamp");
+		}
 
-		if(shader->hasTextureParam("mainTexture"))
+		static StringID GUIParamsSemantic = "GUIParams";
+		const Map<String, SHADER_PARAM_BLOCK_DESC>& paramBlockDescs = shader->getParamBlocks();
+
+		for (auto& paramBlockDesc : paramBlockDescs)
 		{
-			mTextureParam = mMaterial->getParamTexture("mainTexture");
-			mSamplerParam = mMaterial->getParamSamplerState("mainTexSamp");
+			if (paramBlockDesc.second.rendererSemantic == GUIParamsSemantic)
+				mParamBufferIdx = mParams->getParamBlockBufferIndex(paramBlockDesc.second.name);
 		}
 
-		mTintParam = mMaterial->getParamColor("tint");
-		mInvViewportWidthParam = mMaterial->getParamFloat("invViewportWidth");
-		mInvViewportHeightParam = mMaterial->getParamFloat("invViewportHeight");
-		mWorldTransformParam = mMaterial->getParamMat4("worldTransform");
+		if(mParamBufferIdx == -1)
+			LOGERR("Sprite material shader missing \"GUIParams\" block.");
 	}
 
 	void SpriteMaterial::destroy(const SPtr<MaterialCore>& material, const SPtr<GpuParamsSetCore>& params)
@@ -66,8 +74,8 @@ namespace bs
 	}
 
 	void SpriteMaterial::render(const SPtr<MeshCoreBase>& mesh, const SPtr<TextureCore>& texture,
-		const SPtr<SamplerStateCore>& sampler, const Color& tint, const Matrix4& worldTransform,
-		const Vector2& invViewportSize, const SPtr<SpriteMaterialExtraInfo>& additionalData) const
+		const SPtr<SamplerStateCore>& sampler, const SPtr<GpuParamBlockBufferCore>& paramBuffer,
+		const SPtr<SpriteMaterialExtraInfo>& additionalData) const
 	{
 		SPtr<TextureCore> spriteTexture;
 		if (texture != nullptr)
@@ -77,10 +85,9 @@ namespace bs
 
 		mTextureParam.set(spriteTexture);
 		mSamplerParam.set(sampler);
-		mTintParam.set(tint);
-		mInvViewportWidthParam.set(invViewportSize.x);
-		mInvViewportHeightParam.set(invViewportSize.y);
-		mWorldTransformParam.set(worldTransform);
+
+		if(mParamBufferIdx != -1)
+			mParams->setParamBlockBuffer(mParamBufferIdx, paramBuffer, true);
 
 		mMaterial->updateParamsSet(mParams);
 

+ 19 - 25
Source/BansheeGLRenderAPI/Source/BsGLRenderAPI.cpp

@@ -55,7 +55,7 @@ namespace bs
 		, mActivePipeline(nullptr)
 		, mCurrentDrawOperation(DOT_TRIANGLE_LIST)
 		, mDrawCallInProgress(false)
-		, mActiveTextureUnit(0)
+		, mActiveTextureUnit(-1)
 	{
 		// Get our GLSupport
 		mGLSupport = bs::getGLSupport();
@@ -356,17 +356,15 @@ namespace bs
 				FrameVector<UINT32> textureUnits(12);
 				auto getTexUnit = [&](UINT32 binding)
 				{
-					UINT32 unit;
-
-					auto iterFind = std::find(textureUnits.begin(), textureUnits.end(), binding);
-					if (iterFind != textureUnits.end())
-						unit = *iterFind;
-					else
+					for(UINT32 i = 0; i < (UINT32)textureUnits.size(); i++)
 					{
-						unit = textureUnitCount++;
-						textureUnits.push_back(binding);
+						if (textureUnits[i] == binding)
+							return i;
 					}
 
+					UINT32 unit = textureUnitCount++;
+					textureUnits.push_back(binding);
+
 					return unit;
 				};
 
@@ -374,17 +372,15 @@ namespace bs
 				FrameVector<UINT32> imageUnits(6);
 				auto getImageUnit = [&](UINT32 binding)
 				{
-					UINT32 unit;
-
-					auto iterFind = std::find(imageUnits.begin(), imageUnits.end(), binding);
-					if (iterFind != imageUnits.end())
-						unit = *iterFind;
-					else
+					for (UINT32 i = 0; i < (UINT32)imageUnits.size(); i++)
 					{
-						unit = imageUnitCount++;
-						imageUnits.push_back(binding);
+						if (imageUnits[i] == binding)
+							return i;
 					}
 
+					UINT32 unit = imageUnitCount++;
+					imageUnits.push_back(binding);
+
 					return unit;
 				};
 
@@ -392,17 +388,15 @@ namespace bs
 				FrameVector<UINT32> uniformUnits(6);
 				auto getUniformUnit = [&](UINT32 binding)
 				{
-					UINT32 unit;
-
-					auto iterFind = std::find(uniformUnits.begin(), uniformUnits.end(), binding);
-					if (iterFind != uniformUnits.end())
-						unit = *iterFind;
-					else
+					for (UINT32 i = 0; i < (UINT32)uniformUnits.size(); i++)
 					{
-						unit = uniformUnitCount++;
-						uniformUnits.push_back(binding);
+						if (uniformUnits[i] == binding)
+							return i;
 					}
 
+					UINT32 unit = uniformUnitCount++;
+					uniformUnits.push_back(binding);
+
 					return unit;
 				};