Quellcode durchsuchen

More work on generic buffers
Work on Buffer views

Marko Pintera vor 13 Jahren
Ursprung
Commit
26ac8e10b8

+ 2 - 0
CamelotD3D11RenderSystem/CamelotD3D11RenderSystem.vcxproj

@@ -150,6 +150,7 @@
     <ClInclude Include="Include\CmD3D11DepthStencilBuffer.h" />
     <ClInclude Include="Include\CmD3D11DepthStencilBuffer.h" />
     <ClInclude Include="Include\CmD3D11DepthStencilState.h" />
     <ClInclude Include="Include\CmD3D11DepthStencilState.h" />
     <ClInclude Include="Include\CmD3D11GenericBuffer.h" />
     <ClInclude Include="Include\CmD3D11GenericBuffer.h" />
+    <ClInclude Include="Include\CmD3D11GenericBufferView.h" />
     <ClInclude Include="Include\CmD3D11HardwareBufferManager.h" />
     <ClInclude Include="Include\CmD3D11HardwareBufferManager.h" />
     <ClInclude Include="Include\CmD3D11HardwareConstantBuffer.h" />
     <ClInclude Include="Include\CmD3D11HardwareConstantBuffer.h" />
     <ClInclude Include="Include\CmD3D11Device.h" />
     <ClInclude Include="Include\CmD3D11Device.h" />
@@ -188,6 +189,7 @@
     <ClCompile Include="Source\CmD3D11Driver.cpp" />
     <ClCompile Include="Source\CmD3D11Driver.cpp" />
     <ClCompile Include="Source\CmD3D11DriverList.cpp" />
     <ClCompile Include="Source\CmD3D11DriverList.cpp" />
     <ClCompile Include="Source\CmD3D11GenericBuffer.cpp" />
     <ClCompile Include="Source\CmD3D11GenericBuffer.cpp" />
+    <ClCompile Include="Source\CmD3D11GenericBufferView.cpp" />
     <ClCompile Include="Source\CmD3D11GpuProgram.cpp" />
     <ClCompile Include="Source\CmD3D11GpuProgram.cpp" />
     <ClCompile Include="Source\CmD3D11GpuProgramManager.cpp" />
     <ClCompile Include="Source\CmD3D11GpuProgramManager.cpp" />
     <ClCompile Include="Source\CmD3D11HardwareBuffer.cpp" />
     <ClCompile Include="Source\CmD3D11HardwareBuffer.cpp" />

+ 6 - 0
CamelotD3D11RenderSystem/CamelotD3D11RenderSystem.vcxproj.filters

@@ -117,6 +117,9 @@
     <ClInclude Include="Include\CmD3D11GenericBuffer.h">
     <ClInclude Include="Include\CmD3D11GenericBuffer.h">
       <Filter>Header Files</Filter>
       <Filter>Header Files</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="Include\CmD3D11GenericBufferView.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\CmD3D11GpuProgram.cpp">
     <ClCompile Include="Source\CmD3D11GpuProgram.cpp">
@@ -212,5 +215,8 @@
     <ClCompile Include="Source\CmD3D11GenericBuffer.cpp">
     <ClCompile Include="Source\CmD3D11GenericBuffer.cpp">
       <Filter>Source Files</Filter>
       <Filter>Source Files</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="Source\CmD3D11GenericBufferView.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
 </Project>
 </Project>

+ 4 - 4
CamelotD3D11RenderSystem/Include/CmD3D11GenericBuffer.h

@@ -39,10 +39,10 @@ namespace CamelotEngine
 		void copyData(GenericBuffer& srcBuffer, UINT32 srcOffset, 
 		void copyData(GenericBuffer& srcBuffer, UINT32 srcOffset, 
 			UINT32 dstOffset, UINT32 length, bool discardWholeBuffer = false);
 			UINT32 dstOffset, UINT32 length, bool discardWholeBuffer = false);
 
 
-	private:
-		ID3D11Buffer* mBuffer;
+	protected:
+		D3D11HardwareBuffer* mBuffer;
 
 
-		ID3D11ShaderResourceView* createSRV(UINT32 firstElement, UINT32 elementWidth, UINT32 numElements);
-		ID3D11UnorderedAccessView* createUAV(UINT32 firstElement, UINT32 numElements);
+		virtual GenericBufferView* createView(UINT32 firstElement, UINT32 elementWidth, UINT32 numElements, bool randomGpuWrite);
+		virtual void destroyView(GenericBufferView* view);
     };
     };
 }
 }

+ 22 - 0
CamelotD3D11RenderSystem/Include/CmD3D11GenericBufferView.h

@@ -0,0 +1,22 @@
+#pragma once
+
+#include "CmD3D11Prerequisites.h"
+#include "CmGenericBuffer.h"
+#include "CmGenericBufferView.h"
+
+namespace CamelotEngine
+{
+	class CM_D3D11_EXPORT D3D11GenericBufferView : public GenericBufferView
+	{
+	public:
+		D3D11GenericBufferView(ID3D11Buffer* buffer, GenericBufferType type, UINT32 firstElement, UINT32 elementWidth, UINT32 numElements, bool randomGpuWrite, bool useCounter = false);
+		virtual ~D3D11GenericBufferView();
+
+	private:
+		ID3D11ShaderResourceView* mSRV;
+		ID3D11UnorderedAccessView* mUAV;
+
+		ID3D11ShaderResourceView* createSRV(ID3D11Buffer* buffer, GenericBufferType type, UINT32 firstElement, UINT32 elementWidth, UINT32 numElements);
+		ID3D11UnorderedAccessView* createUAV(ID3D11Buffer* buffer, GenericBufferType type, UINT32 firstElement, UINT32 numElements, bool useCounter);
+	};
+}

+ 31 - 20
CamelotD3D11RenderSystem/Include/CmD3D11HardwareBuffer.h

@@ -10,28 +10,18 @@ namespace CamelotEngine
 	public:
 	public:
 		enum BufferType
 		enum BufferType
 		{
 		{
-			VERTEX_BUFFER,
-			INDEX_BUFFER,
-			CONSTANT_BUFFER
+			BT_VERTEX = 0x1,
+			BT_INDEX = 0x2,
+			BT_CONSTANT = 0x4,
+			BT_GROUP_GENERIC = 0x8,
+			BT_STRUCTURED = BT_GROUP_GENERIC | 0x10,
+			BT_RAW = BT_GROUP_GENERIC | 0x20,
+			BT_INDIRECTARGUMENT = BT_GROUP_GENERIC | 0x40,
+			BT_APPENDCONSUME = BT_GROUP_GENERIC | 0x80
 		};
 		};
 
 
-	protected:
-		ID3D11Buffer* mD3DBuffer;
-		bool mUseTempStagingBuffer;
-		D3D11HardwareBuffer* mpTempStagingBuffer;
-		bool mStagingUploadNeeded;
-		BufferType mBufferType;
-		D3D11Device& mDevice;
-		D3D11_BUFFER_DESC mDesc;
-
-		/** See HardwareBuffer. */
-		void* lockImpl(UINT32 offset, UINT32 length, GpuLockOptions options);
-		/** See HardwareBuffer. */
-		void unlockImpl(void);
-
-	public:
-		D3D11HardwareBuffer(BufferType btype, UINT32 sizeBytes, GpuBufferUsage usage, 
-			D3D11Device& device, bool useSystemMem, bool streamOut);
+		D3D11HardwareBuffer(BufferType btype, GpuBufferUsage usage, UINT32 elementCount, UINT32 elementSize, 
+			D3D11Device& device, bool useSystemMem = false, bool streamOut = false, bool randomGpuWrite = false, bool useCounter = false);
 		~D3D11HardwareBuffer();
 		~D3D11HardwareBuffer();
 
 
 		/** See HardwareBuffer. */
 		/** See HardwareBuffer. */
@@ -45,5 +35,26 @@ namespace CamelotEngine
 
 
 		/// Get the D3D-specific buffer
 		/// Get the D3D-specific buffer
 		ID3D11Buffer* getD3DBuffer(void) { return mD3DBuffer; }
 		ID3D11Buffer* getD3DBuffer(void) { return mD3DBuffer; }
+
+	protected:
+		BufferType mBufferType;
+		bool mRandomGpuWrite;
+		bool mUseCounter;
+		UINT32 mElementCount;
+		UINT32 mElementSize;
+
+		ID3D11Buffer* mD3DBuffer;
+
+		bool mUseTempStagingBuffer;
+		D3D11HardwareBuffer* mpTempStagingBuffer;
+		bool mStagingUploadNeeded;
+		
+		D3D11Device& mDevice;
+		D3D11_BUFFER_DESC mDesc;
+
+		/** See HardwareBuffer. */
+		void* lockImpl(UINT32 offset, UINT32 length, GpuLockOptions options);
+		/** See HardwareBuffer. */
+		void unlockImpl(void);
 	};
 	};
 }
 }

+ 38 - 163
CamelotD3D11RenderSystem/Source/CmD3D11GenericBuffer.cpp

@@ -1,5 +1,7 @@
 #include "CmD3D11GenericBuffer.h"
 #include "CmD3D11GenericBuffer.h"
+#include "CmD3D11GenericBufferView.h"
 #include "CmD3D11RenderSystem.h"
 #include "CmD3D11RenderSystem.h"
+#include "CmD3D11HardwareBuffer.h"
 #include "CmD3D11Device.h"
 #include "CmD3D11Device.h"
 #include "CmException.h"
 #include "CmException.h"
 
 
@@ -7,199 +9,72 @@ namespace CamelotEngine
 {
 {
 	D3D11GenericBuffer::D3D11GenericBuffer(UINT32 elementCount, UINT32 elementSize, GenericBufferType type, GpuBufferUsage usage, bool randomGpuWrite, bool useCounter) 
 	D3D11GenericBuffer::D3D11GenericBuffer(UINT32 elementCount, UINT32 elementSize, GenericBufferType type, GpuBufferUsage usage, bool randomGpuWrite, bool useCounter) 
 		: GenericBuffer(elementCount, elementSize, type, usage, randomGpuWrite, useCounter), mBuffer(nullptr)
 		: GenericBuffer(elementCount, elementSize, type, usage, randomGpuWrite, useCounter), mBuffer(nullptr)
-	{  
-		D3D11_BUFFER_DESC desc;
-		ZeroMemory(&desc, sizeof(desc));
-
-		if(type == GBT_APPENDCONSUME && !randomGpuWrite)
-			CM_EXCEPT(InvalidParametersException, "Append/Consume buffer must be created with randomGpuWrite enabled.");
-
-		if(type != GBT_STRUCTURED && useCounter)
-			CM_EXCEPT(InvalidParametersException, "Counter can only be used with a structured buffer.");
-
-		if(useCounter && !randomGpuWrite)
-			CM_EXCEPT(InvalidParametersException, "Counter can only be used with buffers that have randomGpuWrite enabled.");
-
-		if(type == GBT_STRUCTURED || type == GBT_APPENDCONSUME)
-		{
-			desc.ByteWidth = elementCount * elementSize;
-			desc.StructureByteStride = elementSize;
-			desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
-		}
-		else if(type == GBT_RAW)
-		{
-			desc.ByteWidth = elementCount * elementSize;
-			desc.StructureByteStride = 0;
-			desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS;
-		}
-		else if(type == GBT_INDIRECTARGUMENT)
-		{
-			desc.ByteWidth = elementCount * elementSize;
-			desc.StructureByteStride = 0;
-			desc.MiscFlags = D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS;
-		}
-
-		if(!randomGpuWrite)
-		{
-			desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
-
-			if(usage == GBU_STATIC)
-			{
-				desc.Usage = D3D11_USAGE_DEFAULT;
-				desc.CPUAccessFlags = 0;
-			}
-			else if(usage == GBU_DYNAMIC)
-			{
-				desc.Usage = D3D11_USAGE_DYNAMIC;
-				desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
-			}
-			else
-				CM_EXCEPT(InternalErrorException, "Invalid usage flag: " + toString(usage));
-		}
-		else
-		{
-			desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS;
-			desc.Usage = D3D11_USAGE_DEFAULT;
-			desc.CPUAccessFlags = 0;
-		}
-
-		D3D11RenderSystem* d3d11rs = static_cast<D3D11RenderSystem*>(D3D11RenderSystem::instancePtr());
-		HRESULT hr = d3d11rs->getPrimaryDevice().getD3D11Device()->CreateBuffer(&desc, nullptr, &mBuffer);
-
-		if (FAILED(hr) || d3d11rs->getPrimaryDevice().hasError())
-		{
-			String msg = d3d11rs->getPrimaryDevice().getErrorDescription();
-			CM_EXCEPT(RenderingAPIException, "Cannot create D3D11 buffer: " + msg);
-		}
-	}
-
-	D3D11GenericBuffer::~D3D11GenericBuffer() 
 	{
 	{
-		SAFE_RELEASE(mBuffer);
-	}
-
-	ID3D11ShaderResourceView* D3D11GenericBuffer::createSRV(UINT32 firstElement, UINT32 elementWidth, UINT32 numElements)
-	{
-		if(mType == GBT_APPENDCONSUME)
-			CM_EXCEPT(InvalidParametersException, "Cannot create ShaderResourceView for an append/consume buffer.");
-
-		D3D11_SHADER_RESOURCE_VIEW_DESC desc;
-		ZeroMemory(&desc, sizeof(desc));
-
-		if(mType == GBT_STRUCTURED)
-		{
-			desc.Format = DXGI_FORMAT_UNKNOWN;
-			desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
-			desc.Buffer.ElementOffset = firstElement * elementWidth;
-			desc.Buffer.ElementWidth = elementWidth;
-		}
-		else if(mType == GBT_RAW)
-		{
-			desc.Format = DXGI_FORMAT_R32_TYPELESS;
-			desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFEREX;
-			desc.BufferEx.Flags = D3D11_BUFFEREX_SRV_FLAG_RAW;
-			desc.BufferEx.FirstElement = firstElement;
-			desc.BufferEx.NumElements = numElements;
-		}
-		else if(mType == GBT_INDIRECTARGUMENT)
-		{
-			desc.Format = DXGI_FORMAT_R32_UINT;
-			desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
-			desc.Buffer.ElementOffset = firstElement * elementWidth;
-			desc.Buffer.ElementWidth = elementWidth;
-		}
-
-		ID3D11ShaderResourceView* srv = nullptr;
-
+		D3D11HardwareBuffer::BufferType bufferType;
 		D3D11RenderSystem* d3d11rs = static_cast<D3D11RenderSystem*>(D3D11RenderSystem::instancePtr());
 		D3D11RenderSystem* d3d11rs = static_cast<D3D11RenderSystem*>(D3D11RenderSystem::instancePtr());
-		HRESULT hr = d3d11rs->getPrimaryDevice().getD3D11Device()->CreateShaderResourceView(mBuffer, &desc, &srv);
 
 
-		if (FAILED(hr) || d3d11rs->getPrimaryDevice().hasError())
-		{
-			String msg = d3d11rs->getPrimaryDevice().getErrorDescription();
-			CM_EXCEPT(RenderingAPIException, "Cannot create ShaderResourceView: " + msg);
+		switch(type)
+		{
+		case GBT_STRUCTURED:
+			bufferType = D3D11HardwareBuffer::BT_STRUCTURED;
+			break;
+		case GBT_RAW:
+			bufferType = D3D11HardwareBuffer::BT_RAW;
+			break;
+		case GBT_INDIRECTARGUMENT:
+			bufferType = D3D11HardwareBuffer::BT_INDIRECTARGUMENT;
+			break;
+		case GBT_APPENDCONSUME:
+			bufferType = D3D11HardwareBuffer::BT_APPENDCONSUME;
+			break;
 		}
 		}
 
 
-		return srv;
+		mBuffer = new D3D11HardwareBuffer(bufferType, usage, elementCount, elementSize, 
+			d3d11rs->getPrimaryDevice(), false, false, randomGpuWrite, useCounter);
 	}
 	}
 
 
-	ID3D11UnorderedAccessView* D3D11GenericBuffer::createUAV(UINT32 firstElement, UINT32 numElements)
+	D3D11GenericBuffer::~D3D11GenericBuffer()
 	{
 	{
-		D3D11_UNORDERED_ACCESS_VIEW_DESC desc;
-		ZeroMemory(&desc, sizeof(desc));
-
-		desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
-
-		if(mType == GBT_STRUCTURED)
-		{
-			desc.Format = DXGI_FORMAT_UNKNOWN;
-			desc.Buffer.FirstElement = firstElement;
-			desc.Buffer.NumElements = numElements;
-
-			if(mUseCounter)
-				desc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_COUNTER;
-			else
-				desc.Buffer.Flags = 0;
-		}
-		else if(mType == GBT_RAW)
-		{
-			desc.Format = DXGI_FORMAT_R32_TYPELESS;
-			desc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_RAW;
-			desc.Buffer.FirstElement = firstElement;
-			desc.Buffer.NumElements = numElements;
-		}
-		else if(mType == GBT_INDIRECTARGUMENT)
-		{
-			desc.Format = DXGI_FORMAT_R32_UINT;
-			desc.Buffer.Flags = 0;
-			desc.Buffer.FirstElement = firstElement;
-			desc.Buffer.NumElements = numElements;
-		}
-		else if(mType == GBT_APPENDCONSUME)
-		{
-			desc.Format = DXGI_FORMAT_UNKNOWN;
-			desc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_APPEND;
-			desc.Buffer.FirstElement = firstElement;
-			desc.Buffer.NumElements = numElements;
-		}
-
-		ID3D11UnorderedAccessView* uav = nullptr;
-
-		D3D11RenderSystem* d3d11rs = static_cast<D3D11RenderSystem*>(D3D11RenderSystem::instancePtr());
-		HRESULT hr = d3d11rs->getPrimaryDevice().getD3D11Device()->CreateUnorderedAccessView(mBuffer, &desc, &uav);
+		delete mBuffer;
 
 
-		if (FAILED(hr) || d3d11rs->getPrimaryDevice().hasError())
-		{
-			String msg = d3d11rs->getPrimaryDevice().getErrorDescription();
-			CM_EXCEPT(RenderingAPIException, "Cannot create UnorderedAccessView: " + msg);
-		}
-
-		return uav;
+		clearBufferViews();
 	}
 	}
 
 
 	void* D3D11GenericBuffer::lock(UINT32 offset, UINT32 length, GpuLockOptions options)
 	void* D3D11GenericBuffer::lock(UINT32 offset, UINT32 length, GpuLockOptions options)
 	{
 	{
-		return nullptr;
+		return mBuffer->lock(offset, length, options);
 	}
 	}
 
 
 	void D3D11GenericBuffer::unlock()
 	void D3D11GenericBuffer::unlock()
 	{
 	{
-
+		mBuffer->unlock();
 	}
 	}
 
 
 	void D3D11GenericBuffer::readData(UINT32 offset, UINT32 length, void* pDest)
 	void D3D11GenericBuffer::readData(UINT32 offset, UINT32 length, void* pDest)
 	{
 	{
-
+		mBuffer->readData(offset, length, pDest);
 	}
 	}
 
 
 	void D3D11GenericBuffer::writeData(UINT32 offset, UINT32 length, const void* pSource, bool discardWholeBuffer)
 	void D3D11GenericBuffer::writeData(UINT32 offset, UINT32 length, const void* pSource, bool discardWholeBuffer)
 	{
 	{
-
+		mBuffer->writeData(offset, length, pSource, discardWholeBuffer);
 	}
 	}
 
 
 	void D3D11GenericBuffer::copyData(GenericBuffer& srcBuffer, UINT32 srcOffset, 
 	void D3D11GenericBuffer::copyData(GenericBuffer& srcBuffer, UINT32 srcOffset, 
 		UINT32 dstOffset, UINT32 length, bool discardWholeBuffer)
 		UINT32 dstOffset, UINT32 length, bool discardWholeBuffer)
 	{
 	{
+		D3D11GenericBuffer* d3d11SrcBuffer = static_cast<D3D11GenericBuffer*>(&srcBuffer);
+
+		mBuffer->copyData(*d3d11SrcBuffer->mBuffer, srcOffset, dstOffset, length, discardWholeBuffer);
+	}
 
 
+	GenericBufferView* D3D11GenericBuffer::createView(UINT32 firstElement, UINT32 elementWidth, UINT32 numElements, bool randomGpuWrite)
+	{
+		return new D3D11GenericBufferView(mBuffer->getD3DBuffer(), mType, firstElement, elementWidth, numElements, randomGpuWrite, mUseCounter);
+	}
+
+	void D3D11GenericBuffer::destroyView(GenericBufferView* view)
+	{
+		delete view;
 	}
 	}
 }
 }

+ 124 - 0
CamelotD3D11RenderSystem/Source/CmD3D11GenericBufferView.cpp

@@ -0,0 +1,124 @@
+#include "CmD3D11GenericBufferView.h"
+#include "CmD3D11RenderSystem.h"
+#include "CmD3D11Device.h"
+#include "CmException.h"
+
+namespace CamelotEngine
+{
+	D3D11GenericBufferView::D3D11GenericBufferView(ID3D11Buffer* buffer, GenericBufferType type, 
+		UINT32 firstElement, UINT32 elementWidth, UINT32 numElements, bool randomGpuWrite, bool useCounter)
+		:GenericBufferView(firstElement, elementWidth, numElements, randomGpuWrite), mSRV(nullptr), mUAV(nullptr)
+	{
+		if(randomGpuWrite)
+			mSRV = createSRV(buffer, type, firstElement, elementWidth, numElements);
+		else
+			mUAV = createUAV(buffer, type, firstElement, numElements, useCounter);
+	}
+
+	D3D11GenericBufferView::~D3D11GenericBufferView()
+	{
+		SAFE_RELEASE(mSRV);
+		SAFE_RELEASE(mUAV);
+	}
+
+	ID3D11ShaderResourceView* D3D11GenericBufferView::createSRV(ID3D11Buffer* buffer, 
+		GenericBufferType type, UINT32 firstElement, UINT32 elementWidth, UINT32 numElements)
+	{
+		if(type == GBT_APPENDCONSUME)
+			CM_EXCEPT(InvalidParametersException, "Cannot create ShaderResourceView for an append/consume buffer.");
+
+		D3D11_SHADER_RESOURCE_VIEW_DESC desc;
+		ZeroMemory(&desc, sizeof(desc));
+
+		if(type == GBT_STRUCTURED)
+		{
+			desc.Format = DXGI_FORMAT_UNKNOWN;
+			desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
+			desc.Buffer.ElementOffset = firstElement * elementWidth;
+			desc.Buffer.ElementWidth = elementWidth;
+		}
+		else if(type == GBT_RAW)
+		{
+			desc.Format = DXGI_FORMAT_R32_TYPELESS;
+			desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFEREX;
+			desc.BufferEx.Flags = D3D11_BUFFEREX_SRV_FLAG_RAW;
+			desc.BufferEx.FirstElement = firstElement;
+			desc.BufferEx.NumElements = numElements;
+		}
+		else if(type == GBT_INDIRECTARGUMENT)
+		{
+			desc.Format = DXGI_FORMAT_R32_UINT;
+			desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
+			desc.Buffer.ElementOffset = firstElement * elementWidth;
+			desc.Buffer.ElementWidth = elementWidth;
+		}
+
+		ID3D11ShaderResourceView* srv = nullptr;
+
+		D3D11RenderSystem* d3d11rs = static_cast<D3D11RenderSystem*>(D3D11RenderSystem::instancePtr());
+		HRESULT hr = d3d11rs->getPrimaryDevice().getD3D11Device()->CreateShaderResourceView(buffer, &desc, &srv);
+
+		if (FAILED(hr) || d3d11rs->getPrimaryDevice().hasError())
+		{
+			String msg = d3d11rs->getPrimaryDevice().getErrorDescription();
+			CM_EXCEPT(RenderingAPIException, "Cannot create ShaderResourceView: " + msg);
+		}
+
+		return srv;
+	}
+
+	ID3D11UnorderedAccessView* D3D11GenericBufferView::createUAV(ID3D11Buffer* buffer, 
+		GenericBufferType type, UINT32 firstElement, UINT32 numElements, bool useCounter)
+	{
+		D3D11_UNORDERED_ACCESS_VIEW_DESC desc;
+		ZeroMemory(&desc, sizeof(desc));
+
+		desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
+
+		if(type == GBT_STRUCTURED)
+		{
+			desc.Format = DXGI_FORMAT_UNKNOWN;
+			desc.Buffer.FirstElement = firstElement;
+			desc.Buffer.NumElements = numElements;
+
+			if(useCounter)
+				desc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_COUNTER;
+			else
+				desc.Buffer.Flags = 0;
+		}
+		else if(type == GBT_RAW)
+		{
+			desc.Format = DXGI_FORMAT_R32_TYPELESS;
+			desc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_RAW;
+			desc.Buffer.FirstElement = firstElement;
+			desc.Buffer.NumElements = numElements;
+		}
+		else if(type == GBT_INDIRECTARGUMENT)
+		{
+			desc.Format = DXGI_FORMAT_R32_UINT;
+			desc.Buffer.Flags = 0;
+			desc.Buffer.FirstElement = firstElement;
+			desc.Buffer.NumElements = numElements;
+		}
+		else if(type == GBT_APPENDCONSUME)
+		{
+			desc.Format = DXGI_FORMAT_UNKNOWN;
+			desc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_APPEND;
+			desc.Buffer.FirstElement = firstElement;
+			desc.Buffer.NumElements = numElements;
+		}
+
+		ID3D11UnorderedAccessView* uav = nullptr;
+
+		D3D11RenderSystem* d3d11rs = static_cast<D3D11RenderSystem*>(D3D11RenderSystem::instancePtr());
+		HRESULT hr = d3d11rs->getPrimaryDevice().getD3D11Device()->CreateUnorderedAccessView(buffer, &desc, &uav);
+
+		if (FAILED(hr) || d3d11rs->getPrimaryDevice().hasError())
+		{
+			String msg = d3d11rs->getPrimaryDevice().getErrorDescription();
+			CM_EXCEPT(RenderingAPIException, "Cannot create UnorderedAccessView: " + msg);
+		}
+
+		return uav;
+	}
+}

+ 279 - 248
CamelotD3D11RenderSystem/Source/CmD3D11HardwareBuffer.cpp

@@ -6,253 +6,284 @@
 
 
 namespace CamelotEngine
 namespace CamelotEngine
 {
 {
-	D3D11HardwareBuffer::D3D11HardwareBuffer(BufferType btype, UINT32 sizeBytes, GpuBufferUsage usage, 
-		D3D11Device& device, bool useSystemMemory, bool streamOut)
-		: HardwareBuffer(usage, useSystemMemory),
-		mD3DBuffer(0),
-		mpTempStagingBuffer(0),
-		mUseTempStagingBuffer(false),
-		mBufferType(btype),
-		mDevice(device)
-	{
-		if(streamOut && btype != VERTEX_BUFFER)
-			CM_EXCEPT(InvalidParametersException, "Stream out flag is only supported on vertex buffers");
-
-		mSizeInBytes = sizeBytes;
-		mDesc.ByteWidth = static_cast<UINT>(sizeBytes);
-		
-		mDesc.MiscFlags = 0;
-
-		if (useSystemMemory)
-		{
-			mDesc.Usage = D3D11_USAGE_STAGING;
-			mDesc.BindFlags = 0;
-			mDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE | D3D11_CPU_ACCESS_READ ;// A D3D11_USAGE_STAGING Resource must have at least one CPUAccessFlag bit set.
-
-		}
-		else
-		{
-			mDesc.Usage = D3D11Mappings::_getUsage(mUsage);
-			mDesc.BindFlags = btype == VERTEX_BUFFER ? D3D11_BIND_VERTEX_BUFFER : 
-				btype == INDEX_BUFFER  ? D3D11_BIND_INDEX_BUFFER  :
-				D3D11_BIND_CONSTANT_BUFFER;
-			mDesc.CPUAccessFlags = D3D11Mappings::_getAccessFlags(mUsage); 
-		}
-
-		// Check of stream out flag
-		if (streamOut)
-		{
-			mDesc.BindFlags |= D3D11_BIND_STREAM_OUTPUT;
-		}
-
-		// TODO: we can explicitly initialise the buffer contents here if we like
-		// not doing this since OGRE doesn't support this model yet
-		HRESULT hr = device.getD3D11Device()->CreateBuffer( &mDesc, nullptr, &mD3DBuffer );
-		if (FAILED(hr) || mDevice.hasError())
-		{
-			String msg = device.getErrorDescription();
-			CM_EXCEPT(RenderingAPIException, "Cannot create D3D11 buffer: " + msg);
-		}
-	}
-
-	D3D11HardwareBuffer::~D3D11HardwareBuffer()
-	{
-		SAFE_RELEASE(mD3DBuffer);
-		SAFE_DELETE(mpTempStagingBuffer); // should never be nonzero unless destroyed while locked
-	}
-
-	void* D3D11HardwareBuffer::lockImpl(UINT32 offset, 
-		UINT32 length, GpuLockOptions options)
-	{
-		if (length > mSizeInBytes)
-			CM_EXCEPT(RenderingAPIException, "Provided length " + toString(length) + " larger than the buffer " + toString(mSizeInBytes) + ".");		
-
-		// Use direct (and faster) Map/Unmap if dynamic write, or a staging read/write
-		if((mDesc.Usage == D3D11_USAGE_DYNAMIC && options != GBL_READ_ONLY) || mDesc.Usage == D3D11_USAGE_STAGING)
-		{
-			D3D11_MAP mapType;
-
-			switch(options)
-			{
-			case GBL_WRITE_ONLY_DISCARD:
-				if (mUsage & GBU_DYNAMIC)
-				{
-					// Map cannot be called with MAP_WRITE access, 
-					// because the Resource was created as D3D11_USAGE_DYNAMIC. 
-					// D3D11_USAGE_DYNAMIC Resources must use either MAP_WRITE_DISCARD 
-					// or MAP_WRITE_NO_OVERWRITE with Map.
-					mapType = D3D11_MAP_WRITE_DISCARD;
-				}
-				else
-				{
-					// Map cannot be called with MAP_WRITE_DISCARD access, 
-					// because the Resource was not created as D3D11_USAGE_DYNAMIC. 
-					// D3D11_USAGE_DYNAMIC Resources must use either MAP_WRITE_DISCARD 
-					// or MAP_WRITE_NO_OVERWRITE with Map.
-					mapType = D3D11_MAP_WRITE;
-
-					LOGWRN("DISCARD lock is only available on dynamic buffers. Falling back to normal write.");
-				}
-				break;
-			case GBL_WRITE_ONLY_NO_OVERWRITE:
-				if(mBufferType == INDEX_BUFFER || mBufferType == VERTEX_BUFFER)
-					mapType = D3D11_MAP_WRITE_NO_OVERWRITE;
-				else
-				{
-					mapType = D3D11_MAP_WRITE;
-
-					LOGWRN("NO_OVERWRITE lock is not available on this (" + toString(mBufferType) + ") buffer type. Falling back to normal write.");
-				}
-				break;
-			case GBL_READ_WRITE:
-				if ((mDesc.CPUAccessFlags & D3D11_CPU_ACCESS_READ) != 0 &&
-					(mDesc.CPUAccessFlags & D3D11_CPU_ACCESS_WRITE) != 0)
-				{
-					mapType = D3D11_MAP_READ_WRITE;
-				}
-				else if(mDesc.CPUAccessFlags & D3D11_CPU_ACCESS_WRITE)
-				{
-					mapType = D3D11_MAP_WRITE;
-				}
-				else
-				{
-					mapType = D3D11_MAP_READ;
-				}
-				break;
-			case GBL_READ_ONLY:
-				mapType = D3D11_MAP_READ;
-				break;
-			}
-
-			if(D3D11Mappings::isMappingRead(mapType) && (mDesc.CPUAccessFlags & D3D11_CPU_ACCESS_READ) == 0)
-				CM_EXCEPT(RenderingAPIException, "Trying to read a buffer, but buffer wasn't created with a read access flag.");
-
-			if(D3D11Mappings::isMappingWrite(mapType) && (mDesc.CPUAccessFlags & D3D11_CPU_ACCESS_WRITE) == 0)
-				CM_EXCEPT(RenderingAPIException, "Trying to write to a buffer, but buffer wasn't created with a write access flag.");
-
-			void * pRet = NULL;
-			D3D11_MAPPED_SUBRESOURCE mappedSubResource;
-			mappedSubResource.pData = NULL;
-			mDevice.clearErrors();
-			HRESULT hr = mDevice.getImmediateContext()->Map(mD3DBuffer, 0, mapType, 0, &mappedSubResource);
-			if (FAILED(hr) || mDevice.hasError())
-			{
-				String msg = mDevice.getErrorDescription();
-				CM_EXCEPT(RenderingAPIException, "Error calling Map: " + msg);
-			}
-
-			pRet = static_cast<void*>(static_cast<char*>(mappedSubResource.pData) + offset);
-
-			return pRet;
-		}
-		else // Otherwise create a staging buffer to do all read/write operations on. Usually try to avoid this.
-		{
-			mUseTempStagingBuffer = true;
-			if (!mpTempStagingBuffer)
-			{
-				// create another buffer instance but use system memory
-				mpTempStagingBuffer = new D3D11HardwareBuffer(mBufferType, 
-					mSizeInBytes, mUsage, mDevice, true, false);
-			}
-
-			// schedule a copy to the staging
-			if (options != GBL_WRITE_ONLY_DISCARD)
-				mpTempStagingBuffer->copyData(*this, 0, 0, mSizeInBytes, true);
-
-			// register whether we'll need to upload on unlock
-			mStagingUploadNeeded = (options != GBL_READ_ONLY);
-
-			return mpTempStagingBuffer->lock(offset, length, options);
-		}
-	}
-
-	void D3D11HardwareBuffer::unlockImpl(void)
-	{
-		if (mUseTempStagingBuffer)
-		{
-			mUseTempStagingBuffer = false;
-
-			// ok, we locked the staging buffer
-			mpTempStagingBuffer->unlock();
-
-			// copy data if needed
-			// this is async but driver should keep reference
-			if (mStagingUploadNeeded)
-				copyData(*mpTempStagingBuffer, 0, 0, mSizeInBytes, true);
-
-			// delete
-			// not that efficient, but we should not be locking often
-			SAFE_DELETE(mpTempStagingBuffer);
-		}
-		else
-		{
-			// unmap
-			mDevice.getImmediateContext()->Unmap(mD3DBuffer, 0);
-		}
-	}
-
-	void D3D11HardwareBuffer::copyData(HardwareBuffer& srcBuffer, UINT32 srcOffset, 
-		UINT32 dstOffset, UINT32 length, bool discardWholeBuffer)
-	{
-		// If we're copying same-size buffers in their entirety...
-		if (srcOffset == 0 && dstOffset == 0 &&
-			length == mSizeInBytes && mSizeInBytes == srcBuffer.getSizeInBytes())
-		{
-			// schedule hardware buffer copy
-			mDevice.getImmediateContext()->CopyResource(mD3DBuffer, static_cast<D3D11HardwareBuffer&>(srcBuffer).getD3DBuffer());
-			if (mDevice.hasError())
-			{
-				String errorDescription = mDevice.getErrorDescription();
-				CM_EXCEPT(RenderingAPIException, "Cannot copy D3D11 resource\nError Description:" + errorDescription);
-			}
-		}
-		else
-		{
-			// copy subregion
-			D3D11_BOX srcBox;
-			srcBox.left = (UINT)srcOffset;
-			srcBox.right = (UINT)srcOffset + length;
-			srcBox.top = 0;
-			srcBox.bottom = 1;
-			srcBox.front = 0;
-			srcBox.back = 1;
-
-			mDevice.getImmediateContext()->CopySubresourceRegion(mD3DBuffer, 0, (UINT)dstOffset, 0, 0, 
-				static_cast<D3D11HardwareBuffer&>(srcBuffer).getD3DBuffer(), 0, &srcBox);
-			if (mDevice.hasError())
-			{
-				String errorDescription = mDevice.getErrorDescription();
-				CM_EXCEPT(RenderingAPIException, "Cannot copy D3D11 subresource region\nError Description:" + errorDescription);
-			}
-		}
-	}
-
-	void D3D11HardwareBuffer::readData(UINT32 offset, UINT32 length, void* pDest)
-	{
-		// There is no functional interface in D3D, just do via manual 
-		// lock, copy & unlock
-		void* pSrc = this->lock(offset, length, GBL_READ_ONLY);
-		memcpy(pDest, pSrc, length);
-		this->unlock();
-	}
-
-	void D3D11HardwareBuffer::writeData(UINT32 offset, UINT32 length, 
-		const void* pSource, bool discardWholeBuffer)
-	{
-		if(mDesc.Usage == D3D11_USAGE_DYNAMIC || mDesc.Usage == D3D11_USAGE_STAGING)
-		{
-			void* pDst = this->lock(offset, length, 
-				discardWholeBuffer ? GBL_WRITE_ONLY_DISCARD : GBL_READ_WRITE);
-			memcpy(pDst, pSource, length);
-			this->unlock();
-		}
-		else if(mDesc.Usage == D3D11_USAGE_DEFAULT)
-		{
-			mDevice.getImmediateContext()->UpdateSubresource(mD3DBuffer, 0, nullptr, pSource, offset, length);
-		}
-		else
-		{
-			CM_EXCEPT(RenderingAPIException, "Trying to write into a buffer with unsupported usage: " + toString(mDesc.Usage));
-		}
+	D3D11HardwareBuffer::D3D11HardwareBuffer(BufferType btype, GpuBufferUsage usage, UINT32 elementCount, UINT32 elementSize, 
+		D3D11Device& device, bool useSystemMem, bool streamOut, bool randomGpuWrite, bool useCounter)
+		: HardwareBuffer(usage, useSystemMem),
+		mD3DBuffer(0),
+		mpTempStagingBuffer(0),
+		mUseTempStagingBuffer(false),
+		mBufferType(btype),
+		mDevice(device),
+		mElementCount(elementCount),
+		mElementSize(elementSize),
+		mRandomGpuWrite(randomGpuWrite),
+		mUseCounter(useCounter)
+	{
+		assert((!streamOut || btype == BT_VERTEX) && "Stream out flag is only supported on vertex buffers");
+		assert(!randomGpuWrite || (btype & BT_GROUP_GENERIC) != 0 && "randomGpuWrite flag can only be enabled with append/consume, indirect argument, structured or raw buffers");
+		assert(btype != BT_APPENDCONSUME || randomGpuWrite && "Append/Consume buffer must be created with randomGpuWrite enabled.");
+		assert(!useCounter || btype == BT_STRUCTURED && "Counter can only be used with a structured buffer.");
+		assert(!useCounter || randomGpuWrite && "Counter can only be used with buffers that have randomGpuWrite enabled.");
+		assert(!randomGpuWrite || !useSystemMem && "randomGpuWrite and useSystemMem cannot be used together.");
+		assert(!(useSystemMem && streamOut) && "useSystemMem and streamOut cannot be used together.");
+
+		mSizeInBytes = elementCount * elementSize;
+		mDesc.ByteWidth = mSizeInBytes;
+		mDesc.MiscFlags = 0;
+		mDesc.StructureByteStride = 0;
+
+		if (useSystemMem)
+		{
+			mDesc.Usage = D3D11_USAGE_STAGING;
+			mDesc.BindFlags = 0;
+			mDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE | D3D11_CPU_ACCESS_READ ;
+		}
+		else if(randomGpuWrite)
+		{
+			mDesc.Usage = D3D11_USAGE_DEFAULT;
+			mDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS;
+			mDesc.CPUAccessFlags = 0;
+		}
+		else
+		{
+			mDesc.Usage = D3D11Mappings::_getUsage(mUsage);
+			mDesc.CPUAccessFlags = D3D11Mappings::_getAccessFlags(mUsage); 
+
+			switch(btype)
+			{
+			case BT_VERTEX:
+				mDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
+				if (streamOut)
+					mDesc.BindFlags |= D3D11_BIND_STREAM_OUTPUT;
+				break;
+			case BT_INDEX:
+				mDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
+				break;
+			case BT_CONSTANT:
+				mDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
+				break;
+			case BT_STRUCTURED:
+			case BT_APPENDCONSUME:
+				mDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+				mDesc.StructureByteStride = elementSize;
+				mDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
+				break;
+			case BT_RAW:
+				mDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+				mDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS;
+				break;
+			case BT_INDIRECTARGUMENT:
+				mDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+				mDesc.MiscFlags = D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS;
+				break;
+			}
+		}
+
+		HRESULT hr = device.getD3D11Device()->CreateBuffer( &mDesc, nullptr, &mD3DBuffer );
+		if (FAILED(hr) || mDevice.hasError())
+		{
+			String msg = device.getErrorDescription();
+			CM_EXCEPT(RenderingAPIException, "Cannot create D3D11 buffer: " + msg);
+		}
+	}
+
+	D3D11HardwareBuffer::~D3D11HardwareBuffer()
+	{
+		SAFE_RELEASE(mD3DBuffer);
+		SAFE_DELETE(mpTempStagingBuffer); // should never be nonzero unless destroyed while locked
+	}
+
+	void* D3D11HardwareBuffer::lockImpl(UINT32 offset, 
+		UINT32 length, GpuLockOptions options)
+	{
+		if (length > mSizeInBytes)
+			CM_EXCEPT(RenderingAPIException, "Provided length " + toString(length) + " larger than the buffer " + toString(mSizeInBytes) + ".");		
+
+		// Use direct (and faster) Map/Unmap if dynamic write, or a staging read/write
+		if((mDesc.Usage == D3D11_USAGE_DYNAMIC && options != GBL_READ_ONLY) || mDesc.Usage == D3D11_USAGE_STAGING)
+		{
+			D3D11_MAP mapType;
+
+			switch(options)
+			{
+			case GBL_WRITE_ONLY_DISCARD:
+				if (mUsage & GBU_DYNAMIC)
+				{
+					// Map cannot be called with MAP_WRITE access, 
+					// because the Resource was created as D3D11_USAGE_DYNAMIC. 
+					// D3D11_USAGE_DYNAMIC Resources must use either MAP_WRITE_DISCARD 
+					// or MAP_WRITE_NO_OVERWRITE with Map.
+					mapType = D3D11_MAP_WRITE_DISCARD;
+				}
+				else
+				{
+					// Map cannot be called with MAP_WRITE_DISCARD access, 
+					// because the Resource was not created as D3D11_USAGE_DYNAMIC. 
+					// D3D11_USAGE_DYNAMIC Resources must use either MAP_WRITE_DISCARD 
+					// or MAP_WRITE_NO_OVERWRITE with Map.
+					mapType = D3D11_MAP_WRITE;
+
+					LOGWRN("DISCARD lock is only available on dynamic buffers. Falling back to normal write.");
+				}
+				break;
+			case GBL_WRITE_ONLY_NO_OVERWRITE:
+				if(mBufferType == BT_INDEX || mBufferType == BT_VERTEX)
+					mapType = D3D11_MAP_WRITE_NO_OVERWRITE;
+				else
+				{
+					mapType = D3D11_MAP_WRITE;
+
+					LOGWRN("NO_OVERWRITE lock is not available on this (" + toString(mBufferType) + ") buffer type. Falling back to normal write.");
+				}
+				break;
+			case GBL_READ_WRITE:
+				if ((mDesc.CPUAccessFlags & D3D11_CPU_ACCESS_READ) != 0 &&
+					(mDesc.CPUAccessFlags & D3D11_CPU_ACCESS_WRITE) != 0)
+				{
+					mapType = D3D11_MAP_READ_WRITE;
+				}
+				else if(mDesc.CPUAccessFlags & D3D11_CPU_ACCESS_WRITE)
+				{
+					mapType = D3D11_MAP_WRITE;
+				}
+				else
+				{
+					mapType = D3D11_MAP_READ;
+				}
+				break;
+			case GBL_READ_ONLY:
+				mapType = D3D11_MAP_READ;
+				break;
+			}
+
+			if(D3D11Mappings::isMappingRead(mapType) && (mDesc.CPUAccessFlags & D3D11_CPU_ACCESS_READ) == 0)
+				CM_EXCEPT(RenderingAPIException, "Trying to read a buffer, but buffer wasn't created with a read access flag.");
+
+			if(D3D11Mappings::isMappingWrite(mapType) && (mDesc.CPUAccessFlags & D3D11_CPU_ACCESS_WRITE) == 0)
+				CM_EXCEPT(RenderingAPIException, "Trying to write to a buffer, but buffer wasn't created with a write access flag.");
+
+			void * pRet = NULL;
+			D3D11_MAPPED_SUBRESOURCE mappedSubResource;
+			mappedSubResource.pData = NULL;
+			mDevice.clearErrors();
+			HRESULT hr = mDevice.getImmediateContext()->Map(mD3DBuffer, 0, mapType, 0, &mappedSubResource);
+			if (FAILED(hr) || mDevice.hasError())
+			{
+				String msg = mDevice.getErrorDescription();
+				CM_EXCEPT(RenderingAPIException, "Error calling Map: " + msg);
+			}
+
+			pRet = static_cast<void*>(static_cast<char*>(mappedSubResource.pData) + offset);
+
+			return pRet;
+		}
+		else // Otherwise create a staging buffer to do all read/write operations on. Usually try to avoid this.
+		{
+			mUseTempStagingBuffer = true;
+			if (!mpTempStagingBuffer)
+			{
+				// create another buffer instance but use system memory
+				mpTempStagingBuffer = new D3D11HardwareBuffer(mBufferType, mUsage, 1, mSizeInBytes, mDevice, true);
+			}
+
+			// schedule a copy to the staging
+			if (options != GBL_WRITE_ONLY_DISCARD)
+				mpTempStagingBuffer->copyData(*this, 0, 0, mSizeInBytes, true);
+
+			// register whether we'll need to upload on unlock
+			mStagingUploadNeeded = (options != GBL_READ_ONLY);
+
+			return mpTempStagingBuffer->lock(offset, length, options);
+		}
+	}
+
+	void D3D11HardwareBuffer::unlockImpl(void)
+	{
+		if (mUseTempStagingBuffer)
+		{
+			mUseTempStagingBuffer = false;
+
+			// ok, we locked the staging buffer
+			mpTempStagingBuffer->unlock();
+
+			// copy data if needed
+			// this is async but driver should keep reference
+			if (mStagingUploadNeeded)
+				copyData(*mpTempStagingBuffer, 0, 0, mSizeInBytes, true);
+
+			// delete
+			// not that efficient, but we should not be locking often
+			SAFE_DELETE(mpTempStagingBuffer);
+		}
+		else
+		{
+			// unmap
+			mDevice.getImmediateContext()->Unmap(mD3DBuffer, 0);
+		}
+	}
+
+	void D3D11HardwareBuffer::copyData(HardwareBuffer& srcBuffer, UINT32 srcOffset, 
+		UINT32 dstOffset, UINT32 length, bool discardWholeBuffer)
+	{
+		// If we're copying same-size buffers in their entirety...
+		if (srcOffset == 0 && dstOffset == 0 &&
+			length == mSizeInBytes && mSizeInBytes == srcBuffer.getSizeInBytes())
+		{
+			// schedule hardware buffer copy
+			mDevice.getImmediateContext()->CopyResource(mD3DBuffer, static_cast<D3D11HardwareBuffer&>(srcBuffer).getD3DBuffer());
+			if (mDevice.hasError())
+			{
+				String errorDescription = mDevice.getErrorDescription();
+				CM_EXCEPT(RenderingAPIException, "Cannot copy D3D11 resource\nError Description:" + errorDescription);
+			}
+		}
+		else
+		{
+			// copy subregion
+			D3D11_BOX srcBox;
+			srcBox.left = (UINT)srcOffset;
+			srcBox.right = (UINT)srcOffset + length;
+			srcBox.top = 0;
+			srcBox.bottom = 1;
+			srcBox.front = 0;
+			srcBox.back = 1;
+
+			mDevice.getImmediateContext()->CopySubresourceRegion(mD3DBuffer, 0, (UINT)dstOffset, 0, 0, 
+				static_cast<D3D11HardwareBuffer&>(srcBuffer).getD3DBuffer(), 0, &srcBox);
+			if (mDevice.hasError())
+			{
+				String errorDescription = mDevice.getErrorDescription();
+				CM_EXCEPT(RenderingAPIException, "Cannot copy D3D11 subresource region\nError Description:" + errorDescription);
+			}
+		}
+	}
+
+	void D3D11HardwareBuffer::readData(UINT32 offset, UINT32 length, void* pDest)
+	{
+		// There is no functional interface in D3D, just do via manual 
+		// lock, copy & unlock
+		void* pSrc = this->lock(offset, length, GBL_READ_ONLY);
+		memcpy(pDest, pSrc, length);
+		this->unlock();
+	}
+
+	void D3D11HardwareBuffer::writeData(UINT32 offset, UINT32 length, 
+		const void* pSource, bool discardWholeBuffer)
+	{
+		if(mDesc.Usage == D3D11_USAGE_DYNAMIC || mDesc.Usage == D3D11_USAGE_STAGING)
+		{
+			void* pDst = this->lock(offset, length, 
+				discardWholeBuffer ? GBL_WRITE_ONLY_DISCARD : GBL_READ_WRITE);
+			memcpy(pDst, pSource, length);
+			this->unlock();
+		}
+		else if(mDesc.Usage == D3D11_USAGE_DEFAULT)
+		{
+			mDevice.getImmediateContext()->UpdateSubresource(mD3DBuffer, 0, nullptr, pSource, offset, length);
+		}
+		else
+		{
+			CM_EXCEPT(RenderingAPIException, "Trying to write into a buffer with unsupported usage: " + toString(mDesc.Usage));
+		}
 	}
 	}
 }
 }

+ 1 - 1
CamelotD3D11RenderSystem/Source/CmD3D11HardwareIndexBuffer.cpp

@@ -6,7 +6,7 @@ namespace CamelotEngine
 		GpuBufferUsage usage, bool useSystemMem)
 		GpuBufferUsage usage, bool useSystemMem)
 		:HardwareIndexBuffer(mgr, idxType, numIndexes, usage, useSystemMem)
 		:HardwareIndexBuffer(mgr, idxType, numIndexes, usage, useSystemMem)
 	{
 	{
-		mBuffer = new D3D11HardwareBuffer(D3D11HardwareBuffer::INDEX_BUFFER, mSizeInBytes, usage, device, useSystemMem, false);
+		mBuffer = new D3D11HardwareBuffer(D3D11HardwareBuffer::BT_INDEX, usage, 1, mSizeInBytes, device, useSystemMem);
 	}
 	}
 
 
 	D3D11HardwareIndexBuffer::~D3D11HardwareIndexBuffer()
 	D3D11HardwareIndexBuffer::~D3D11HardwareIndexBuffer()

+ 1 - 1
CamelotD3D11RenderSystem/Source/CmD3D11HardwareVertexBuffer.cpp

@@ -6,7 +6,7 @@ namespace CamelotEngine
 		GpuBufferUsage usage, bool useSystemMem, bool streamOut)
 		GpuBufferUsage usage, bool useSystemMem, bool streamOut)
 		:HardwareVertexBuffer(mgr, vertexSize, numVertices, usage, useSystemMem)
 		:HardwareVertexBuffer(mgr, vertexSize, numVertices, usage, useSystemMem)
 	{
 	{
-		mBuffer = new D3D11HardwareBuffer(D3D11HardwareBuffer::VERTEX_BUFFER, mSizeInBytes, usage, device, useSystemMem, streamOut);
+		mBuffer = new D3D11HardwareBuffer(D3D11HardwareBuffer::BT_VERTEX, usage, 1, mSizeInBytes, device, useSystemMem, streamOut);
 	}
 	}
 
 
 	D3D11HardwareVertexBuffer::~D3D11HardwareVertexBuffer()
 	D3D11HardwareVertexBuffer::~D3D11HardwareVertexBuffer()

+ 2 - 0
CamelotRenderer/CamelotRenderer.vcxproj

@@ -192,6 +192,7 @@
     <ClInclude Include="Include\CmDepthStencilStateRTTI.h" />
     <ClInclude Include="Include\CmDepthStencilStateRTTI.h" />
     <ClInclude Include="Include\CmDepthStencilState.h" />
     <ClInclude Include="Include\CmDepthStencilState.h" />
     <ClInclude Include="Include\CmGenericBuffer.h" />
     <ClInclude Include="Include\CmGenericBuffer.h" />
+    <ClInclude Include="Include\CmGenericBufferView.h" />
     <ClInclude Include="Include\CmGpuParamBlock.h" />
     <ClInclude Include="Include\CmGpuParamBlock.h" />
     <ClInclude Include="Include\CmGpuParamDesc.h" />
     <ClInclude Include="Include\CmGpuParamDesc.h" />
     <ClInclude Include="Include\CmGpuParams.h" />
     <ClInclude Include="Include\CmGpuParams.h" />
@@ -279,6 +280,7 @@
     <ClCompile Include="Source\CmDepthStencilBuffer.cpp" />
     <ClCompile Include="Source\CmDepthStencilBuffer.cpp" />
     <ClCompile Include="Source\CmDepthStencilState.cpp" />
     <ClCompile Include="Source\CmDepthStencilState.cpp" />
     <ClCompile Include="Source\CmGenericBuffer.cpp" />
     <ClCompile Include="Source\CmGenericBuffer.cpp" />
+    <ClCompile Include="Source\CmGenericBufferView.cpp" />
     <ClCompile Include="Source\CmGpuParamBlock.cpp" />
     <ClCompile Include="Source\CmGpuParamBlock.cpp" />
     <ClCompile Include="Source\CmGpuParams.cpp" />
     <ClCompile Include="Source\CmGpuParams.cpp" />
     <ClCompile Include="Source\CmGpuProgram.cpp" />
     <ClCompile Include="Source\CmGpuProgram.cpp" />

+ 6 - 0
CamelotRenderer/CamelotRenderer.vcxproj.filters

@@ -359,6 +359,9 @@
     <ClInclude Include="Include\CmCommonEnums.h">
     <ClInclude Include="Include\CmCommonEnums.h">
       <Filter>Header Files\Utility</Filter>
       <Filter>Header Files\Utility</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="Include\CmGenericBufferView.h">
+      <Filter>Header Files\RenderSystem</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\CamelotRenderer.cpp">
     <ClCompile Include="Source\CamelotRenderer.cpp">
@@ -541,5 +544,8 @@
     <ClCompile Include="Source\CmGenericBuffer.cpp">
     <ClCompile Include="Source\CmGenericBuffer.cpp">
       <Filter>Source Files\RenderSystem</Filter>
       <Filter>Source Files\RenderSystem</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="Source\CmGenericBufferView.cpp">
+      <Filter>Source Files\RenderSystem</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
 </Project>
 </Project>

+ 22 - 4
CamelotRenderer/Include/CmGenericBuffer.h

@@ -2,6 +2,7 @@
 
 
 #include "CmPrerequisites.h"
 #include "CmPrerequisites.h"
 #include "CmCommonEnums.h"
 #include "CmCommonEnums.h"
+#include "CmGenericBufferView.h"
 
 
 namespace CamelotEngine 
 namespace CamelotEngine 
 {
 {
@@ -16,10 +17,8 @@ namespace CamelotEngine
 	class CM_EXPORT GenericBuffer
 	class CM_EXPORT GenericBuffer
     {
     {
     public:
     public:
-        GenericBuffer(UINT32 elementCount, UINT32 elementSize, GenericBufferType type, GpuBufferUsage usage, bool randomGpuWrite = false, bool useCounter = false)
-			:mElementCount(elementCount), mElementSize(elementSize), mType(type), mUsage(usage), mRandomGpuWrite(randomGpuWrite), mUseCounter(useCounter)
-        {  }
-        virtual ~GenericBuffer() {}
+        GenericBuffer(UINT32 elementCount, UINT32 elementSize, GenericBufferType type, GpuBufferUsage usage, bool randomGpuWrite = false, bool useCounter = false);
+        virtual ~GenericBuffer();
 
 
 		virtual void* lock(UINT32 offset, UINT32 length, GpuLockOptions options) = 0;
 		virtual void* lock(UINT32 offset, UINT32 length, GpuLockOptions options) = 0;
 		virtual void unlock() = 0;
 		virtual void unlock() = 0;
@@ -30,6 +29,9 @@ namespace CamelotEngine
 		virtual void copyData(GenericBuffer& srcBuffer, UINT32 srcOffset, 
 		virtual void copyData(GenericBuffer& srcBuffer, UINT32 srcOffset, 
 			UINT32 dstOffset, UINT32 length, bool discardWholeBuffer = false) = 0;
 			UINT32 dstOffset, UINT32 length, bool discardWholeBuffer = false) = 0;
 
 
+		GenericBufferView* requestView(UINT32 firstElement, UINT32 elementWidth, UINT32 numElements, bool randomGpuWrite);
+		void releaseView(GenericBufferView* view);
+
 	protected:
 	protected:
 		GenericBufferType mType;
 		GenericBufferType mType;
 		GpuBufferUsage mUsage;
 		GpuBufferUsage mUsage;
@@ -37,5 +39,21 @@ namespace CamelotEngine
 		bool mUseCounter;
 		bool mUseCounter;
 		UINT32 mElementCount;
 		UINT32 mElementCount;
 		UINT32 mElementSize;
 		UINT32 mElementSize;
+
+		virtual GenericBufferView* createView(UINT32 firstElement, UINT32 elementWidth, UINT32 numElements, bool randomGpuWrite) = 0;
+		virtual void destroyView(GenericBufferView* view) = 0;
+		void clearBufferViews();
+
+		struct GenericBufferReference
+		{
+			GenericBufferReference(GenericBufferView* _view)
+				:view(_view), refCount(0)
+			{ }
+
+			GenericBufferView* view;
+			UINT32 refCount;
+		};
+
+		std::unordered_map<GenericBufferView::Key, GenericBufferReference*, GenericBufferView::HashFunction, GenericBufferView::EqualFunction> mBufferViews;
     };
     };
 }
 }

+ 52 - 0
CamelotRenderer/Include/CmGenericBufferView.h

@@ -0,0 +1,52 @@
+#pragma once
+
+#include "CmPrerequisites.h"
+
+namespace CamelotEngine
+{
+	class CM_EXPORT GenericBufferView
+	{
+	public:
+		struct Key
+		{
+			Key()
+			{ }
+
+			Key(const GenericBufferView& view)
+				: mFirstElement(view.mFirstElement), mElementWidth(view.mElementWidth)
+				, mNumElements(view.mNumElements), mRandomGpuWrite(view.mRandomGpuWrite)
+			{ }
+
+			Key(UINT32 firstElement, UINT32 elementWidth, UINT32 numElements, bool randomGpuWrite)
+				: mFirstElement(firstElement), mElementWidth(elementWidth)
+				, mNumElements(numElements), mRandomGpuWrite(randomGpuWrite)
+			{ }
+
+			UINT32 mFirstElement;
+			UINT32 mElementWidth;
+			UINT32 mNumElements;
+			bool mRandomGpuWrite;
+		};
+
+		class HashFunction
+		{
+		public:
+			size_t operator()(const Key &key) const;
+		};
+
+		class EqualFunction
+		{
+		public:
+			bool operator()(const Key &a, const Key &b) const;
+		};
+
+		GenericBufferView(UINT32 firstElement, UINT32 elementWidth, UINT32 numElements, bool randomGpuWrite);
+		virtual ~GenericBufferView();
+
+	private:
+		UINT32 mFirstElement;
+		UINT32 mElementWidth;
+		UINT32 mNumElements;
+		bool mRandomGpuWrite;
+	};
+}

+ 61 - 0
CamelotRenderer/Source/CmGenericBuffer.cpp

@@ -1,6 +1,67 @@
 #include "CmGenericBuffer.h"
 #include "CmGenericBuffer.h"
+#include "CmException.h"
 
 
 namespace CamelotEngine
 namespace CamelotEngine
 {
 {
+	GenericBuffer::GenericBuffer(UINT32 elementCount, UINT32 elementSize, GenericBufferType type, GpuBufferUsage usage, bool randomGpuWrite, bool useCounter)
+		:mElementCount(elementCount), mElementSize(elementSize), mType(type), mUsage(usage), mRandomGpuWrite(randomGpuWrite), mUseCounter(useCounter)
+	{  
+	}
 
 
+	GenericBuffer::~GenericBuffer() 
+	{
+		// Make sure that derived classes call clearBufferViews
+		// I can't call it here since it needs a virtual method call
+	}
+
+	void GenericBuffer::clearBufferViews()
+	{
+		for(auto iter = mBufferViews.begin(); iter != mBufferViews.end(); ++iter)
+		{
+			destroyView(iter->second->view);
+			delete iter->second;
+		}
+
+		mBufferViews.clear();
+	}
+
+	GenericBufferView* GenericBuffer::requestView(UINT32 firstElement, UINT32 elementWidth, UINT32 numElements, bool randomGpuWrite)
+	{
+		GenericBufferView::Key key(firstElement, elementWidth, numElements, randomGpuWrite);
+
+		auto iterFind = mBufferViews.find(key);
+		if(iterFind == mBufferViews.end())
+		{
+			GenericBufferView* newView = createView(firstElement, elementWidth, numElements, randomGpuWrite);
+			mBufferViews[key] = new GenericBufferReference(newView);
+
+			iterFind = mBufferViews.find(key);
+		}
+
+		iterFind->second->refCount++;
+		return iterFind->second->view;
+	}
+
+	void GenericBuffer::releaseView(GenericBufferView* view)
+	{
+		GenericBufferView::Key key(*view);
+
+		auto iterFind = mBufferViews.find(key);
+		if(iterFind == mBufferViews.end())
+		{
+			CM_EXCEPT(InternalErrorException, "Trying to release a buffer that doesn't exist!");
+		}
+
+		iterFind->second->refCount--;
+
+		if(iterFind->second->refCount == 0)
+		{
+			GenericBufferReference* toRemove = iterFind->second;
+
+			mBufferViews.erase(iterFind);
+
+			destroyView(toRemove->view);
+			delete toRemove;
+		}
+	}
 }
 }

+ 34 - 0
CamelotRenderer/Source/CmGenericBufferView.cpp

@@ -0,0 +1,34 @@
+#include "CmGenericBufferView.h"
+#include "CmUtil.h"
+
+namespace CamelotEngine
+{
+	size_t GenericBufferView::HashFunction::operator()(const Key &key) const
+	{
+		size_t seed = 0;
+		hash_combine(seed, key.mElementWidth);
+		hash_combine(seed, key.mFirstElement);
+		hash_combine(seed, key.mNumElements);
+		hash_combine(seed, key.mRandomGpuWrite);
+
+		return seed;
+	}
+
+	bool GenericBufferView::EqualFunction::operator()
+		(const Key &a, const Key &b) const
+	{
+		return a.mElementWidth == b.mElementWidth && a.mFirstElement == b.mFirstElement 
+			&& a.mNumElements == b.mNumElements && a.mRandomGpuWrite == b.mRandomGpuWrite;
+	}
+
+	GenericBufferView::GenericBufferView(UINT32 firstElement, UINT32 elementWidth, UINT32 numElements, bool randomGpuWrite)
+		:mFirstElement(firstElement), mElementWidth(elementWidth), mNumElements(numElements), mRandomGpuWrite(randomGpuWrite)
+	{
+
+	}
+
+	GenericBufferView::~GenericBufferView()
+	{
+
+	}
+}

+ 56 - 25
CamelotRenderer/TODO.txt

@@ -12,7 +12,41 @@
 
 
 -----------------------IMMEDIATE TODO---------------------------------------------------------------
 -----------------------IMMEDIATE TODO---------------------------------------------------------------
 
 
-
+Plan until end of February:
+Week A:
+ Generic buffers DX11 and dummy implementations (that log warnings) for DX9 and OpenGL
+ Texture buffers in DX11 and OpenGL
+ A way to bind buffers to a Pass, while specifying buffer range
+
+Week B:
+ Stream out (mainly OpenGL)
+ Static/Dynamic usage for GpuParamBlocks
+ GpuParams support for bools, buffers, structs
+
+Week C:
+ Refactor render system methods to comply with DX11
+ Implement working DX11 render system Part 1
+
+Week D:
+ Implement working DX11 render system Part 2
+
+Week E:
+ Refactor so that primary window is created with rendersystem initialization
+ Make RenderTexture and DepthStenciLTexture use common interface
+
+Week F:
+ Ability to switch out GpuParamBlocks
+ Smart way of initializing GpuParamBlocks (without duplicates)
+ Port CG so it no longer uses low level shaders
+ Fix MaterialRTTI saving (Save params per gpuprogram is simplest and cleanest)
+ Make sure that gpu programs assigned to Pass don't share parameters of different types
+
+Week G:
+ Refactor how we handle RenderTargets (no attach/detach, and no waitForVSync propery in RenderSystem)
+ Fix how and when is GpuParamBlock created/destroyed. Needs to happen on the render thread
+
+>>>>>>>>>>>>>>>START WORKING ON THE EDITOR!
+ 
 
 
 
 
 
 
@@ -21,7 +55,6 @@
 
 
 Destroying and constructing GpuParamBlock happens on main thread, which is wrong (especially destroying it)
 Destroying and constructing GpuParamBlock happens on main thread, which is wrong (especially destroying it)
 
 
-Uniform buffers for GL are all set up but don't actually work :/
 Saving/loading of material params isn't completed (in MAterialRTTI)
 Saving/loading of material params isn't completed (in MAterialRTTI)
 Port DX11 to new shader param system
 Port DX11 to new shader param system
 Ability to switch out GpuParamBlocks (i.e. share them between programs)
 Ability to switch out GpuParamBlocks (i.e. share them between programs)
@@ -69,36 +102,32 @@ Figure out how to handle accessing texture from a non-render thread?
 
 
 RenderSystem needed modifications
 RenderSystem needed modifications
  - High priority
  - High priority
+  - Figure out how to handle different resource views and setting them on Passes
+    - Specifying buffer & texture ranges
+	- Setting UAV for both buffers and textures (Need to add a special flag for texture creation)
   - Generic buffers (Normal/Structured/Raw/Append/Consume/Indirect)
   - Generic buffers (Normal/Structured/Raw/Append/Consume/Indirect)
-  - Unordered access view for OM and CS stages (this should probably just be a flag .enableRandomWrite on Texture & Buffer classes)
-  - Pass needs to be modified
-   - Needs to support bool/double/texture1D/textue3D/textureCUBE/texture arrays/MS textures/all types of buffers/structs
-   - Needs to support (*void) data type for setting structs in constant buffers
-  - Right now HLSL11 CANNOT SPECIFY TEXTURE PARAMETERS! (Pass needs to be extended)
+  - Texture buffers 
+  - Stream out (write vertex buffers) (DX11 and GL)
+  - Static/Dynamic usage for GpuParamBlocks
+  - GpuParams need to support bools, buffers & structs (void*)
   - Tesselation (hull/domain) shader
   - Tesselation (hull/domain) shader
-  - Stream out (write vertex buffers)
-  - Append/Consume buffer
-  - Instancing (DrawInstanced, also check DrawIndirect)
-  - 1D/2D/Cube texture arrays
-  - Rendertargets that aren't just 2D (Volumetric (3D) render targets in particular)
-  - DX11 allows detachable and reusable depthStencil buffers but right now DX9 and OpenGL just ignore them
-	- Also RenderWindow can't have detachable depth stencil buffers for multiple reasons:
-		- Resizing a window requires a resize of the depth/stencil buffer, so what to do if the buffer is external?
-		- OpenGL doesn't allow access to primary window buffer anyway
-		- Is there any situation where I actually need to set primary depth buffer?
- - Process OpenGL and make sure to equivalents of DX11 features
-  - Exact features that are missing (not an exhaustive list):
-    - Vertex buffer stream out (Transform Feedback)
-	- Instancing
-	- HLSL11 shader equivalents (domain/hull/compute shaders), and advanced shader parameters
- - HLSL9/HLSL11/GLSL/Cg shaders need preprocessor defines & includes
+  - Detachable and readable depthstencil buffer (Window buffers not required as they behave a bit differently in OpenGL)
+   - Also make DepthStencilBuffer share common features with RenderTexture
+  
  - Low priority
  - Low priority
+  - Single and dual channel textures (especially render textures, which are very important for effects like SSAO)
   - Compute pipeline
   - Compute pipeline
+  - Instancing (DrawInstanced) (DX11 and GL)
+  - OpenGL append/consume buffers
+  - Indirect drawing via indirect argument buffers
+  - Texture arrays
+  - Rendertargets that aren't just 2D (Volumetric (3D) render targets in particular)
+  - Shader support for doubles
   - Dynamic shader linkage (Interfaces and similar)
   - Dynamic shader linkage (Interfaces and similar)
   - Multisampled texture resources
   - Multisampled texture resources
   - Multiple adapters (multi gpu)
   - Multiple adapters (multi gpu)
-  - Texture buffers 
-    - Essentially a glorified 1D texture, but they don't have 1D texture size limitations
+  - HLSL9/HLSL11/GLSL/Cg shaders need preprocessor defines & includes
+
 
 
 
 
 
 
@@ -106,6 +135,7 @@ Command buffer TODO:
  - When importing a resource, and registering it with Resources I don't think it properly gets added to the loaded resources array? For some reason shaders get created twice.
  - When importing a resource, and registering it with Resources I don't think it properly gets added to the loaded resources array? For some reason shaders get created twice.
  - Doing setPixels_async in the texture doesn't make sure that the user doesn't actually modify the provided PixelData after
  - Doing setPixels_async in the texture doesn't make sure that the user doesn't actually modify the provided PixelData after
     that call.
     that call.
+ - In general I need to rethink how to handle modifying resources with multithreading
 
 
 Mesh
 Mesh
  - Make sure to queue up mesh deletion to make sure it gets destroyed on the render thread
  - Make sure to queue up mesh deletion to make sure it gets destroyed on the render thread
@@ -142,6 +172,7 @@ Mid priority TODO:
      I need to make sure that HighLevelGpuProgram class has valid RTTI type as well. Otherwise the inheritance hierarchy will not be correct. Right now this isn't checked anywhere.
      I need to make sure that HighLevelGpuProgram class has valid RTTI type as well. Otherwise the inheritance hierarchy will not be correct. Right now this isn't checked anywhere.
 
 
 Low priority TODO:
 Low priority TODO:
+ - Can I assign a RenderTexture to a Pass?
  - Mesh loading:
  - Mesh loading:
   - Sub-meshes aren't being transformed by world matrices of their nodes
   - Sub-meshes aren't being transformed by world matrices of their nodes
  - Are resource getting properly unloaded? e.g. when shared_ptr destroys a texture is it removed from gpu?
  - Are resource getting properly unloaded? e.g. when shared_ptr destroys a texture is it removed from gpu?

+ 1 - 0
CamelotUtility/CamelotUtility.vcxproj

@@ -209,6 +209,7 @@
     <ClInclude Include="Include\CmRay.h" />
     <ClInclude Include="Include\CmRay.h" />
     <ClInclude Include="Include\CmSphere.h" />
     <ClInclude Include="Include\CmSphere.h" />
     <ClInclude Include="Include\CmStdHeaders.h" />
     <ClInclude Include="Include\CmStdHeaders.h" />
+    <ClInclude Include="Include\CmUtil.h" />
     <ClInclude Include="Include\CmUUID.h" />
     <ClInclude Include="Include\CmUUID.h" />
     <ClInclude Include="Include\CmVector2.h" />
     <ClInclude Include="Include\CmVector2.h" />
     <ClInclude Include="Include\CmVector3.h" />
     <ClInclude Include="Include\CmVector3.h" />

+ 3 - 0
CamelotUtility/CamelotUtility.vcxproj.filters

@@ -204,6 +204,9 @@
     <ClInclude Include="Include\CmPixelDataRTTI.h">
     <ClInclude Include="Include\CmPixelDataRTTI.h">
       <Filter>Header Files\RTTI</Filter>
       <Filter>Header Files\RTTI</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="Include\CmUtil.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="Include\CmAxisAlignedBox.cpp">
     <ClCompile Include="Include\CmAxisAlignedBox.cpp">

+ 13 - 0
CamelotUtility/Include/CmUtil.h

@@ -0,0 +1,13 @@
+#pragma once
+
+#include "CmPrerequisitesUtil.h"
+
+namespace CamelotEngine
+{
+	template <class T>
+	inline void hash_combine(std::size_t& seed, const T& v)
+	{
+		std::hash<T> hasher;
+		seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
+	}
+}