Explorar el Código

Added generic GPU buffer support to DX11 and OpenGL

BearishSun hace 9 años
padre
commit
deab7206d5
Se han modificado 55 ficheros con 1255 adiciones y 320 borrados
  1. 42 0
      Source/BansheeCore/Include/BsCommonTypes.h
  2. 15 12
      Source/BansheeCore/Include/BsGpuBuffer.h
  3. 1 0
      Source/BansheeCore/Include/BsGpuBufferView.h
  4. 39 0
      Source/BansheeCore/Include/BsGpuParam.h
  5. 17 0
      Source/BansheeCore/Include/BsGpuParams.h
  6. 1 1
      Source/BansheeCore/Include/BsHardwareBuffer.h
  7. 19 12
      Source/BansheeCore/Include/BsHardwareBufferManager.h
  8. 36 0
      Source/BansheeCore/Include/BsMaterial.h
  9. 44 0
      Source/BansheeCore/Include/BsMaterialParam.h
  10. 35 3
      Source/BansheeCore/Include/BsMaterialParams.h
  11. 20 0
      Source/BansheeCore/Include/BsRenderAPI.h
  12. 70 15
      Source/BansheeCore/Source/BsGpuBuffer.cpp
  13. 3 2
      Source/BansheeCore/Source/BsGpuBufferView.cpp
  14. 34 0
      Source/BansheeCore/Source/BsGpuParam.cpp
  15. 91 6
      Source/BansheeCore/Source/BsGpuParams.cpp
  16. 6 4
      Source/BansheeCore/Source/BsHardwareBufferManager.cpp
  17. 51 0
      Source/BansheeCore/Source/BsMaterial.cpp
  18. 65 0
      Source/BansheeCore/Source/BsMaterialParam.cpp
  19. 69 16
      Source/BansheeCore/Source/BsMaterialParams.cpp
  20. 18 0
      Source/BansheeCore/Source/BsRenderAPI.cpp
  21. 15 8
      Source/BansheeD3D11RenderAPI/Include/BsD3D11GpuBuffer.h
  22. 6 0
      Source/BansheeD3D11RenderAPI/Include/BsD3D11GpuBufferView.h
  23. 2 2
      Source/BansheeD3D11RenderAPI/Include/BsD3D11HardwareBufferManager.h
  24. 3 0
      Source/BansheeD3D11RenderAPI/Include/BsD3D11Mappings.h
  25. 1 0
      Source/BansheeD3D11RenderAPI/Include/BsD3D11Prerequisites.h
  26. 3 0
      Source/BansheeD3D11RenderAPI/Include/BsD3D11RenderAPI.h
  27. 27 3
      Source/BansheeD3D11RenderAPI/Source/BsD3D11GpuBuffer.cpp
  28. 8 6
      Source/BansheeD3D11RenderAPI/Source/BsD3D11GpuBufferView.cpp
  29. 3 3
      Source/BansheeD3D11RenderAPI/Source/BsD3D11HardwareBuffer.cpp
  30. 3 2
      Source/BansheeD3D11RenderAPI/Source/BsD3D11HardwareBufferManager.cpp
  31. 50 0
      Source/BansheeD3D11RenderAPI/Source/BsD3D11Mappings.cpp
  32. 67 0
      Source/BansheeD3D11RenderAPI/Source/BsD3D11RenderAPI.cpp
  33. 2 2
      Source/BansheeD3D9RenderAPI/Include/BsD3D9GpuBuffer.h
  34. 2 2
      Source/BansheeD3D9RenderAPI/Include/BsD3D9HardwareBufferManager.h
  35. 3 0
      Source/BansheeD3D9RenderAPI/Include/BsD3D9RenderAPI.h
  36. 3 3
      Source/BansheeD3D9RenderAPI/Source/BsD3D9GpuBuffer.cpp
  37. 2 2
      Source/BansheeD3D9RenderAPI/Source/BsD3D9HardwareBufferManager.cpp
  38. 7 0
      Source/BansheeD3D9RenderAPI/Source/BsD3D9RenderAPI.cpp
  39. 10 0
      Source/BansheeEngine/Source/BsRendererUtility.cpp
  40. 2 0
      Source/BansheeGLRenderAPI/CMakeSources.cmake
  41. 69 0
      Source/BansheeGLRenderAPI/Include/BsGLBuffer.h
  42. 20 4
      Source/BansheeGLRenderAPI/Include/BsGLGpuBuffer.h
  43. 2 2
      Source/BansheeGLRenderAPI/Include/BsGLHardwareBufferManager.h
  44. 3 3
      Source/BansheeGLRenderAPI/Include/BsGLIndexBuffer.h
  45. 4 0
      Source/BansheeGLRenderAPI/Include/BsGLPixelFormat.h
  46. 3 0
      Source/BansheeGLRenderAPI/Include/BsGLRenderAPI.h
  47. 3 3
      Source/BansheeGLRenderAPI/Include/BsGLVertexBuffer.h
  48. 106 0
      Source/BansheeGLRenderAPI/Source/BsGLBuffer.cpp
  49. 38 4
      Source/BansheeGLRenderAPI/Source/BsGLGpuBuffer.cpp
  50. 3 2
      Source/BansheeGLRenderAPI/Source/BsGLHardwareBufferManager.cpp
  51. 16 103
      Source/BansheeGLRenderAPI/Source/BsGLIndexBuffer.cpp
  52. 50 0
      Source/BansheeGLRenderAPI/Source/BsGLPixelFormat.cpp
  53. 18 0
      Source/BansheeGLRenderAPI/Source/BsGLRenderAPI.cpp
  54. 18 0
      Source/BansheeGLRenderAPI/Source/BsGLSLParamParser.cpp
  55. 7 95
      Source/BansheeGLRenderAPI/Source/BsGLVertexBuffer.cpp

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

@@ -159,6 +159,8 @@ namespace BansheeEngine
 	/** Types of generic GPU buffers that may be attached to GPU programs. */
 	enum GpuBufferType
 	{
+		/** Buffer containing an array of primitives (e.g. float4's). */
+		GBT_STANDARD,
 		/** 
 		 * Buffer containing an array of structures. Structure parameters can usually be easily accessed from within the
 		 * GPU program.
@@ -175,6 +177,46 @@ namespace BansheeEngine
 		GBT_APPENDCONSUME
 	};
 
+	/** Types of valid formats used for standard GPU buffers. */
+	enum GpuBufferFormat
+	{
+		BF_16X1F, /**< 1D 16-bit floating-point format. */
+		BF_16X2F, /**< 2D 16-bit floating-point format. */
+		BF_16X4F, /**< 4D 16-bit floating-point format. */
+		BF_32X1F, /**< 1D 32-bit floating-point format. */
+		BF_32X2F, /**< 2D 32-bit floating-point format. */
+		BF_32X3F, /**< 3D 32-bit floating-point format. */
+		BF_32X4F, /**< 4D 32-bit floating-point format. */
+		BF_8X1,   /**< 1D 8-bit normalized format. */
+		BF_8X2,   /**< 2D 8-bit normalized format. */
+		BF_8X4,   /**< 4D 8-bit normalized format. */
+		BF_16X1,  /**< 1D 16-bit normalized format. */
+		BF_16X2,  /**< 2D 16-bit normalized format. */
+		BF_16X4,  /**< 4D 16-bit normalized format. */
+		BF_8X1S,  /**< 1D 8-bit signed integer format. */
+		BF_8X2S,  /**< 2D 8-bit signed integer format. */
+		BF_8X4S,  /**< 4D 8-bit signed integer format. */
+		BF_16X1S, /**< 1D 16-bit signed integer format. */
+		BF_16X2S, /**< 2D 16-bit signed integer format. */
+		BF_16X4S, /**< 4D 16-bit signed integer format. */
+		BF_32X1S, /**< 1D 32-bit signed integer format. */
+		BF_32X2S, /**< 2D 32-bit signed integer format. */
+		BF_32X3S, /**< 3D 32-bit signed integer format. */
+		BF_32X4S, /**< 4D 32-bit signed integer format. */
+		BF_8X1U,  /**< 1D 8-bit unsigned integer format. */
+		BF_8X2U,  /**< 2D 8-bit unsigned integer format. */
+		BF_8X4U,  /**< 4D 8-bit unsigned integer format. */
+		BF_16X1U, /**< 1D 16-bit unsigned integer format. */
+		BF_16X2U, /**< 2D 16-bit unsigned integer format. */
+		BF_16X4U, /**< 4D 16-bit unsigned integer format. */
+		BF_32X1U, /**< 1D 32-bit unsigned integer format. */
+		BF_32X2U, /**< 2D 32-bit unsigned integer format. */
+		BF_32X3U, /**< 3D 32-bit unsigned integer format. */
+		BF_32X4U, /**< 4D 32-bit unsigned integer format. */
+		BF_COUNT, /**< Not a valid format. Keep just before BS_UNKNOWN. */
+		BF_UNKNOWN = 0xffff /**< Unknown format (used for non-standard buffers, like structured or raw. */
+	};
+
 	/** Different types of GPU views that control how GPU sees a hardware buffer. */
 	enum GpuViewUsage
 	{

+ 15 - 12
Source/BansheeCore/Include/BsGpuBuffer.h

@@ -19,7 +19,7 @@ namespace BansheeEngine
 	class BS_CORE_EXPORT GpuBufferProperties
 	{
 	public:
-		GpuBufferProperties(UINT32 elementCount, UINT32 elementSize, GpuBufferType type, 
+		GpuBufferProperties(UINT32 elementCount, UINT32 elementSize, GpuBufferType type, GpuBufferFormat format,
 			GpuBufferUsage usage, bool randomGpuWrite, bool useCounter);
 
 		/**
@@ -28,6 +28,9 @@ namespace BansheeEngine
 		 */
 		GpuBufferType getType() const { return mType; }
 
+		/** Returns format used by the buffer. Only relevant for standard buffers. */
+		GpuBufferFormat getFormat() const { return mFormat; }
+
 		/** Returns buffer usage which determines how are planning on updating the buffer contents. */
 		GpuBufferUsage getUsage() const { return mUsage; }
 
@@ -46,6 +49,7 @@ namespace BansheeEngine
 	protected:
 		GpuBufferType mType;
 		GpuBufferUsage mUsage;
+		GpuBufferFormat mFormat;
 		bool mRandomGpuWrite;
 		bool mUseCounter;
 		UINT32 mElementCount;
@@ -80,18 +84,18 @@ namespace BansheeEngine
 		/** Retrieves a core implementation of a GPU buffer usable only from the core thread. */
 		SPtr<GpuBufferCore> getCore() const;
 
+		/** Returns the size of a single element in the buffer, of the provided format, in bytes. */
+		static UINT32 getFormatSize(GpuBufferFormat format);
+
 	protected:
 		friend class HardwareBufferManager;
 
-		GpuBuffer(UINT32 elementCount, UINT32 elementSize, GpuBufferType type, GpuBufferUsage usage, 
+		GpuBuffer(UINT32 elementCount, UINT32 elementSize, GpuBufferType type, GpuBufferFormat format, GpuBufferUsage usage,
 			bool randomGpuWrite = false, bool useCounter = false);
 
 		/** @copydoc CoreObject::createCore */
 		SPtr<CoreObjectCore> createCore() const override;
 
-		/** @copydoc HardwareBufferManager::createGpuParamBlockBuffer */
-		static SPtr<GpuParamBlockBuffer> create(UINT32 size, GpuParamBlockUsage usage = GPBU_DYNAMIC);
-
 		GpuBufferProperties mProperties;
     };
 
@@ -169,17 +173,16 @@ namespace BansheeEngine
 		 *
 		 * @param[in]	buffer			Buffer to create the view for.
 		 * @param[in]	firstElement	Position of the first element visible by the view.
-		 * @param[in]	elementWidth	Width of one element in bytes.
-		 * @param[in]	numElements		Number of elements in the buffer.
-		 * @param[in]	useCounter		Should the buffer allow use of a counter. This is only relevant for random read write buffers.
-		 * @param[in]	usage			Determines type of the view we are creating, and which slots in the pipeline will the view be bindable to.
+		 * @param[in]	numElements		Number of elements to bind to the view.
+		 * @param[in]	usage			Determines type of the view we are creating, and which slots in the pipeline will
+		 *								the view be bindable to.
 		 *
 		 * @note If a view with this exact parameters already exists, it will be returned and new one will not be created.
 		 * @note Only Default and RandomWrite views are supported for this type of buffer. 
 		 */
 		// TODO Low Priority: Perhaps reflect usage flag limitation by having an enum with only the supported two options?
-		static GpuBufferView* requestView(const SPtr<GpuBufferCore>& buffer, UINT32 firstElement, UINT32 elementWidth, 
-			UINT32 numElements, bool useCounter, GpuViewUsage usage);
+		static GpuBufferView* requestView(const SPtr<GpuBufferCore>& buffer, UINT32 firstElement, 
+			UINT32 numElements, GpuViewUsage usage);
 
 		/**
 		 * Releases a view created with requestView. 
@@ -189,7 +192,7 @@ namespace BansheeEngine
 		static void releaseView(GpuBufferView* view);
 
 	protected:
-		GpuBufferCore(UINT32 elementCount, UINT32 elementSize, GpuBufferType type, 
+		GpuBufferCore(UINT32 elementCount, UINT32 elementSize, GpuBufferType type, GpuBufferFormat format,
 			GpuBufferUsage usage, bool randomGpuWrite = false, bool useCounter = false);
 
 		/** Creates an empty view for the current buffer. */

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

@@ -22,6 +22,7 @@ namespace BansheeEngine
 		UINT32 numElements;
 		bool useCounter;
 		GpuViewUsage usage;
+		GpuBufferFormat format;
 	};
 
 	/**

+ 39 - 0
Source/BansheeCore/Include/BsGpuParam.h

@@ -34,6 +34,10 @@ namespace BansheeEngine
 	template<> struct TGpuParamBufferType < false > { typedef SPtr<GpuParamBlockBuffer> Type; };
 	template<> struct TGpuParamBufferType < true > { typedef SPtr<GpuParamBlockBufferCore> Type; };
 
+	template<bool Core> struct TGpuBufferType { };
+	template<> struct TGpuBufferType < false > { typedef SPtr<GpuBuffer> Type; };
+	template<> struct TGpuBufferType < true > { typedef SPtr<GpuBufferCore> Type; };
+
 	/**
 	 * Policy class that allows us to re-use this template class for matrices which might need transposing, and other 
 	 * types which do not. Matrix needs to be transposed for certain render systems depending on how they store them 
@@ -220,6 +224,38 @@ namespace BansheeEngine
 		GpuParamObjectDesc* mParamDesc;
 	};
 
+	/** @copydoc TGpuDataParam */
+	template<bool Core>
+	class BS_CORE_EXPORT TGpuParamBuffer
+	{
+	private:
+		friend class GpuParams;
+		friend class GpuParamsCore;
+
+		typedef typename TGpuParamsPtrType<Core>::Type GpuParamsType;
+		typedef typename TGpuBufferType<Core>::Type BufferType;
+
+	public:
+		TGpuParamBuffer();
+		TGpuParamBuffer(GpuParamObjectDesc* paramDesc, const GpuParamsType& parent);
+
+		/** @copydoc TGpuDataParam::set */
+		void set(const BufferType& texture);
+
+		/** @copydoc TGpuDataParam::get */
+		BufferType get();
+
+		/** Checks if param is initialized. */
+		bool operator==(const nullptr_t &nullval) const
+		{
+			return mParamDesc == nullptr;
+		}
+
+	protected:
+		GpuParamsType mParent;
+		GpuParamObjectDesc* mParamDesc;
+	};
+
 	/** @copydoc TGpuDataParam */
 	template<bool Core>
 	class BS_CORE_EXPORT TGpuParamSampState
@@ -287,6 +323,9 @@ namespace BansheeEngine
 
 	typedef TGpuParamTexture<false> GpuParamTexture;
 	typedef TGpuParamTexture<true> GpuParamTextureCore;
+	
+	typedef TGpuParamBuffer<false> GpuParamBuffer;
+	typedef TGpuParamBuffer<true> GpuParamBufferCore;
 
 	typedef TGpuParamSampState<false> GpuParamSampState;
 	typedef TGpuParamSampState<true> GpuParamSampStateCore;

+ 17 - 0
Source/BansheeCore/Include/BsGpuParams.h

@@ -75,6 +75,9 @@ namespace BansheeEngine
 		/**	Checks if load/store texture parameter with the specified name exists. */
 		bool hasLoadStoreTexture(const String& name) const;
 
+		/**	Checks if buffer parameter with the specified name exists. */
+		bool hasBuffer(const String& name) const;
+
 		/**	Checks if sampler state parameter with the specified name exists. */
 		bool hasSamplerState(const String& name) const;
 
@@ -105,6 +108,7 @@ namespace BansheeEngine
 		UINT32 mNumParamBlocks;
 		UINT32 mNumTextures;
 		UINT32 mNumLoadStoreTextures;
+		UINT32 mNumBuffers;
 		UINT32 mNumSamplerStates;
 
 		TextureSurface* mLoadStoreSurfaces;
@@ -117,6 +121,7 @@ namespace BansheeEngine
 	{
 		typedef GpuParams GpuParamsType;
 		typedef HTexture TextureType;
+		typedef SPtr<GpuBuffer> BufferType;
 		typedef SPtr<SamplerState> SamplerType;
 		typedef SPtr<GpuParamBlockBuffer> ParamsBufferType;
 	};
@@ -125,6 +130,7 @@ namespace BansheeEngine
 	{
 		typedef GpuParamsCore GpuParamsType;
 		typedef SPtr<TextureCore> TextureType;
+		typedef SPtr<GpuBufferCore> BufferType;
 		typedef SPtr<SamplerStateCore> SamplerType;
 		typedef SPtr<GpuParamBlockBufferCore> ParamsBufferType;
 	};
@@ -136,6 +142,7 @@ namespace BansheeEngine
 	public:
 		typedef typename TGpuParamsTypes<Core>::GpuParamsType GpuParamsType;
 		typedef typename TGpuParamsTypes<Core>::TextureType TextureType;
+		typedef typename TGpuParamsTypes<Core>::BufferType BufferType;
 		typedef typename TGpuParamsTypes<Core>::SamplerType SamplerType;
 		typedef typename TGpuParamsTypes<Core>::ParamsBufferType ParamsBufferType;
 
@@ -186,6 +193,9 @@ namespace BansheeEngine
 		/** @copydoc getParam */
 		void getLoadStoreTextureParam(const String& name, TGpuParamLoadStoreTexture<Core>& output) const;
 
+		/** @copydoc getParam */
+		void getBufferParam(const String& name, TGpuParamBuffer<Core>& output) const;
+
 		/** @copydoc getParam */
 		void getSamplerStateParam(const String& name, TGpuParamSampState<Core>& output) const;
 
@@ -198,6 +208,9 @@ namespace BansheeEngine
 		/**	Gets a load/store texture bound to the specified slot. */
 		TextureType getLoadStoreTexture(UINT32 slot);
 
+		/**	Gets a buffer bound to the specified slot. */
+		BufferType getBuffer(UINT32 slot);
+
 		/**	Gets a sampler state bound to the specified slot. */
 		SamplerType getSamplerState(UINT32 slot);
 
@@ -207,6 +220,9 @@ namespace BansheeEngine
 		/**	Sets a load/store texture at the specified slot. */
 		void setLoadStoreTexture(UINT32 slot, const TextureType& texture, const TextureSurface& surface);
 
+		/**	Sets a buffer at the specified slot. */
+		void setBuffer(UINT32 slot, const BufferType& buffer);
+
 		/**	Sets a sampler state at the specified slot. */
 		void setSamplerState(UINT32 slot, const SamplerType& sampler);
 
@@ -217,6 +233,7 @@ namespace BansheeEngine
 		ParamsBufferType* mParamBlockBuffers;
 		TextureType* mTextures;
 		TextureType* mLoadStoreTextures;
+		BufferType* mBuffers;
 		SamplerType* mSamplerStates;
 	};
 

+ 1 - 1
Source/BansheeCore/Include/BsHardwareBuffer.h

@@ -54,7 +54,7 @@ namespace BansheeEngine
             return this->lock(0, mSizeInBytes, options);
         }
 
-		/**	Releases the lock on this buffer.  */
+		/**	Releases the lock on this buffer. */
 		virtual void unlock()
         {
             assert(isLocked() && "Cannot unlock this buffer, it is not locked!");

+ 19 - 12
Source/BansheeCore/Include/BsHardwareBufferManager.h

@@ -34,7 +34,8 @@ namespace BansheeEngine
 		 * @param[in]	usage		Usage that tells the hardware how will be buffer be used. 
 		 * @param[in]	streamOut	If true the buffer will be usable for streaming out data from the GPU.
 		 */
-		virtual SPtr<VertexBuffer> createVertexBuffer(UINT32 vertexSize, UINT32 numVerts, GpuBufferUsage usage, bool streamOut = false);
+		virtual SPtr<VertexBuffer> createVertexBuffer(UINT32 vertexSize, UINT32 numVerts, GpuBufferUsage usage, 
+			bool streamOut = false);
 
 		/**
 		 * Creates a new index buffer that holds indices referencing vertices in a vertex buffer. Indices are interpreted 
@@ -63,6 +64,7 @@ namespace BansheeEngine
 		 * @param[in]	elementCount  	Number of elements in the buffer. 
 		 * @param[in]	elementSize   	Size of each individual element in the buffer, in bytes.
 		 * @param[in]	type		  	Type of the buffer.
+		 * @param[in]	format			Format if the data in the buffer. Only relevant for standard buffers.
 		 * @param[in]	usage		  	Usage that tells the hardware how will be buffer be used. 
 		 * @param[in]	randomGpuWrite	(optional) Allows the GPU to write to the resource.
 		 * @param[in]	useCounter	  	(optional) Binds a counter that can be used from a GPU program on the buffer.
@@ -71,8 +73,8 @@ namespace BansheeEngine
 		 * Be aware that due to some render API restrictions some of these settings cannot be used together, and if so you 
 		 * will receive an assert in debug mode.
 		 */
-		virtual SPtr<GpuBuffer> createGpuBuffer(UINT32 elementCount, UINT32 elementSize, 
-			GpuBufferType type, GpuBufferUsage usage, bool randomGpuWrite = false, bool useCounter = false);
+		virtual SPtr<GpuBuffer> createGpuBuffer(UINT32 elementCount, UINT32 elementSize, GpuBufferType type, 
+			GpuBufferFormat format, GpuBufferUsage usage, bool randomGpuWrite = false, bool useCounter = false);
 
 		/** Creates a new vertex declaration from a list of vertex elements. */
 		virtual SPtr<VertexDeclaration> createVertexDeclaration(const SPtr<VertexDataDesc>& desc);
@@ -89,7 +91,8 @@ namespace BansheeEngine
 		virtual ~HardwareBufferCoreManager() { }
 
 		/** @copydoc HardwareBufferManager::createVertexBuffer */
-		virtual SPtr<VertexBufferCore> createVertexBuffer(UINT32 vertexSize, UINT32 numVerts, GpuBufferUsage usage, bool streamOut = false);
+		virtual SPtr<VertexBufferCore> createVertexBuffer(UINT32 vertexSize, UINT32 numVerts, GpuBufferUsage usage, 
+			bool streamOut = false);
 
 		/** @copydoc HardwareBufferManager::createIndexBuffer */
 		virtual SPtr<IndexBufferCore> createIndexBuffer(IndexType itype, UINT32 numIndices, GpuBufferUsage usage);
@@ -101,11 +104,12 @@ namespace BansheeEngine
 		virtual SPtr<VertexDeclarationCore> createVertexDeclaration(const List<VertexElement>& elements);
 
 		/** @copydoc HardwareBufferManager::createGpuParamBlockBuffer */
-		virtual SPtr<GpuParamBlockBufferCore> createGpuParamBlockBuffer(UINT32 size, GpuParamBlockUsage usage = GPBU_DYNAMIC);
+		virtual SPtr<GpuParamBlockBufferCore> createGpuParamBlockBuffer(UINT32 size, 
+			GpuParamBlockUsage usage = GPBU_DYNAMIC);
 
 		/** @copydoc HardwareBufferManager::createGpuBuffer */
-		virtual SPtr<GpuBufferCore> createGpuBuffer(UINT32 elementCount, UINT32 elementSize, 
-			GpuBufferType type, GpuBufferUsage usage, bool randomGpuWrite = false, bool useCounter = false);
+		virtual SPtr<GpuBufferCore> createGpuBuffer(UINT32 elementCount, UINT32 elementSize, GpuBufferType type, 
+			GpuBufferFormat format, GpuBufferUsage usage, bool randomGpuWrite = false, bool useCounter = false);
 
 	protected:
 		friend class IndexBuffer;
@@ -117,17 +121,20 @@ namespace BansheeEngine
 		friend class GpuBuffer;
 
 		/** @copydoc createVertexBuffer */
-		virtual SPtr<VertexBufferCore> createVertexBufferInternal(UINT32 vertexSize, UINT32 numVerts, GpuBufferUsage usage, bool streamOut = false) = 0;
+		virtual SPtr<VertexBufferCore> createVertexBufferInternal(UINT32 vertexSize, UINT32 numVerts, GpuBufferUsage usage, 
+			bool streamOut = false) = 0;
 
 		/** @copydoc createIndexBuffer */
-		virtual SPtr<IndexBufferCore> createIndexBufferInternal(IndexType itype, UINT32 numIndices, GpuBufferUsage usage) = 0;
+		virtual SPtr<IndexBufferCore> createIndexBufferInternal(IndexType itype, UINT32 numIndices, 
+			GpuBufferUsage usage) = 0;
 
 		/** @copydoc createGpuParamBlockBuffer */
-		virtual SPtr<GpuParamBlockBufferCore> createGpuParamBlockBufferInternal(UINT32 size, GpuParamBlockUsage usage = GPBU_DYNAMIC) = 0;
+		virtual SPtr<GpuParamBlockBufferCore> createGpuParamBlockBufferInternal(UINT32 size, 
+			GpuParamBlockUsage usage = GPBU_DYNAMIC) = 0;
 
 		/** @copydoc createGpuBuffer */
-		virtual SPtr<GpuBufferCore> createGpuBufferInternal(UINT32 elementCount, UINT32 elementSize,
-			GpuBufferType type, GpuBufferUsage usage, bool randomGpuWrite = false, bool useCounter = false) = 0;
+		virtual SPtr<GpuBufferCore> createGpuBufferInternal(UINT32 elementCount, UINT32 elementSize, GpuBufferType type, 
+			GpuBufferFormat format, GpuBufferUsage usage, bool randomGpuWrite = false, bool useCounter = false) = 0;
 
 		/** @copydoc createVertexDeclaration */
 		virtual SPtr<VertexDeclarationCore> createVertexDeclarationInternal(const List<VertexElement>& elements);

+ 36 - 0
Source/BansheeCore/Include/BsMaterial.h

@@ -161,6 +161,7 @@ namespace BansheeEngine
 	public:
 		typedef typename TGpuParamsPtrType<Core>::Type GpuParamsType;
 		typedef typename TGpuParamTextureType<Core>::Type TextureType;
+		typedef typename TGpuBufferType<Core>::Type BufferType;
 		typedef typename TGpuParamSamplerStateType<Core>::Type SamplerStateType;
 		typedef typename TGpuParamBlockBufferPtrType<Core>::Type ParamBlockPtrType;
 		typedef typename TGpuParamBlockBufferType<Core>::Type ParamBlockType;
@@ -249,6 +250,9 @@ namespace BansheeEngine
 			return getParamLoadStoreTexture(name).set(value, surface); 
 		}
 
+		/** Assigns a buffer to the shader parameter with the specified name. */
+		void setBuffer(const String& name, const BufferType& value) { return getParamBuffer(name).set(value); }
+
 		/** Assigns a sampler state to the shader parameter with the specified name. */
 		void setSamplerState(const String& name, const SamplerStateType& value) { return getParamSamplerState(name).set(value); }
 
@@ -484,6 +488,18 @@ namespace BansheeEngine
 		 */
 		TMaterialParamLoadStoreTexture<Core> getParamLoadStoreTexture(const String& name) const;
 
+		/**
+		 * Returns a buffer GPU parameter. This parameter may be used for more efficiently getting/setting GPU parameter 
+		 * values than calling Material::get* / Material::set* methods. 
+		 *
+		 * @note	
+		 * Expected behavior is that you would retrieve this parameter when initially constructing the material, and then 
+		 * use it throughout material lifetime to assign and retrieve parameter values.
+		 * @note
+		 * If material shader changes this handle will be invalidated.
+		 */
+		TMaterialParamBuffer<Core> getParamBuffer(const String& name) const;
+
 		/**
 		 * Returns a sampler state GPU parameter. This parameter may be used for more efficiently getting/setting GPU 
 		 * parameter values than calling Material::get* / Material::set* methods. 
@@ -603,6 +619,26 @@ namespace BansheeEngine
 			return TMaterialParamLoadStoreTexture<true>(gpuParams);
 		}
 
+		/** 
+		 * Creates a material param out of multiple GPU params. Caller must ensure all GPU params reference the same 
+		 * parameter. 
+		 */
+		TMaterialParamBuffer<false> createBufferParam(const String& name, 
+			const SPtr<Vector<TGpuParamBuffer<false>>>& gpuParams) const
+		{
+			return TMaterialParamBuffer<false>(name, getCachedParams(), gpuParams);
+		}
+
+		/** 
+		 * Creates a material param out of multiple GPU params. Caller must ensure all GPU params reference the same 
+		 * parameter. 
+		 */
+		TMaterialParamBuffer<true> createBufferParam(const String& name,
+			const SPtr<Vector<TGpuParamBuffer<true>>>& gpuParams) const
+		{
+			return TMaterialParamBuffer<true>(gpuParams);
+		}
+
 		/** 
 		 * Creates a material param out of multiple GPU params. Caller must ensure all GPU params reference the same 
 		 * parameter. 

+ 44 - 0
Source/BansheeCore/Include/BsMaterialParam.h

@@ -213,6 +213,50 @@ namespace BansheeEngine
 		SPtr<Vector<TGpuParamLoadStoreTexture<true>>> mParams;
 	};
 
+	/** @copydoc TMaterialDataParam */
+	template<bool Core>
+	class BS_CORE_EXPORT TMaterialParamBuffer
+	{ };
+
+	/** @copydoc TMaterialDataParam */
+	template<>
+	class BS_CORE_EXPORT TMaterialParamBuffer<false>
+	{
+	public:
+		TMaterialParamBuffer(const String& name, const SPtr<MaterialParams>& params,
+			const SPtr<Vector<TGpuParamBuffer<false>>>& gpuParams);
+		TMaterialParamBuffer() { }
+
+		/** @copydoc GpuParamBuffer::set */
+		void set(const SPtr<GpuBuffer>& buffer);
+
+		/** @copydoc GpuParamBuffer::get */
+		SPtr<GpuBuffer> get();
+
+	protected:
+		UINT32 mParamIndex;
+		SPtr<MaterialParams> mMaterialParams;
+		SPtr<Vector<TGpuParamBuffer<false>>> mGPUParams;
+	};
+
+	/** @copydoc TMaterialDataParam */
+	template<>
+	class BS_CORE_EXPORT TMaterialParamBuffer<true>
+	{
+	public:
+		TMaterialParamBuffer(const SPtr<Vector<TGpuParamBuffer<true>>>& params);
+		TMaterialParamBuffer() { }
+
+		/** @copydoc GpuParamBuffer::set */
+		void set(const SPtr<GpuBufferCore>& buffer);
+
+		/** @copydoc GpuParamBuffer::get */
+		SPtr<GpuBufferCore> get();
+
+	protected:
+		SPtr<Vector<TGpuParamBuffer<true>>> mParams;
+	};
+
 	/** @copydoc TMaterialDataParam */
 	template<bool Core>
 	class BS_CORE_EXPORT TMaterialParamSampState

+ 35 - 3
Source/BansheeCore/Include/BsMaterialParams.h

@@ -43,7 +43,7 @@ namespace BansheeEngine
 		/** Type of material parameter. */
 		enum class ParamType
 		{
-			Data, Texture, Sampler
+			Data, Texture, Sampler, Buffer
 		};
 
 		/** Result codes for getParam method. */
@@ -73,7 +73,7 @@ namespace BansheeEngine
 
 			friend class StructParamDataRTTI;
 			static RTTITypeBase* getRTTIStatic();
-			virtual RTTITypeBase* getRTTI() const override;
+			RTTITypeBase* getRTTI() const override;
 		};
 
 		/** Data for a single texture parameter. */
@@ -86,7 +86,7 @@ namespace BansheeEngine
 
 			friend class TextureParamDataRTTI;
 			static RTTITypeBase* getRTTIStatic();
-			virtual RTTITypeBase* getRTTI() const override;
+			RTTITypeBase* getRTTI() const override;
 		};
 
 		/** Creates a new material params object and initializes enough room for parameters from the provided shader. */
@@ -206,6 +206,24 @@ namespace BansheeEngine
 		 */
 		void setLoadStoreTexture(const String& name, const HTexture& value, const TextureSurface& surface);
 
+		/** 
+		 * Returns the value of a shader buffer parameter with the specified name. If the parameter name or type is not 
+		 * valid a warning will be logged and output value will not be retrieved.
+		 * 
+		 * @param[in]	name		Name of the shader parameter.
+		 * @param[out]	value		Output value of the parameter.
+		 */
+		void getBuffer(const String& name, SPtr<GpuBuffer>& value) const;
+
+		/** 
+		 * Sets the value of a shader buffer parameter with the specified name. If the parameter name or type is not 
+		 * valid a warning will be logged and output value will not be set.
+		 * 
+		 * @param[in]	name		Name of the shader parameter.
+		 * @param[in]	value		New value of the parameter.
+		 */
+		void setBuffer(const String& name, const SPtr<GpuBuffer>& value);
+
 		/** 
 		 * Sets the value of a shader sampler state parameter with the specified name. If the parameter name or type is not 
 		 * valid a warning will be logged and output value will not be set.
@@ -314,6 +332,18 @@ namespace BansheeEngine
 		 */
 		void setTexture(UINT32 index, const HTexture& value);
 
+		/** 
+		 * Equivalent to getBuffer(const String&, SPtr<GpuBuffer>&) except it uses the internal parameter index directly, 
+		 * avoiding the name lookup. Caller must guarantee the index is valid.
+		 */
+		void getBuffer(UINT32 index, SPtr<GpuBuffer>& value) const;
+
+		/** 
+		 * Equivalent to setBuffer(const String&, SPtr<GpuBuffer>&) except it uses the internal parameter index directly, 
+		 * avoiding the name lookup. Caller must guarantee the index is valid.
+		 */
+		void setBuffer(UINT32 index, const SPtr<GpuBuffer>& value);
+
 		/** 
 		 * Equivalent to getLoadStoreTexture(const String&, HTexture&, TextureSurface&) except it uses the internal 
 		 * parameter index directly, avoiding the name lookup. Caller must guarantee the index is valid.
@@ -364,6 +394,7 @@ namespace BansheeEngine
 		UINT8* mDataParamsBuffer = nullptr;
 		StructParamData* mStructParams = nullptr;
 		TextureParamData* mTextureParams = nullptr;
+		SPtr<GpuBuffer>* mBufferParams = nullptr;
 		SPtr<SamplerState>* mSamplerStateParams = nullptr;
 		HTexture* mDefaultTextureParams = nullptr;
 		SPtr<SamplerState>* mDefaultSamplerStateParams = nullptr;
@@ -371,6 +402,7 @@ namespace BansheeEngine
 		UINT32 mDataSize = 0;
 		UINT32 mNumStructParams = 0;
 		UINT32 mNumTextureParams = 0;
+		UINT32 mNumBufferParams = 0;
 		UINT32 mNumSamplerParams = 0;
 
 		mutable StaticAlloc<STATIC_BUFFER_SIZE, STATIC_BUFFER_SIZE> mAlloc;

+ 20 - 0
Source/BansheeCore/Include/BsRenderAPI.h

@@ -57,6 +57,14 @@ namespace BansheeEngine
 		static void setLoadStoreTexture(CoreAccessor& accessor, GpuProgramType gptype, UINT16 texUnit, bool enabled, 
 			const SPtr<Texture>& texPtr, const TextureSurface& surface);
 
+		/**  
+		 * @copydoc RenderAPICore::setBuffer()
+		 *
+		 * @param[in]	accessor	Accessor on which will this command be queued for execution.
+		 */
+		static void setBuffer(CoreAccessor& accessor, GpuProgramType gptype, UINT16 unit, const SPtr<GpuBuffer>& buffer,
+			bool loadStore = false);
+
 		/** 
 		 * @copydoc RenderAPICore::setSamplerState()
 		 *
@@ -409,6 +417,18 @@ namespace BansheeEngine
 		virtual void setLoadStoreTexture(GpuProgramType gptype, UINT16 texUnit, bool enabled,
 			const SPtr<TextureCore>& texPtr, const TextureSurface& surface) = 0;
 
+		/**
+		 * Binds a buffer that can be used for read or write operations on the GPU.
+		 *
+		 * @param[in]	gptype		Determines to which GPU program slot to bind the buffer.
+		 * @param[in]	unit		GPU program unit index to bind the buffer to.
+		 * @param[in]	buffer		Buffer to bind.
+		 * @param[in]	loadStore	If true the buffer will be bound with support for unordered reads and writes, otherwise
+		 *							it will only be bound for reads.
+		 */
+		virtual void setBuffer(GpuProgramType gptype, UINT16 unit, const SPtr<GpuBufferCore>& buffer, 
+			bool loadStore = false) = 0;
+
 		/**
 		 * Signals that rendering for a specific viewport has started. Any draw calls need to be called between beginFrame()
 		 * and endFrame(). 

+ 70 - 15
Source/BansheeCore/Source/BsGpuBuffer.cpp

@@ -7,17 +7,18 @@
 
 namespace BansheeEngine
 {
-	GpuBufferProperties::GpuBufferProperties(UINT32 elementCount, UINT32 elementSize, GpuBufferType type,
-		GpuBufferUsage usage, bool randomGpuWrite, bool useCounter)
-		: mType(type), mUsage(usage), mRandomGpuWrite(randomGpuWrite), mUseCounter(useCounter), mElementCount(elementCount)
-		, mElementSize(elementSize)
+	GpuBufferProperties::GpuBufferProperties(UINT32 elementCount, UINT32 elementSize, GpuBufferType type, 
+		GpuBufferFormat format, GpuBufferUsage usage, bool randomGpuWrite, bool useCounter)
+		: mType(type), mUsage(usage), mFormat(format), mRandomGpuWrite(randomGpuWrite), mUseCounter(useCounter)
+		, mElementCount(elementCount), mElementSize(elementSize)
 	{
-
+		if(type == GBT_STANDARD)
+			mElementSize = GpuBuffer::getFormatSize(format);
 	}
 
-	GpuBufferCore::GpuBufferCore(UINT32 elementCount, UINT32 elementSize, GpuBufferType type, GpuBufferUsage usage,
-		bool randomGpuWrite, bool useCounter)
-		: mProperties(elementCount, elementSize, type, usage, randomGpuWrite, useCounter)
+	GpuBufferCore::GpuBufferCore(UINT32 elementCount, UINT32 elementSize, GpuBufferType type, GpuBufferFormat format, 
+		GpuBufferUsage usage, bool randomGpuWrite, bool useCounter)
+		: mProperties(elementCount, elementSize, type, format, usage, randomGpuWrite, useCounter)
 	{
 	}
 
@@ -39,14 +40,17 @@ namespace BansheeEngine
 	}
 
 	GpuBufferView* GpuBufferCore::requestView(const SPtr<GpuBufferCore>& buffer, UINT32 firstElement,
-		UINT32 elementWidth, UINT32 numElements, bool useCounter, GpuViewUsage usage)
+		UINT32 numElements, GpuViewUsage usage)
 	{
+		const auto& props = buffer->getProperties();
+
 		GPU_BUFFER_DESC key;
 		key.firstElement = firstElement;
-		key.elementWidth = elementWidth;
-		key.numElements = numElements;
+		key.elementWidth = props.getElementSize();
 		key.numElements = numElements;
 		key.usage = usage;
+		key.format = props.getFormat();
+		key.useCounter = props.getUseCounter();
 
 		auto iterFind = buffer->mBufferViews.find(key);
 		if (iterFind == buffer->mBufferViews.end())
@@ -85,9 +89,9 @@ namespace BansheeEngine
 		}
 	}
 
-	GpuBuffer::GpuBuffer(UINT32 elementCount, UINT32 elementSize, GpuBufferType type, GpuBufferUsage usage, 
-		bool randomGpuWrite, bool useCounter)
-		:mProperties(elementCount, elementSize, type, usage, randomGpuWrite, useCounter)
+	GpuBuffer::GpuBuffer(UINT32 elementCount, UINT32 elementSize, GpuBufferType type, GpuBufferFormat format, 
+		GpuBufferUsage usage, bool randomGpuWrite, bool useCounter)
+		:mProperties(elementCount, elementSize, type, format, usage, randomGpuWrite, useCounter)
 	{  
 	}
 
@@ -99,6 +103,57 @@ namespace BansheeEngine
 	SPtr<CoreObjectCore> GpuBuffer::createCore() const
 	{
 		return HardwareBufferCoreManager::instance().createGpuBufferInternal(mProperties.getElementCount(), 
-			mProperties.getElementSize(), mProperties.getType(), mProperties.getUsage(), mProperties.getRandomGpuWrite(), mProperties.getUseCounter());
+			mProperties.getElementSize(), mProperties.getType(), mProperties.getFormat(), mProperties.getUsage(), 
+			mProperties.getRandomGpuWrite(), mProperties.getUseCounter());
+	}
+
+	UINT32 GpuBuffer::getFormatSize(GpuBufferFormat format)
+	{
+		static bool lookupInitialized = false;
+
+		static UINT32 lookup[BF_COUNT];
+		if (!lookupInitialized)
+		{
+			lookup[BF_16X1F] = 2;
+			lookup[BF_16X2F] = 4;
+			lookup[BF_16X4F] = 8;
+			lookup[BF_32X1F] = 4;
+			lookup[BF_32X2F] = 8;
+			lookup[BF_32X3F] = 12;
+			lookup[BF_32X4F] = 16;
+			lookup[BF_8X1] = 1;
+			lookup[BF_8X2] = 2;
+			lookup[BF_8X4] = 4;
+			lookup[BF_16X1] = 2;
+			lookup[BF_16X2] = 4;
+			lookup[BF_16X4] = 8;
+			lookup[BF_8X1S] = 1;
+			lookup[BF_8X2S] = 2;
+			lookup[BF_8X4S] = 4;
+			lookup[BF_16X1S] = 2;
+			lookup[BF_16X2S] = 4;
+			lookup[BF_16X4S] = 8;
+			lookup[BF_32X1S] = 4;
+			lookup[BF_32X2S] = 8;
+			lookup[BF_32X3S] = 12;
+			lookup[BF_32X4S] = 16;
+			lookup[BF_8X1U] = 1;
+			lookup[BF_8X2U] = 2;
+			lookup[BF_8X4U] = 4;
+			lookup[BF_16X1U] = 1;
+			lookup[BF_16X2U] = 2;
+			lookup[BF_16X4U] = 4;
+			lookup[BF_32X1U] = 4;
+			lookup[BF_32X2U] = 8;
+			lookup[BF_32X3U] = 12;
+			lookup[BF_32X4U] = 16;
+
+			lookupInitialized = true;
+		}
+
+		if (format >= BF_COUNT)
+			return 0;
+
+		return lookup[(UINT32)format];
 	}
 }

+ 3 - 2
Source/BansheeCore/Source/BsGpuBufferView.cpp

@@ -12,6 +12,7 @@ namespace BansheeEngine
 		hash_combine(seed, key.numElements);
 		hash_combine(seed, key.useCounter);
 		hash_combine(seed, key.usage);
+		hash_combine(seed, key.format);
 
 		return seed;
 	}
@@ -19,8 +20,8 @@ namespace BansheeEngine
 	bool GpuBufferView::EqualFunction::operator()
 		(const GPU_BUFFER_DESC& a, const GPU_BUFFER_DESC& b) const
 	{
-		return a.elementWidth == b.elementWidth && a.firstElement == b.firstElement 
-			&& a.numElements == b.numElements && a.useCounter == b.useCounter && a.usage == b.usage;
+		return a.elementWidth == b.elementWidth && a.firstElement == b.firstElement && a.numElements == b.numElements 
+			&& a.useCounter == b.useCounter && a.usage == b.usage && a.format == b.format;
 	}
 
 	GpuBufferView::GpuBufferView()

+ 34 - 0
Source/BansheeCore/Source/BsGpuParam.cpp

@@ -210,6 +210,37 @@ namespace BansheeEngine
 		return mParent->getTexture(mParamDesc->slot);
 	}
 
+	template<bool Core>
+	TGpuParamBuffer<Core>::TGpuParamBuffer()
+		:mParamDesc(nullptr)
+	{ }
+
+	template<bool Core>
+	TGpuParamBuffer<Core>::TGpuParamBuffer(GpuParamObjectDesc* paramDesc, const GpuParamsType& parent)
+		: mParent(parent), mParamDesc(paramDesc)
+	{ }
+
+	template<bool Core>
+	void TGpuParamBuffer<Core>::set(const BufferType& texture)
+	{
+		if (mParent == nullptr)
+			return;
+
+		mParent->setBuffer(mParamDesc->slot, texture);
+
+		mParent->_markResourcesDirty();
+		mParent->_markCoreDirty();
+	}
+
+	template<bool Core>
+	typename TGpuParamBuffer<Core>::BufferType TGpuParamBuffer<Core>::get()
+	{
+		if (mParent == nullptr)
+			return BufferType();
+
+		return mParent->getBuffer(mParamDesc->slot);
+	}
+
 	template<bool Core>
 	TGpuParamLoadStoreTexture<Core>::TGpuParamLoadStoreTexture()
 		:mParamDesc(nullptr)
@@ -316,6 +347,9 @@ namespace BansheeEngine
 	template class TGpuParamTexture < false > ;
 	template class TGpuParamTexture < true > ;
 
+	template class TGpuParamBuffer < false >;
+	template class TGpuParamBuffer < true >;
+
 	template class TGpuParamSampState < false > ;
 	template class TGpuParamSampState < true > ;
 

+ 91 - 6
Source/BansheeCore/Source/BsGpuParams.cpp

@@ -5,6 +5,7 @@
 #include "BsGpuParamBlockBuffer.h"
 #include "BsVector2.h"
 #include "BsTexture.h"
+#include "BsGpuBuffer.h"
 #include "BsSamplerState.h"
 #include "BsFrameAlloc.h"
 #include "BsDebug.h"
@@ -15,8 +16,8 @@
 namespace BansheeEngine
 {
 	GpuParamsBase::GpuParamsBase(const SPtr<GpuParamDesc>& paramDesc, bool transposeMatrices)
-		: mParamDesc(paramDesc), mNumParamBlocks(0), mNumTextures(0), mNumLoadStoreTextures(0), mNumSamplerStates(0)
-		, mLoadStoreSurfaces(nullptr), mTransposeMatrices(transposeMatrices)
+		: mParamDesc(paramDesc), mNumParamBlocks(0), mNumTextures(0), mNumLoadStoreTextures(0), mNumBuffers(0)
+		, mNumSamplerStates(0), mLoadStoreSurfaces(nullptr), mTransposeMatrices(transposeMatrices)
 	{
 		for (auto& paramBlock : mParamDesc->paramBlocks)
 		{
@@ -36,6 +37,12 @@ namespace BansheeEngine
 				mNumLoadStoreTextures = texture.second.slot + 1;
 		}
 
+		for (auto& buffer : mParamDesc->buffers)
+		{
+			if ((buffer.second.slot + 1) > mNumBuffers)
+				mNumBuffers = buffer.second.slot + 1;
+		}
+
 		for (auto& sampler : mParamDesc->samplers)
 		{
 			if ((sampler.second.slot + 1) > mNumSamplerStates)
@@ -73,6 +80,15 @@ UINT32 GpuParamsBase::getDataParamSize(const String& name) const
 		return false;
 	}
 
+	bool GpuParamsBase::hasBuffer(const String& name) const
+	{
+		auto paramIter = mParamDesc->buffers.find(name);
+		if (paramIter != mParamDesc->buffers.end())
+			return true;
+
+		return false;
+	}
+
 	bool GpuParamsBase::hasLoadStoreTexture(const String& name) const
 	{
 		auto paramIter = mParamDesc->loadStoreTextures.find(name);
@@ -134,7 +150,7 @@ UINT32 GpuParamsBase::getDataParamSize(const String& name) const
 	template<bool Core>
 	TGpuParams<Core>::TGpuParams(const SPtr<GpuParamDesc>& paramDesc, bool transposeMatrices)
 		: GpuParamsBase(paramDesc, transposeMatrices), mParamBlockBuffers(nullptr), mTextures(nullptr)
-		, mLoadStoreTextures(nullptr), mSamplerStates(nullptr)
+		, mLoadStoreTextures(nullptr), mBuffers(nullptr), mSamplerStates(nullptr)
 	{
 		if (mNumParamBlocks > 0)
 			mParamBlockBuffers = bs_newN<ParamsBufferType>(mNumParamBlocks);
@@ -145,6 +161,9 @@ UINT32 GpuParamsBase::getDataParamSize(const String& name) const
 		if (mNumLoadStoreTextures > 0)
 			mLoadStoreTextures = bs_newN<TextureType>(mNumLoadStoreTextures);
 
+		if(mNumBuffers > 0)
+			mBuffers = bs_newN<BufferType>(mNumBuffers);
+
 		if (mNumSamplerStates > 0)
 			mSamplerStates = bs_newN<SamplerType>(mNumSamplerStates);
 	}
@@ -161,6 +180,9 @@ UINT32 GpuParamsBase::getDataParamSize(const String& name) const
 		if (mLoadStoreTextures != nullptr)
 			bs_deleteN(mLoadStoreTextures, mNumLoadStoreTextures);
 
+		if (mBuffers != nullptr)
+			bs_deleteN(mBuffers, mNumBuffers);
+
 		if (mSamplerStates != nullptr)
 			bs_deleteN(mSamplerStates, mNumSamplerStates);
 	}
@@ -252,6 +274,20 @@ UINT32 GpuParamsBase::getDataParamSize(const String& name) const
 			output = TGpuParamLoadStoreTexture<Core>(&iterFind->second, _getThisPtr());
 	}
 
+	template<bool Core>
+	void TGpuParams<Core>::getBufferParam(const String& name, TGpuParamBuffer<Core>& output) const
+	{
+		auto iterFind = mParamDesc->buffers.find(name);
+
+		if (iterFind == mParamDesc->buffers.end())
+		{
+			output = TGpuParamBuffer<Core>(nullptr, nullptr);
+			LOGWRN("Cannot find buffer parameter with the name '" + name + "'");
+		}
+		else
+			output = TGpuParamBuffer<Core>(&iterFind->second, _getThisPtr());
+	}
+
 	template<bool Core>
 	void TGpuParams<Core>::getSamplerStateParam(const String& name, TGpuParamSampState<Core>& output) const
 	{
@@ -302,6 +338,18 @@ UINT32 GpuParamsBase::getDataParamSize(const String& name) const
 		return mLoadStoreTextures[slot];
 	}
 
+	template<bool Core>
+	typename TGpuParams<Core>::BufferType TGpuParams<Core>::getBuffer(UINT32 slot)
+	{
+		if (slot < 0 || slot >= mNumBuffers)
+		{
+			BS_EXCEPT(InvalidParametersException, "Index out of range: Valid range: 0 .. " +
+				toString(mNumBuffers - 1) + ". Requested: " + toString(slot));
+		}
+
+		return mBuffers[slot];
+	}
+
 	template<bool Core>
 	typename TGpuParams<Core>::SamplerType TGpuParams<Core>::getSamplerState(UINT32 slot)
 	{
@@ -344,6 +392,21 @@ UINT32 GpuParamsBase::getDataParamSize(const String& name) const
 		_markCoreDirty();
 	}
 
+	template<bool Core>
+	void TGpuParams<Core>::setBuffer(UINT32 slot, const BufferType& buffer)
+	{
+		if (slot < 0 || slot >= mNumBuffers)
+		{
+			BS_EXCEPT(InvalidParametersException, "Index out of range: Valid range: 0 .. " +
+				toString(mNumBuffers - 1) + ". Requested: " + toString(slot));
+		}
+
+		mBuffers[slot] = buffer;
+
+		_markResourcesDirty();
+		_markCoreDirty();
+	}
+
 	template<bool Core>
 	void TGpuParams<Core>::setSamplerState(UINT32 slot, const SamplerType& sampler)
 	{
@@ -428,16 +491,18 @@ UINT32 GpuParamsBase::getDataParamSize(const String& name) const
 		UINT32 paramBufferSize = mNumParamBlocks * sizeof(SPtr<GpuParamBlockBufferCore>);
 		UINT32 textureArraySize = mNumTextures * sizeof(SPtr<TextureCore>);
 		UINT32 loadStoreTextureArraySize = mNumLoadStoreTextures * sizeof(SPtr<TextureCore>);
+		UINT32 bufferArraySize = mNumBuffers * sizeof(SPtr<GpuBufferCore>);
 		UINT32 samplerArraySize = mNumSamplerStates * sizeof(SPtr<SamplerStateCore>);
 
 		UINT32 totalSize = loadStoreSurfacesSize + paramBufferSize + textureArraySize + loadStoreTextureArraySize
-			+ samplerArraySize;
+			+ bufferArraySize + samplerArraySize;
 
 		UINT32 textureInfoOffset = 0;
 		UINT32 paramBufferOffset = textureInfoOffset + loadStoreSurfacesSize;
 		UINT32 textureArrayOffset = paramBufferOffset + paramBufferSize;
 		UINT32 loadStoreTextureArrayOffset = textureArrayOffset + textureArraySize;
-		UINT32 samplerArrayOffset = loadStoreTextureArrayOffset + loadStoreTextureArraySize;
+		UINT32 bufferArrayOffset = loadStoreTextureArrayOffset + bufferArraySize;
+		UINT32 samplerArrayOffset = bufferArrayOffset + loadStoreTextureArraySize;
 
 		assert(data.getBufferSize() == totalSize);
 
@@ -447,6 +512,7 @@ UINT32 GpuParamsBase::getDataParamSize(const String& name) const
 		SPtr<GpuParamBlockBufferCore>* paramBuffers = (SPtr<GpuParamBlockBufferCore>*)(dataPtr + paramBufferOffset);
 		SPtr<TextureCore>* textures = (SPtr<TextureCore>*)(dataPtr + textureArrayOffset);
 		SPtr<TextureCore>* loadStoreTextures = (SPtr<TextureCore>*)(dataPtr + loadStoreTextureArrayOffset);
+		SPtr<GpuBufferCore>* buffers = (SPtr<GpuBufferCore>*)(dataPtr + bufferArrayOffset);
 		SPtr<SamplerStateCore>* samplers = (SPtr<SamplerStateCore>*)(dataPtr + samplerArrayOffset);
 
 		// Copy & destruct
@@ -471,6 +537,12 @@ UINT32 GpuParamsBase::getDataParamSize(const String& name) const
 			loadStoreTextures[i].~SPtr<TextureCore>();
 		}
 
+		for (UINT32 i = 0; i < mNumBuffers; i++)
+		{
+			mBuffers[i] = buffers[i];
+			buffers[i].~SPtr<GpuBufferCore>();
+		}
+
 		for (UINT32 i = 0; i < mNumSamplerStates; i++)
 		{
 			mSamplerStates[i] = samplers[i];
@@ -541,6 +613,7 @@ UINT32 GpuParamsBase::getDataParamSize(const String& name) const
 		UINT32 paramBufferSize = mNumParamBlocks * sizeof(SPtr<GpuParamBlockBufferCore>);
 		UINT32 textureArraySize = mNumTextures * sizeof(SPtr<TextureCore>);
 		UINT32 loadStoreTextureArraySize = mNumLoadStoreTextures * sizeof(SPtr<TextureCore>);
+		UINT32 bufferArraySize = mNumBuffers * sizeof(SPtr<GpuBufferCore>);
 		UINT32 samplerArraySize = mNumSamplerStates * sizeof(SPtr<SamplerStateCore>);
 
 		UINT32 totalSize = loadStoreSurfacesSize + paramBufferSize + textureArraySize + loadStoreTextureArraySize 
@@ -550,7 +623,8 @@ UINT32 GpuParamsBase::getDataParamSize(const String& name) const
 		UINT32 paramBufferOffset = textureInfoOffset + loadStoreSurfacesSize;
 		UINT32 textureArrayOffset = paramBufferOffset + paramBufferSize;
 		UINT32 loadStoreTextureArrayOffset = textureArrayOffset + textureArraySize;
-		UINT32 samplerArrayOffset = loadStoreTextureArrayOffset + loadStoreTextureArraySize;
+		UINT32 bufferArrayOffset = loadStoreTextureArrayOffset + bufferArraySize;
+		UINT32 samplerArrayOffset = bufferArrayOffset + loadStoreTextureArraySize;
 
 		UINT8* data = allocator->alloc(totalSize);
 
@@ -558,6 +632,7 @@ UINT32 GpuParamsBase::getDataParamSize(const String& name) const
 		SPtr<GpuParamBlockBufferCore>* paramBuffers = (SPtr<GpuParamBlockBufferCore>*)(data + paramBufferOffset);
 		SPtr<TextureCore>* textures = (SPtr<TextureCore>*)(data + textureArrayOffset);
 		SPtr<TextureCore>* loadStoreTextures = (SPtr<TextureCore>*)(data + loadStoreTextureArrayOffset);
+		SPtr<GpuBufferCore>* buffers = (SPtr<GpuBufferCore>*)(data + bufferArrayOffset);
 		SPtr<SamplerStateCore>* samplers = (SPtr<SamplerStateCore>*)(data + samplerArrayOffset);
 
 		// Construct & copy
@@ -592,6 +667,16 @@ UINT32 GpuParamsBase::getDataParamSize(const String& name) const
 				loadStoreTextures[i] = nullptr;
 		}
 
+		for (UINT32 i = 0; i < mNumBuffers; i++)
+		{
+			new (&buffers[i]) SPtr<GpuBufferCore>();
+
+			if (mBuffers[i] != nullptr)
+				buffers[i] = mBuffers[i]->getCore();
+			else
+				buffers[i] = nullptr;
+		}
+
 		for (UINT32 i = 0; i < mNumSamplerStates; i++)
 		{
 			new (&samplers[i]) SPtr<SamplerStateCore>();

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

@@ -58,9 +58,10 @@ namespace BansheeEngine
 	}
 
 	SPtr<GpuBuffer> HardwareBufferManager::createGpuBuffer(UINT32 elementCount, UINT32 elementSize, 
-		GpuBufferType type, GpuBufferUsage usage, bool randomGpuWrite, bool useCounter)
+		GpuBufferType type, GpuBufferFormat format, GpuBufferUsage usage, bool randomGpuWrite, bool useCounter)
 	{
-		SPtr<GpuBuffer> gbuf = bs_core_ptr<GpuBuffer>(new (bs_alloc<GpuBuffer>()) GpuBuffer(elementCount, elementSize, type, usage, randomGpuWrite, useCounter));
+		SPtr<GpuBuffer> gbuf = bs_core_ptr<GpuBuffer>(new (bs_alloc<GpuBuffer>()) 
+			GpuBuffer(elementCount, elementSize, type, format, usage, randomGpuWrite, useCounter));
 		gbuf->_setThisPtr(gbuf);
 		gbuf->initialize();
 
@@ -111,9 +112,10 @@ namespace BansheeEngine
 	}
 
 	SPtr<GpuBufferCore> HardwareBufferCoreManager::createGpuBuffer(UINT32 elementCount, UINT32 elementSize,
-		GpuBufferType type, GpuBufferUsage usage, bool randomGpuWrite, bool useCounter)
+		GpuBufferType type, GpuBufferFormat format, GpuBufferUsage usage, bool randomGpuWrite, bool useCounter)
 	{
-		SPtr<GpuBufferCore> gbuf = createGpuBufferInternal(elementCount, elementSize, type, usage, randomGpuWrite, useCounter);
+		SPtr<GpuBufferCore> gbuf = createGpuBufferInternal(elementCount, elementSize, type, format, usage, randomGpuWrite, 
+			useCounter);
 		gbuf->initialize();
 
 		return gbuf;

+ 51 - 0
Source/BansheeCore/Source/BsMaterial.cpp

@@ -597,6 +597,41 @@ namespace BansheeEngine
 		return createLoadStoreTextureParam(name, gpuParams);
 	}
 
+	template<bool Core>
+	TMaterialParamBuffer<Core> TMaterial<Core>::getParamBuffer(const String& name) const
+	{
+		throwIfNotInitialized();
+
+		SPtr<Vector<TGpuParamBuffer<Core>>> gpuParams;
+
+		auto iterFind = mValidParams.find(name);
+		if (iterFind != mValidParams.end())
+		{
+			const String& gpuVarName = iterFind->second;
+			gpuParams = bs_shared_ptr_new<Vector<TGpuParamBuffer<Core>>>();
+
+			for (auto iter = mParametersPerPass.begin(); iter != mParametersPerPass.end(); ++iter)
+			{
+				SPtr<PassParamsType> params = *iter;
+
+				for (UINT32 i = 0; i < PassParamsType::NUM_PARAMS; i++)
+				{
+					GpuParamsType& paramPtr = params->getParamByIdx(i);
+					if (paramPtr)
+					{
+						if (paramPtr->hasBuffer(gpuVarName))
+						{
+							gpuParams->push_back(TGpuParamBuffer<Core>());
+							paramPtr->getBufferParam(gpuVarName, gpuParams->back());
+						}
+					}
+				}
+			}
+		}
+
+		return createBufferParam(name, gpuParams);
+	}
+
 	template<bool Core>
 	TMaterialParamSampState<Core> TMaterial<Core>::getParamSamplerState(const String& name) const
 	{
@@ -1395,6 +1430,22 @@ namespace BansheeEngine
 			}
 		}
 
+		auto& bufferParams = mShader->getBufferParams();
+		for (auto& param : bufferParams)
+		{
+			const MaterialParams::ParamData* paramData = nullptr;
+			auto result = params->getParamData(param.first, MaterialParams::ParamType::Buffer, GPDT_UNKNOWN, 0, &paramData);
+
+			if (result != MaterialParams::GetParamResult::Success)
+				continue;
+
+			TMaterialParamBuffer<false> curParam = getParamBuffer(param.first);
+
+			SPtr<GpuBuffer> buffer;
+			params->getBuffer(paramData->index, buffer);
+			curParam.set(buffer);
+		}
+
 		auto& samplerParams = mShader->getSamplerParams();
 		for (auto& param : samplerParams)
 		{

+ 65 - 0
Source/BansheeCore/Source/BsMaterialParam.cpp

@@ -308,6 +308,71 @@ namespace BansheeEngine
 		return (*mParams)[0].get(); // They should all have the same value
 	}
 
+	TMaterialParamBuffer<false>::TMaterialParamBuffer(const String& name, const SPtr<MaterialParams>& params,
+		const SPtr<Vector<TGpuParamBuffer<false>>>& gpuParams)
+		:mParamIndex(0), mMaterialParams(nullptr), mGPUParams(gpuParams)
+	{
+		if (params != nullptr)
+		{
+			const MaterialParams::ParamData* data = nullptr;
+			auto result = params->getParamData(name, MaterialParams::ParamType::Buffer, GPDT_UNKNOWN, 0, &data);
+
+			if (result == MaterialParams::GetParamResult::Success)
+			{
+				mMaterialParams = params;
+				mParamIndex = data->index;
+			}
+			else
+				params->reportGetParamError(result, name, 0);
+		}
+	}
+
+	void TMaterialParamBuffer<false>::set(const SPtr<GpuBuffer>& buffer)
+	{
+		if (mMaterialParams == nullptr)
+			return;
+
+		mMaterialParams->setBuffer(mParamIndex, buffer);
+
+		if (mGPUParams != nullptr)
+		{
+			for (auto& param : *mGPUParams)
+				param.set(buffer);
+		}
+	}
+
+	SPtr<GpuBuffer> TMaterialParamBuffer<false>::get()
+	{
+		SPtr<GpuBuffer> buffer;
+		if (mMaterialParams == nullptr)
+			return buffer;
+
+		mMaterialParams->getBuffer(mParamIndex, buffer);
+
+		return buffer;
+	}
+
+	TMaterialParamBuffer<true>::TMaterialParamBuffer(const SPtr<Vector<TGpuParamBuffer<true>>>& params)
+		:mParams(params)
+	{ }
+
+	void TMaterialParamBuffer<true>::set(const SPtr<GpuBufferCore>& buffer)
+	{
+		if (mParams == nullptr)
+			return;
+
+		for (auto& param : *mParams)
+			param.set(buffer);
+	}
+
+	SPtr<GpuBufferCore> TMaterialParamBuffer<true>::get()
+	{
+		if (mParams == nullptr || mParams->size() == 0)
+			return SPtr<GpuBufferCore>();
+
+		return (*mParams)[0].get(); // They should all have the same value
+	}
+
 	TMaterialParamSampState<false>::TMaterialParamSampState(const String& name, const SPtr<MaterialParams>& params, 
 		const SPtr<Vector<TGpuParamSampState<false>>>& gpuParams)
 		:mParamIndex(0), mMaterialParams(nullptr), mGPUParams(gpuParams)

+ 69 - 16
Source/BansheeCore/Source/BsMaterialParams.cpp

@@ -22,9 +22,11 @@ namespace BansheeEngine
 		}
 
 		auto& textureParams = shader->getTextureParams();
+		auto& bufferParams = shader->getBufferParams();
 		auto& samplerParams = shader->getSamplerParams();
 
 		mNumTextureParams = (UINT32)textureParams.size();
+		mNumBufferParams = (UINT32)bufferParams.size();
 		mNumSamplerParams = (UINT32)samplerParams.size();
 
 		mDataParamsBuffer = mAlloc.alloc(mDataSize);
@@ -32,14 +34,16 @@ namespace BansheeEngine
 
 		mStructParams = mAlloc.construct<StructParamData>(mNumStructParams);
 		mTextureParams = mAlloc.construct<TextureParamData>(mNumTextureParams);
+		mBufferParams = mAlloc.construct<SPtr<GpuBuffer>>(mNumBufferParams);
 		mSamplerStateParams = mAlloc.construct<SPtr<SamplerState>>(mNumSamplerParams);
 		mDefaultTextureParams = mAlloc.construct<HTexture>(mNumTextureParams);
 		mDefaultSamplerStateParams = mAlloc.construct<SPtr<SamplerState>>(mNumSamplerParams);
 
-		UINT32 mDataBufferIdx = 0;
-		UINT32 mStructIdx = 0;
-		UINT32 mTextureIdx = 0;
-		UINT32 mSamplerIdx = 0;
+		UINT32 dataBufferIdx = 0;
+		UINT32 structIdx = 0;
+		UINT32 textureIdx = 0;
+		UINT32 bufferIdx = 0;
+		UINT32 samplerIdx = 0;
 
 		for (auto& entry : dataParams)
 		{
@@ -53,19 +57,19 @@ namespace BansheeEngine
 			const GpuParamDataTypeInfo& typeInfo = GpuParams::PARAM_SIZES.lookup[(int)dataParam.dataType];
 			UINT32 paramSize = typeInfo.numColumns * typeInfo.numRows * typeInfo.baseTypeSize;
 
-			dataParam.index = mDataBufferIdx;
-			mDataBufferIdx += arraySize * paramSize;
+			dataParam.index = dataBufferIdx;
+			dataBufferIdx += arraySize * paramSize;
 
 			if(entry.second.type == GPDT_STRUCT)
 			{
 				for (UINT32 i = 0; i < arraySize; i++)
 				{
-					StructParamData& param = mStructParams[mStructIdx];
+					StructParamData& param = mStructParams[structIdx];
 					param.dataSize = entry.second.elementSize;
 					param.data = mAlloc.alloc(param.dataSize);
 
-					dataParam.index = mStructIdx;
-					mStructIdx++;
+					dataParam.index = structIdx;
+					structIdx++;
 				}
 			}
 		}
@@ -77,15 +81,27 @@ namespace BansheeEngine
 			dataParam.arraySize = 1;
 			dataParam.type = ParamType::Texture;
 			dataParam.dataType = GPDT_UNKNOWN;
-			dataParam.index = mTextureIdx;
+			dataParam.index = textureIdx;
 
-			TextureParamData& param = mTextureParams[mTextureIdx];
+			TextureParamData& param = mTextureParams[textureIdx];
 			param.isLoadStore = false;
 
 			if (entry.second.defaultValueIdx != (UINT32)-1)
-				mDefaultTextureParams[mTextureIdx] = shader->getDefaultTexture(entry.second.defaultValueIdx);
+				mDefaultTextureParams[textureIdx] = shader->getDefaultTexture(entry.second.defaultValueIdx);
 
-			mTextureIdx++;
+			textureIdx++;
+		}
+
+		for (auto& entry : bufferParams)
+		{
+			ParamData& dataParam = mParams[entry.first];
+
+			dataParam.arraySize = 1;
+			dataParam.type = ParamType::Buffer;
+			dataParam.dataType = GPDT_UNKNOWN;
+			dataParam.index = bufferIdx;
+
+			bufferIdx++;
 		}
 
 		for (auto& entry : samplerParams)
@@ -95,12 +111,12 @@ namespace BansheeEngine
 			dataParam.arraySize = 1;
 			dataParam.type = ParamType::Sampler;
 			dataParam.dataType = GPDT_UNKNOWN;
-			dataParam.index = mSamplerIdx;
+			dataParam.index = samplerIdx;
 
 			if (entry.second.defaultValueIdx != (UINT32)-1)
-				mDefaultSamplerStateParams[mTextureIdx] = shader->getDefaultSampler(entry.second.defaultValueIdx);
+				mDefaultSamplerStateParams[textureIdx] = shader->getDefaultSampler(entry.second.defaultValueIdx);
 
-			mSamplerIdx++;
+			samplerIdx++;
 		}
 	}
 
@@ -115,6 +131,7 @@ namespace BansheeEngine
 		mAlloc.free(mDataParamsBuffer);
 		mAlloc.destruct(mStructParams, mNumStructParams);
 		mAlloc.destruct(mTextureParams, mNumTextureParams);
+		mAlloc.destruct(mBufferParams, mNumBufferParams);
 		mAlloc.destruct(mSamplerStateParams, mNumSamplerParams);
 
 		if(mDefaultTextureParams != nullptr)
@@ -204,6 +221,32 @@ namespace BansheeEngine
 		setLoadStoreTexture(param->index, value, surface);
 	}
 
+	void MaterialParams::getBuffer(const String& name, SPtr<GpuBuffer>& value) const
+	{
+		const ParamData* param = nullptr;
+		GetParamResult result = getParamData(name, ParamType::Buffer, GPDT_UNKNOWN, 0, &param);
+		if (result != GetParamResult::Success)
+		{
+			reportGetParamError(result, name, 0);
+			return;
+		}
+
+		getBuffer(param->index, value);
+	}
+
+	void MaterialParams::setBuffer(const String& name, const SPtr<GpuBuffer>& value)
+	{
+		const ParamData* param = nullptr;
+		GetParamResult result = getParamData(name, ParamType::Buffer, GPDT_UNKNOWN, 0, &param);
+		if (result != GetParamResult::Success)
+		{
+			reportGetParamError(result, name, 0);
+			return;
+		}
+
+		setBuffer(param->index, value);
+	}
+
 	void MaterialParams::getSamplerState(const String& name, SPtr<SamplerState>& value) const
 	{
 		const ParamData* param = nullptr;
@@ -312,6 +355,16 @@ namespace BansheeEngine
 		textureParam.isLoadStore = false;
 	}
 
+	void MaterialParams::getBuffer(UINT32 index, SPtr<GpuBuffer>& value) const
+	{
+		value = mBufferParams[index];
+	}
+
+	void MaterialParams::setBuffer(UINT32 index, const SPtr<GpuBuffer>& value)
+	{
+		mBufferParams[index] = value;
+	}
+
 	void MaterialParams::getLoadStoreTexture(UINT32 index, HTexture& value, TextureSurface& surface) const
 	{
 		TextureParamData& textureParam = mTextureParams[index];

+ 18 - 0
Source/BansheeCore/Source/BsRenderAPI.cpp

@@ -14,6 +14,7 @@
 #include "BsDepthStencilState.h"
 #include "BsRasterizerState.h"
 #include "BsGpuParamDesc.h"
+#include "BsGpuBuffer.h"
 #include "BsShader.h"
 
 using namespace std::placeholders;
@@ -37,6 +38,13 @@ namespace BansheeEngine
 			surface));
 	}
 
+	void RenderAPI::setBuffer(CoreAccessor& accessor, GpuProgramType gptype, UINT16 unit, const SPtr<GpuBuffer>& buffer,
+		bool loadStore)
+	{
+		accessor.queueCommand(std::bind(&RenderAPICore::setBuffer, RenderAPICore::instancePtr(), gptype, unit, 
+			buffer->getCore(), loadStore));
+	}
+
 	void RenderAPI::setSamplerState(CoreAccessor& accessor, GpuProgramType gptype, UINT16 texUnit, const SPtr<SamplerState>& samplerState)
 	{
 		accessor.queueCommand(std::bind(&RenderAPICore::setSamplerState, RenderAPICore::instancePtr(), gptype, texUnit, samplerState->getCore()));
@@ -429,6 +437,16 @@ namespace BansheeEngine
 				setLoadStoreTexture(gptype, iter->second.slot, true, texture, surface);
 		}
 
+		for (auto iter = paramDesc.buffers.begin(); iter != paramDesc.buffers.end(); ++iter)
+		{
+			SPtr<GpuBufferCore> buffer = params->getBuffer(iter->second.slot);
+
+			bool isLoadStore = iter->second.type != GPOT_BYTE_BUFFER &&
+				iter->second.type != GPOT_STRUCTURED_BUFFER;
+
+			setBuffer(gptype, iter->second.slot, buffer, isLoadStore);
+		}
+
 		setConstantBuffers(gptype, params);
 	}
 

+ 15 - 8
Source/BansheeD3D11RenderAPI/Include/BsD3D11GpuBuffer.h

@@ -18,16 +18,16 @@ namespace BansheeEngine
 		~D3D11GpuBufferCore();
 
 		/** @copydoc GpuBufferCore::lock */
-		virtual void* lock(UINT32 offset, UINT32 length, GpuLockOptions options) override;
+		void* lock(UINT32 offset, UINT32 length, GpuLockOptions options) override;
 
 		/** @copydoc GpuBufferCore::unlock */
-		virtual void unlock() override;
+		void unlock() override;
 
 		/** @copydoc GpuBufferCore::readData */
-		virtual void readData(UINT32 offset, UINT32 length, void* pDest) override;
+		void readData(UINT32 offset, UINT32 length, void* pDest) override;
 
 		/** @copydoc GpuBufferCore::writeData */
-        virtual void writeData(UINT32 offset, UINT32 length, const void* pSource,
+        void writeData(UINT32 offset, UINT32 length, const void* pSource,
 			BufferWriteType writeFlags = BufferWriteType::Normal) override;
 
 		/** @copydoc GpuBufferCore::copyData */
@@ -37,23 +37,30 @@ namespace BansheeEngine
 		/**	Returns the internal DX11 GPU buffer object. */
 		ID3D11Buffer* getDX11Buffer() const;
 
+		/** Returns the DX11 shader resource view object for the buffer. */
+		ID3D11ShaderResourceView* getSRV() const;
+
+		/** Returns the DX11 unordered access view object for the buffer. */
+		ID3D11UnorderedAccessView* getUAV() const;
+
 	protected:
 		friend class D3D11HardwareBufferCoreManager;
 
-		D3D11GpuBufferCore(UINT32 elementCount, UINT32 elementSize, GpuBufferType type, GpuBufferUsage usage,
-			bool randomGpuWrite = false, bool useCounter = false);
+		D3D11GpuBufferCore(UINT32 elementCount, UINT32 elementSize, GpuBufferType type, GpuBufferFormat format, 
+			GpuBufferUsage usage, bool randomGpuWrite = false, bool useCounter = false);
 
 		/** @copydoc GpuBufferCore::createView */
-		virtual GpuBufferView* createView() override;
+		GpuBufferView* createView() override;
 
 		/** @copydoc GpuBufferCore::destroyView */
-		virtual void destroyView(GpuBufferView* view) override;
+		void destroyView(GpuBufferView* view) override;
 
 		/** @copydoc GpuBufferCore::initialize */
 		void initialize() override;
 
 	private:
 		D3D11HardwareBuffer* mBuffer;
+		D3D11GpuBufferView* mBufferView;
     };
 
 	/** @} */

+ 6 - 0
Source/BansheeD3D11RenderAPI/Include/BsD3D11GpuBufferView.h

@@ -24,6 +24,12 @@ namespace BansheeEngine
 		/** @copydoc GpuBufferView::initialize */
 		void initialize(const SPtr<GpuBufferCore>& buffer, GPU_BUFFER_DESC& desc) override;
 
+		/** Returns the DX11 shader resource view object for the buffer. */
+		ID3D11ShaderResourceView* getSRV() const { return mSRV; }
+
+		/** Returns the DX11 unordered access view object for the buffer. */
+		ID3D11UnorderedAccessView* getUAV() const { return mUAV; }
+
 	private:
 		/**
 		 * Creates a DX11 shader resource view that allows a buffer to be bound to a shader for reading (the most common

+ 2 - 2
Source/BansheeD3D11RenderAPI/Include/BsD3D11HardwareBufferManager.h

@@ -31,8 +31,8 @@ namespace BansheeEngine
 			GpuParamBlockUsage usage = GPBU_DYNAMIC) override;
 
 		/** @copydoc HardwareBufferCoreManager::createGpuBufferInternal */
-		SPtr<GpuBufferCore> createGpuBufferInternal(UINT32 elementCount, UINT32 elementSize,
-			GpuBufferType type, GpuBufferUsage usage, bool randomGpuWrite = false, bool useCounter = false) override;
+		SPtr<GpuBufferCore> createGpuBufferInternal(UINT32 elementCount, UINT32 elementSize, GpuBufferType type, 
+			GpuBufferFormat format, GpuBufferUsage usage, bool randomGpuWrite = false, bool useCounter = false) override;
 
 		D3D11Device& mDevice;
 	};

+ 3 - 0
Source/BansheeD3D11RenderAPI/Include/BsD3D11Mappings.h

@@ -95,6 +95,9 @@ namespace BansheeEngine
 		 */
 		static DXGI_FORMAT getPF(PixelFormat format, bool hwGamma);
 		
+		/** Converts engine GPU buffer format to DX11 GPU buffer format. */
+		static DXGI_FORMAT getBF(GpuBufferFormat format);
+
 		/** 
 		 * Returns a typeless version of a depth stencil format. Required for creating a depth stencil texture it can be
 		 * bound both for shader reading and depth/stencil writing.

+ 1 - 0
Source/BansheeD3D11RenderAPI/Include/BsD3D11Prerequisites.h

@@ -62,6 +62,7 @@ namespace BansheeEngine
 	class D3D11RenderUtility;
 	class D3D11GpuProgramCore;
 	class D3D11TextureView;
+	class D3D11GpuBufferView;
 
 	/**	DirectX 11 specific types to track resource statistics for. */
 	enum D3D11RenderStatResourceType

+ 3 - 0
Source/BansheeD3D11RenderAPI/Include/BsD3D11RenderAPI.h

@@ -43,6 +43,9 @@ namespace BansheeEngine
 		void setLoadStoreTexture(GpuProgramType gptype, UINT16 texUnit, bool enabled, const SPtr<TextureCore>& texPtr,
 			const TextureSurface& surface) override;
 
+		/** @copydoc RenderAPICore::setBuffer */
+		void setBuffer(GpuProgramType gptype, UINT16 unit, const SPtr<GpuBufferCore>& buffer, bool loadStore = false) override;
+
 		/** @copydoc RenderAPICore::disableTextureUnit */
 		void disableTextureUnit(GpuProgramType gptype, UINT16 texUnit) override;
 

+ 27 - 3
Source/BansheeD3D11RenderAPI/Source/BsD3D11GpuBuffer.cpp

@@ -12,9 +12,14 @@
 namespace BansheeEngine
 {
 	D3D11GpuBufferCore::D3D11GpuBufferCore(UINT32 elementCount, UINT32 elementSize, GpuBufferType type, 
-		GpuBufferUsage usage, bool randomGpuWrite, bool useCounter)
-		: GpuBufferCore(elementCount, elementSize, type, usage, randomGpuWrite, useCounter), mBuffer(nullptr)
-	{ }
+		GpuBufferFormat format, GpuBufferUsage usage, bool randomGpuWrite, bool useCounter)
+		: GpuBufferCore(elementCount, elementSize, type, format, usage, randomGpuWrite, useCounter), mBuffer(nullptr)
+	{
+		if (type != GBT_STANDARD)
+			assert(format == BF_UNKNOWN && "Format must be set to BF_UNKNOWN when using non-standard buffers");
+		else
+			assert(elementSize != 0 && "No element size can be provided for standard buffer. Size is determined from format.");
+	}
 
 	D3D11GpuBufferCore::~D3D11GpuBufferCore()
 	{ 
@@ -32,6 +37,7 @@ namespace BansheeEngine
 
 		switch (props.getType())
 		{
+		case GBT_STANDARD:
 		case GBT_STRUCTURED:
 			bufferType = D3D11HardwareBuffer::BT_STRUCTURED;
 			break;
@@ -51,6 +57,14 @@ namespace BansheeEngine
 		mBuffer = bs_new<D3D11HardwareBuffer>(bufferType, props.getUsage(), props.getElementCount(), props.getElementSize(),
 			d3d11rs->getPrimaryDevice(), false, false, props.getRandomGpuWrite(), props.getUseCounter());
 
+		SPtr<D3D11GpuBufferCore> thisPtr = std::static_pointer_cast<D3D11GpuBufferCore>(getThisPtr());
+		UINT32 usage = GVU_DEFAULT;
+		if (props.getRandomGpuWrite())
+			usage |= GVU_RANDOMWRITE;
+
+		// Keep a single view of the entire buffer, we don't support views of sub-sets (yet)
+		mBufferView = static_cast<D3D11GpuBufferView*>(requestView(thisPtr, 0, props.getElementCount(), (GpuViewUsage)usage));
+
 		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_GpuBuffer);
 
 		GpuBufferCore::initialize();
@@ -115,4 +129,14 @@ namespace BansheeEngine
 		if(view != nullptr)
 			bs_delete(view);
 	}
+
+	ID3D11ShaderResourceView* D3D11GpuBufferCore::getSRV() const
+	{
+		return mBufferView->getSRV();
+	}
+
+	ID3D11UnorderedAccessView* D3D11GpuBufferCore::getUAV() const
+	{
+		return mBufferView->getUAV();
+	}
 }

+ 8 - 6
Source/BansheeD3D11RenderAPI/Source/BsD3D11GpuBufferView.cpp

@@ -29,14 +29,16 @@ namespace BansheeEngine
 
 		D3D11GpuBufferCore* d3d11GpuBuffer = static_cast<D3D11GpuBufferCore*>(buffer.get());
 
+		if ((desc.usage & GVU_DEFAULT) != 0)
+			mSRV = createSRV(d3d11GpuBuffer, desc.firstElement, desc.elementWidth, desc.numElements);
+
 		if((desc.usage & GVU_RANDOMWRITE) != 0)
 			mUAV = createUAV(d3d11GpuBuffer, desc.firstElement, desc.numElements, desc.useCounter);
-		else if((desc.usage & GVU_RENDERTARGET) != 0)
+
+		if((desc.usage & GVU_RENDERTARGET) != 0 || (desc.usage & GVU_DEPTHSTENCIL) != 0)
 		{
-			BS_EXCEPT(NotImplementedException, "Cannot create a render target view for buffers yet.");
+			BS_EXCEPT(NotImplementedException, "Invalid usage flags for a GPU buffer view.");
 		}
-		else
-			mSRV = createSRV(d3d11GpuBuffer, desc.firstElement, desc.elementWidth, desc.numElements);
 
 		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_ResourceView);
 	}
@@ -51,7 +53,7 @@ namespace BansheeEngine
 		D3D11_SHADER_RESOURCE_VIEW_DESC desc;
 		ZeroMemory(&desc, sizeof(desc));
 
-		if (props.getType() == GBT_STRUCTURED)
+		if (props.getType() == GBT_STRUCTURED || props.getType() == GBT_STANDARD)
 		{
 			desc.Format = DXGI_FORMAT_UNKNOWN;
 			desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
@@ -97,7 +99,7 @@ namespace BansheeEngine
 
 		desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
 
-		if (props.getType() == GBT_STRUCTURED)
+		if (props.getType() == GBT_STRUCTURED || props.getType() == GBT_STANDARD)
 		{
 			desc.Format = DXGI_FORMAT_UNKNOWN;
 			desc.Buffer.FirstElement = firstElement;

+ 3 - 3
Source/BansheeD3D11RenderAPI/Source/BsD3D11HardwareBuffer.cpp

@@ -16,8 +16,8 @@ namespace BansheeEngine
 		 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((!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 standard, 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.");
@@ -76,7 +76,7 @@ namespace BansheeEngine
 			}
 		}
 
-		HRESULT hr = device.getD3D11Device()->CreateBuffer( &mDesc, nullptr, &mD3DBuffer );
+		HRESULT hr = device.getD3D11Device()->CreateBuffer(&mDesc, nullptr, &mD3DBuffer);
 		if (FAILED(hr) || mDevice.hasError())
 		{
 			String msg = device.getErrorDescription();

+ 3 - 2
Source/BansheeD3D11RenderAPI/Source/BsD3D11HardwareBufferManager.cpp

@@ -42,9 +42,10 @@ namespace BansheeEngine
 	}
 
 	SPtr<GpuBufferCore> D3D11HardwareBufferCoreManager::createGpuBufferInternal(UINT32 elementCount, UINT32 elementSize,
-		GpuBufferType type, GpuBufferUsage usage, bool randomGpuWrite, bool useCounter)
+		GpuBufferType type, GpuBufferFormat format, GpuBufferUsage usage, bool randomGpuWrite, bool useCounter)
 	{
-		D3D11GpuBufferCore* buffer = new (bs_alloc<D3D11GpuBufferCore>()) D3D11GpuBufferCore(elementCount, elementSize, type, usage, randomGpuWrite, useCounter);
+		D3D11GpuBufferCore* buffer = new (bs_alloc<D3D11GpuBufferCore>()) 
+			D3D11GpuBufferCore(elementCount, elementSize, type, format, usage, randomGpuWrite, useCounter);
 
 		SPtr<D3D11GpuBufferCore> bufferPtr = bs_shared_ptr<D3D11GpuBufferCore>(buffer);
 		bufferPtr->_setThisPtr(bufferPtr);

+ 50 - 0
Source/BansheeD3D11RenderAPI/Source/BsD3D11Mappings.cpp

@@ -690,6 +690,56 @@ namespace BansheeEngine
 		}
 	}
 
+	DXGI_FORMAT D3D11Mappings::getBF(GpuBufferFormat format)
+	{
+		static bool lookupInitialized = false;
+
+		static DXGI_FORMAT lookup[BF_COUNT];
+		if (!lookupInitialized)
+		{
+			lookup[BF_16X1F] = DXGI_FORMAT_R16_FLOAT;
+			lookup[BF_16X2F] = DXGI_FORMAT_R16G16_FLOAT;
+			lookup[BF_16X4F] = DXGI_FORMAT_R16G16B16A16_FLOAT;
+			lookup[BF_32X1F] = DXGI_FORMAT_R32_FLOAT;
+			lookup[BF_32X2F] = DXGI_FORMAT_R32G32_FLOAT;
+			lookup[BF_32X3F] = DXGI_FORMAT_R32G32B32_FLOAT;
+			lookup[BF_32X4F] = DXGI_FORMAT_R32G32B32A32_FLOAT;
+			lookup[BF_8X1] = DXGI_FORMAT_R8_UNORM;
+			lookup[BF_8X2] = DXGI_FORMAT_R8G8_UNORM;
+			lookup[BF_8X4] = DXGI_FORMAT_R8G8B8A8_UNORM;
+			lookup[BF_16X1] = DXGI_FORMAT_R16_UNORM;
+			lookup[BF_16X2] = DXGI_FORMAT_R16G16_UNORM;
+			lookup[BF_16X4] = DXGI_FORMAT_R16G16B16A16_UNORM;
+			lookup[BF_8X1S] = DXGI_FORMAT_R8_SINT;
+			lookup[BF_8X2S] = DXGI_FORMAT_R8G8_SINT;
+			lookup[BF_8X4S] = DXGI_FORMAT_R8G8B8A8_SINT;
+			lookup[BF_16X1S] = DXGI_FORMAT_R16_SINT;
+			lookup[BF_16X2S] = DXGI_FORMAT_R16G16_SINT;
+			lookup[BF_16X4S] = DXGI_FORMAT_R16G16B16A16_SINT;
+			lookup[BF_32X1S] = DXGI_FORMAT_R32_SINT;
+			lookup[BF_32X2S] = DXGI_FORMAT_R32G32_SINT;
+			lookup[BF_32X3S] = DXGI_FORMAT_R32G32B32_SINT;
+			lookup[BF_32X4S] = DXGI_FORMAT_R32G32B32A32_SINT;
+			lookup[BF_8X1U] = DXGI_FORMAT_R8_UINT;
+			lookup[BF_8X2U] = DXGI_FORMAT_R8G8_UINT;
+			lookup[BF_8X4U] = DXGI_FORMAT_R8G8B8A8_UINT;
+			lookup[BF_16X1U] = DXGI_FORMAT_R16_UINT;
+			lookup[BF_16X2U] = DXGI_FORMAT_R16G16_UINT;
+			lookup[BF_16X4U] = DXGI_FORMAT_R16G16B16A16_UINT;
+			lookup[BF_32X1U] = DXGI_FORMAT_R32_UINT;
+			lookup[BF_32X2U] = DXGI_FORMAT_R32G32_UINT;
+			lookup[BF_32X3U] = DXGI_FORMAT_R32G32B32_UINT;
+			lookup[BF_32X4U] = DXGI_FORMAT_R32G32B32A32_UINT;
+
+			lookupInitialized = true;
+		}
+		
+		if (format >= BF_COUNT)
+			return DXGI_FORMAT_UNKNOWN;
+
+		return lookup[(UINT32)format];
+	}
+
 	DXGI_FORMAT D3D11Mappings::getTypelessDepthStencilPF(PixelFormat format)
 	{
 		switch(format)

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

@@ -29,6 +29,7 @@
 #include "BsException.h"
 #include "BsRenderStats.h"
 #include "BsGpuParamDesc.h"
+#include "BsD3D11GpuBuffer.h"
 
 namespace BansheeEngine
 {
@@ -358,6 +359,72 @@ namespace BansheeEngine
 		BS_INC_RENDER_STAT(NumTextureBinds);
 	}
 
+	void D3D11RenderAPI::setBuffer(GpuProgramType gptype, UINT16 unit, const SPtr<GpuBufferCore>& buffer, bool loadStore)
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		if(!loadStore)
+		{
+			ID3D11ShaderResourceView* viewArray[1];
+			if (buffer != nullptr)
+			{
+				D3D11GpuBufferCore* d3d11buffer = static_cast<D3D11GpuBufferCore*>(buffer.get());
+				viewArray[0] = d3d11buffer->getSRV();
+			}
+			else
+				viewArray[0] = nullptr;
+
+			switch (gptype)
+			{
+			case GPT_VERTEX_PROGRAM:
+				mDevice->getImmediateContext()->VSSetShaderResources(unit, 1, viewArray);
+				break;
+			case GPT_FRAGMENT_PROGRAM:
+				mDevice->getImmediateContext()->PSSetShaderResources(unit, 1, viewArray);
+				break;
+			case GPT_GEOMETRY_PROGRAM:
+				mDevice->getImmediateContext()->GSSetShaderResources(unit, 1, viewArray);
+				break;
+			case GPT_DOMAIN_PROGRAM:
+				mDevice->getImmediateContext()->DSSetShaderResources(unit, 1, viewArray);
+				break;
+			case GPT_HULL_PROGRAM:
+				mDevice->getImmediateContext()->HSSetShaderResources(unit, 1, viewArray);
+				break;
+			case GPT_COMPUTE_PROGRAM:
+				mDevice->getImmediateContext()->CSSetShaderResources(unit, 1, viewArray);
+				break;
+			default:
+				BS_EXCEPT(InvalidParametersException, "Unsupported gpu program type: " + toString(gptype));
+			}
+		}
+		else
+		{
+			ID3D11UnorderedAccessView* viewArray[1];
+			if (buffer != nullptr)
+			{
+				D3D11GpuBufferCore* d3d11buffer = static_cast<D3D11GpuBufferCore*>(buffer.get());
+				viewArray[0] = d3d11buffer->getUAV();
+			}
+			else
+				viewArray[0] = nullptr;
+
+			if (gptype == GPT_FRAGMENT_PROGRAM)
+			{
+				mDevice->getImmediateContext()->OMSetRenderTargetsAndUnorderedAccessViews(
+					D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, nullptr, nullptr, unit, 1, viewArray, nullptr);
+			}
+			else if (gptype == GPT_COMPUTE_PROGRAM)
+			{
+				mDevice->getImmediateContext()->CSSetUnorderedAccessViews(unit, 1, viewArray, nullptr);
+			}
+			else
+				BS_EXCEPT(InvalidParametersException, "Unsupported gpu program type: " + toString(gptype));
+		}
+
+		BS_INC_RENDER_STAT(NumTextureBinds);
+	}
+
 	void D3D11RenderAPI::disableTextureUnit(GpuProgramType gptype, UINT16 texUnit)
 	{
 		THROW_IF_NOT_CORE_THREAD;

+ 2 - 2
Source/BansheeD3D9RenderAPI/Include/BsD3D9GpuBuffer.h

@@ -40,8 +40,8 @@ namespace BansheeEngine
 	protected:
 		friend class D3D9HardwareBufferCoreManager;
 
-		D3D9GpuBufferCore(UINT32 elementCount, UINT32 elementSize, GpuBufferType type, GpuBufferUsage usage,
-			bool randomGpuWrite = false, bool useCounter = false);
+		D3D9GpuBufferCore(UINT32 elementCount, UINT32 elementSize, GpuBufferType type, GpuBufferFormat format, 
+			GpuBufferUsage usage, bool randomGpuWrite = false, bool useCounter = false);
 
 		/** @copydoc GpuBufferCore::createView */
 		GpuBufferView* createView() override;

+ 2 - 2
Source/BansheeD3D9RenderAPI/Include/BsD3D9HardwareBufferManager.h

@@ -28,8 +28,8 @@ namespace BansheeEngine
 		SPtr<GpuParamBlockBufferCore> createGpuParamBlockBufferInternal(UINT32 size, GpuParamBlockUsage usage = GPBU_DYNAMIC) override;
 
 		/** @copydoc HardwareBufferCoreManager::createGpuBufferInternal */
-		SPtr<GpuBufferCore> createGpuBufferInternal(UINT32 elementCount, UINT32 elementSize, 
-			GpuBufferType type, GpuBufferUsage usage, bool randomGpuWrite = false, bool useCounter = false) override;
+		SPtr<GpuBufferCore> createGpuBufferInternal(UINT32 elementCount, UINT32 elementSize, GpuBufferType type, 
+			GpuBufferFormat format, GpuBufferUsage usage, bool randomGpuWrite = false, bool useCounter = false) override;
     };
 
 	/** @} */

+ 3 - 0
Source/BansheeD3D9RenderAPI/Include/BsD3D9RenderAPI.h

@@ -54,6 +54,9 @@ namespace BansheeEngine
 		/** @copydoc RenderAPICore::setTexture() */
 		void setTexture(GpuProgramType gptype, UINT16 texUnit, bool enabled, const SPtr<TextureCore>& texPtr) override;
 
+		/** @copydoc RenderAPICore::setBuffer */
+		void setBuffer(GpuProgramType gptype, UINT16 unit, const SPtr<GpuBufferCore>& buffer, bool loadStore = false) override;
+
 		/** @copydoc RenderAPICore::setLoadStoreTexture() */
 		void setLoadStoreTexture(GpuProgramType gptype, UINT16 texUnit, bool enabled, const SPtr<TextureCore>& texPtr,
 			const TextureSurface& surface) override;

+ 3 - 3
Source/BansheeD3D9RenderAPI/Source/BsD3D9GpuBuffer.cpp

@@ -5,9 +5,9 @@
 
 namespace BansheeEngine
 {
-	D3D9GpuBufferCore::D3D9GpuBufferCore(UINT32 elementCount, UINT32 elementSize, GpuBufferType type, 
-		GpuBufferUsage usage, bool randomGpuWrite, bool useCounter)
-		: GpuBufferCore(elementCount, elementSize, type, usage, randomGpuWrite, useCounter)
+	D3D9GpuBufferCore::D3D9GpuBufferCore(UINT32 elementCount, UINT32 elementSize, GpuBufferType type,
+		GpuBufferFormat format, GpuBufferUsage usage, bool randomGpuWrite, bool useCounter)
+		: GpuBufferCore(elementCount, elementSize, type, format, usage, randomGpuWrite, useCounter)
 	{
 	}
 

+ 2 - 2
Source/BansheeD3D9RenderAPI/Source/BsD3D9HardwareBufferManager.cpp

@@ -51,9 +51,9 @@ namespace BansheeEngine
 	}
 
 	SPtr<GpuBufferCore> D3D9HardwareBufferCoreManager::createGpuBufferInternal(UINT32 elementCount, UINT32 elementSize,
-		GpuBufferType type, GpuBufferUsage usage, bool randomGpuWrite, bool useCounter)
+		GpuBufferType type, GpuBufferFormat format, GpuBufferUsage usage, bool randomGpuWrite, bool useCounter)
 	{
-		D3D9GpuBufferCore* buffer = new (bs_alloc<D3D9GpuBufferCore>()) D3D9GpuBufferCore(elementCount, elementSize, type, usage, randomGpuWrite, useCounter);
+		D3D9GpuBufferCore* buffer = new (bs_alloc<D3D9GpuBufferCore>()) D3D9GpuBufferCore(elementCount, elementSize, type, format, usage, randomGpuWrite, useCounter);
 
 		SPtr<GpuBufferCore> bufferPtr = bs_shared_ptr<D3D9GpuBufferCore>(buffer);
 		bufferPtr->_setThisPtr(bufferPtr);

+ 7 - 0
Source/BansheeD3D9RenderAPI/Source/BsD3D9RenderAPI.cpp

@@ -486,6 +486,13 @@ namespace BansheeEngine
 		LOGWRN("Texture random load/store not supported on DX9.");
 	}
 
+	void D3D9RenderAPI::setBuffer(GpuProgramType gptype, UINT16 unit, const SPtr<GpuBufferCore>& buffer, bool loadStore)
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		LOGWRN("Generic GPU buffers not supported on DX9.");
+	}
+
 	void D3D9RenderAPI::setSamplerState(GpuProgramType gptype, UINT16 unit, const SPtr<SamplerStateCore>& state)
 	{
 		THROW_IF_NOT_CORE_THREAD;

+ 10 - 0
Source/BansheeEngine/Source/BsRendererUtility.cpp

@@ -266,6 +266,16 @@ namespace BansheeEngine
 					rs.setLoadStoreTexture(stage.type, iter->second.slot, true, texture, surface);
 			}
 
+			for (auto iter = paramDesc.buffers.begin(); iter != paramDesc.buffers.end(); ++iter)
+			{
+				SPtr<GpuBufferCore> buffer = params->getBuffer(iter->second.slot);
+
+				bool isLoadStore = iter->second.type != GPOT_BYTE_BUFFER &&
+					iter->second.type != GPOT_STRUCTURED_BUFFER;
+
+				rs.setBuffer(stage.type, iter->second.slot, buffer, isLoadStore);
+			}
+
 			rs.setConstantBuffers(stage.type, params);
 		}
 	}

+ 2 - 0
Source/BansheeGLRenderAPI/CMakeSources.cmake

@@ -30,6 +30,7 @@ set(BS_BANSHEEGLRENDERAPI_INC_NOFILTER
 	"Include/BsGLRenderAPI.h"
 	"Include/BsGLRenderAPIFactory.h"
 	"Include/BsGLUtil.h"
+	"Include/BsGLBuffer.h"
 )
 
 set(BS_BANSHEEGLRENDERAPI_SRC_WIN32
@@ -64,6 +65,7 @@ set(BS_BANSHEEGLRENDERAPI_SRC_NOFILTER
 	"Source/BsGLRenderAPI.cpp"
 	"Source/BsGLRenderAPIFactory.cpp"
 	"Source/BsGLPlugin.cpp"
+	"Source/BsGLBuffer.cpp"
 )
 
 set(BS_BANSHEEGLRENDERAPI_INC_GLSL

+ 69 - 0
Source/BansheeGLRenderAPI/Include/BsGLBuffer.h

@@ -0,0 +1,69 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsGLPrerequisites.h"
+#include "BsVertexBuffer.h"
+#include "BsGLVertexArrayObjectManager.h"
+
+namespace BansheeEngine 
+{
+	/** @addtogroup GL
+	 *  @{
+	 */
+
+	/** Wrapper around a generic OpenGL buffer. */
+    class BS_RSGL_EXPORT GLBuffer
+    {
+    public:
+		GLBuffer();
+		GLBuffer(GLenum target, UINT32 size, GpuBufferUsage usage);
+		~GLBuffer();
+
+		/**
+		 * Locks a portion of the buffer and returns pointer to the locked area. You must call unlock() when done.
+		 *
+		 * @param[in]	offset	Offset in bytes from which to lock the buffer.
+		 * @param[in]	length	Length of the area you want to lock, in bytes.
+		 * @param[in]	options	Signifies what you want to do with the returned pointer. Caller must ensure not to do 
+		 *						anything he hasn't requested (for example don't try to read from the buffer unless you
+		 *						requested it here).
+		 */
+		void* lock(UINT32 offset, UINT32 length, GpuLockOptions options);
+
+		/**	Releases the lock on this buffer. */
+		void unlock();
+
+		/**
+		 * Reads data from a portion of the buffer and copies it to the destination buffer. Caller must ensure destination 
+		 * buffer is large enough.
+		 *
+		 * @param[in]	offset	Offset in bytes from which to copy the data.
+		 * @param[in]	length	Length of the area you want to copy, in bytes.
+		 * @param[in]	dest	Destination buffer large enough to store the read data.
+		 */
+        void readData(UINT32 offset, UINT32 length, void* dest);
+
+		/**
+		 * Writes data into a portion of the buffer from the source memory. 
+		 *
+		 * @param[in]	offset		Offset in bytes from which to copy the data.
+		 * @param[in]	length		Length of the area you want to copy, in bytes.
+		 * @param[in]	source		Source buffer containing the data to write.
+		 * @param[in]	writeFlags	Optional write flags that may affect performance.
+		 */
+        void writeData(UINT32 offset, UINT32 length, const void* source, 
+			BufferWriteType writeFlags = BufferWriteType::Normal);
+
+		/**	Returns internal OpenGL buffer ID. */
+        GLuint getGLBufferId() const { return mBufferId; }
+
+	private:
+		GLenum mTarget;
+		GLuint mBufferId;
+
+		bool mZeroLocked;
+    };
+
+	/** @} */
+}

+ 20 - 4
Source/BansheeGLRenderAPI/Include/BsGLGpuBuffer.h

@@ -4,6 +4,7 @@
 
 #include "BsGLPrerequisites.h"
 #include "BsGpuBuffer.h"
+#include "BsGLBuffer.h"
 
 namespace BansheeEngine
 {
@@ -12,7 +13,6 @@ namespace BansheeEngine
 	 */
 
 	/**	OpenGL implementation of a generic GPU buffer. */
-	// TODO - Not implemented, just a dummy class for now
 	class BS_RSGL_EXPORT GLGpuBufferCore : public GpuBufferCore
 	{
 	public:
@@ -35,20 +35,36 @@ namespace BansheeEngine
 		void copyData(GpuBufferCore& srcBuffer, UINT32 srcOffset,
 			UINT32 dstOffset, UINT32 length, bool discardWholeBuffer = false) override;
 
+		/**	
+		 * Returns internal OpenGL buffer ID. If binding the buffer to the pipeline, bind the texture using
+		 * getGLTextureId() instead. 
+		 */
+		GLuint getGLBufferId() const { return mBuffer.getGLBufferId(); }
+
+		/**	Returns internal OpenGL texture ID. */
+		GLuint getGLTextureId() const { return mTextureID; }
+
+		/** Returns the internal OpenGL format used by the elements of the buffer. */
+		GLuint getGLFormat() const { return mFormat; }
+
 	protected:
 		friend class GLHardwareBufferCoreManager;
 
-		GLGpuBufferCore(UINT32 elementCount, UINT32 elementSize, GpuBufferType type, 
+		GLGpuBufferCore(UINT32 elementCount, UINT32 elementSize, GpuBufferType type, GpuBufferFormat format,
 			GpuBufferUsage usage, bool randomGpuWrite = false, bool useCounter = false);
 
 		/** @copydoc GpuBufferCore::initialize */
 		void initialize() override;
 
 		/** @copydoc GpuBufferCore::createView */
-		virtual GpuBufferView* createView() override;
+		GpuBufferView* createView() override;
 
 		/** @copydoc GpuBufferCore::destroyView */
-		virtual void destroyView(GpuBufferView* view) override;
+		void destroyView(GpuBufferView* view) override;
+
+		GLuint mTextureID;
+		GLBuffer mBuffer;
+		GLenum mFormat;
 	};
 
 	/** @} */

+ 2 - 2
Source/BansheeGLRenderAPI/Include/BsGLHardwareBufferManager.h

@@ -33,8 +33,8 @@ namespace BansheeEngine
 		SPtr<GpuParamBlockBufferCore> createGpuParamBlockBufferInternal(UINT32 size, GpuParamBlockUsage usage = GPBU_DYNAMIC) override;
 
 		/** @copydoc HardwareBufferCoreManager::createGpuBufferInternal */
-		SPtr<GpuBufferCore> createGpuBufferInternal(UINT32 elementCount, UINT32 elementSize, 
-			GpuBufferType type, GpuBufferUsage usage, bool randomGpuWrite = false, bool useCounter = false) override;
+		SPtr<GpuBufferCore> createGpuBufferInternal(UINT32 elementCount, UINT32 elementSize, GpuBufferType type, 
+			GpuBufferFormat format, GpuBufferUsage usage, bool randomGpuWrite = false, bool useCounter = false) override;
     };
 
 	/** @} */

+ 3 - 3
Source/BansheeGLRenderAPI/Include/BsGLIndexBuffer.h

@@ -4,6 +4,7 @@
 
 #include "BsGLPrerequisites.h"
 #include "BsIndexBuffer.h"
+#include "BsGLBuffer.h"
 
 namespace BansheeEngine 
 { 
@@ -26,7 +27,7 @@ namespace BansheeEngine
 			BufferWriteType writeFlags = BufferWriteType::Normal) override;
 
 		/**	Returns internal OpenGL index buffer handle. */
-        GLuint getGLBufferId() const { return mBufferId; }
+        GLuint getGLBufferId() const { return mBuffer.getGLBufferId(); }
 
 	protected:
 		/** @copydoc IndexBufferCore::initialize */
@@ -39,8 +40,7 @@ namespace BansheeEngine
 		void unlockImpl() override;
 
 	private:
-		GLuint mBufferId;
-		bool mZeroLocked;
+		GLBuffer mBuffer;
     };
 
 	/** @} */

+ 4 - 0
Source/BansheeGLRenderAPI/Include/BsGLPixelFormat.h

@@ -44,6 +44,10 @@ namespace BansheeEngine
 
 		/**	Converts an OpenGL internal format into base format. */
 		static GLenum getBaseFormatFromCompressedInternalFormat(GLenum internalFormat);
+
+		/** Converts engine GPU buffer format to OpenGL GPU buffer format. */
+		static GLenum getBufferFormat(GpuBufferFormat format);
+
 	};
 
 	/** @} */

+ 3 - 0
Source/BansheeGLRenderAPI/Include/BsGLRenderAPI.h

@@ -52,6 +52,9 @@ namespace BansheeEngine
 		void setLoadStoreTexture(GpuProgramType gptype, UINT16 texUnit, bool enabled, const SPtr<TextureCore>& texPtr,
 			const TextureSurface& surface) override;
         
+		/** @copydoc RenderAPICore::setBuffer */
+		void setBuffer(GpuProgramType gptype, UINT16 unit, const SPtr<GpuBufferCore>& buffer, bool loadStore = false) override;
+
 		/** @copydoc RenderAPICore::setSamplerState() */
 		void setSamplerState(GpuProgramType gptype, UINT16 texUnit, const SPtr<SamplerStateCore>& samplerState) override;
 

+ 3 - 3
Source/BansheeGLRenderAPI/Include/BsGLVertexBuffer.h

@@ -4,6 +4,7 @@
 
 #include "BsGLPrerequisites.h"
 #include "BsVertexBuffer.h"
+#include "BsGLBuffer.h"
 #include "BsGLVertexArrayObjectManager.h"
 
 namespace BansheeEngine 
@@ -27,7 +28,7 @@ namespace BansheeEngine
 			BufferWriteType writeFlags = BufferWriteType::Normal) override;
 
 		/**	Returns internal OpenGL buffer ID. */
-        GLuint getGLBufferId() const { return mBufferId; }
+        GLuint getGLBufferId() const { return mBuffer.getGLBufferId(); }
 
 		/**	Registers a new VertexArrayObject that uses this vertex buffer. */
 		void registerVAO(const GLVertexArrayObject& vao);
@@ -46,8 +47,7 @@ namespace BansheeEngine
 		void unlockImpl() override;
 
 	private:
-		GLuint mBufferId;
-		bool mZeroLocked;
+		GLBuffer mBuffer;
 
 		Vector<GLVertexArrayObject> mVAObjects;
     };

+ 106 - 0
Source/BansheeGLRenderAPI/Source/BsGLBuffer.cpp

@@ -0,0 +1,106 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsGLBuffer.h"
+#include "BsGLHardwareBufferManager.h"
+#include "BsException.h"
+
+namespace BansheeEngine
+{
+	GLBuffer::GLBuffer()
+		:mTarget(0), mBufferId(0), mZeroLocked(false)
+	{
+		
+	}
+
+	GLBuffer::GLBuffer(GLenum target, UINT32 size, GpuBufferUsage usage)
+		:mTarget(target), mBufferId(0), mZeroLocked(false)
+	{
+		glGenBuffers(1, &mBufferId);
+
+		if (!mBufferId)
+		{
+			BS_EXCEPT(InternalErrorException, "Cannot create GL vertex buffer");
+		}
+
+		glBindBuffer(target, mBufferId);
+		glBufferData(target, size, nullptr, GLHardwareBufferCoreManager::getGLUsage(usage));
+	}
+
+	GLBuffer::~GLBuffer()
+	{
+		glDeleteBuffers(1, &mBufferId);
+	}
+
+	void* GLBuffer::lock(UINT32 offset, UINT32 length, GpuLockOptions options)
+	{
+		GLenum access = 0;
+
+		glBindBuffer(mTarget, mBufferId);
+
+		if ((options == GBL_WRITE_ONLY) || (options == GBL_WRITE_ONLY_NO_OVERWRITE) || (options == GBL_WRITE_ONLY_DISCARD))
+		{
+			access = GL_MAP_WRITE_BIT;
+
+			if (options == GBL_WRITE_ONLY_DISCARD)
+				access |= GL_MAP_INVALIDATE_BUFFER_BIT;
+			else if (options == GBL_WRITE_ONLY_NO_OVERWRITE)
+				access |= GL_MAP_UNSYNCHRONIZED_BIT;
+		}
+		else if (options == GBL_READ_ONLY)
+			access = GL_MAP_READ_BIT;
+		else
+			access = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
+
+		void* buffer = nullptr;
+
+		if (length > 0)
+		{
+			buffer = glMapBufferRange(mTarget, offset, length, access);
+
+			if (buffer == nullptr)
+			{
+				BS_EXCEPT(InternalErrorException, "Cannot map vertex buffer.");
+			}
+
+			mZeroLocked = false;
+		}
+		else
+			mZeroLocked = true;
+
+		return static_cast<void*>(static_cast<unsigned char*>(buffer));
+	}
+
+	void GLBuffer::unlock()
+	{
+		glBindBuffer(mTarget, mBufferId);
+
+		if (!mZeroLocked)
+		{
+			if (!glUnmapBuffer(mTarget))
+			{
+				BS_EXCEPT(InternalErrorException, "Buffer data corrupted, please reload.");
+			}
+		}
+	}
+
+	void GLBuffer::readData(UINT32 offset, UINT32 length, void* pDest)
+	{
+		void* bufferData = lock(offset, length, GBL_READ_ONLY);
+		memcpy(pDest, bufferData, length);
+		unlock();
+	}
+
+	void GLBuffer::writeData(UINT32 offset, UINT32 length,
+		const void* pSource, BufferWriteType writeFlags)
+	{
+		GpuLockOptions lockOption = GBL_WRITE_ONLY;
+		if (writeFlags == BufferWriteType::Discard)
+			lockOption = GBL_WRITE_ONLY_DISCARD;
+		else if (writeFlags == BufferWriteType::NoOverwrite)
+			lockOption = GBL_WRITE_ONLY_NO_OVERWRITE;
+
+		void* bufferData = lock(offset, length, lockOption);
+		memcpy(bufferData, pSource, length);
+		unlock();
+	}
+}

+ 38 - 4
Source/BansheeGLRenderAPI/Source/BsGLGpuBuffer.cpp

@@ -3,23 +3,46 @@
 #include "BsGLGpuBuffer.h"
 #include "BsDebug.h"
 #include "BsRenderStats.h"
+#include "BsGLPixelFormat.h"
+#include "BsGLHardwareBufferManager.h"
 
 namespace BansheeEngine
 {
-	GLGpuBufferCore::GLGpuBufferCore(UINT32 elementCount, UINT32 elementSize, GpuBufferType type, GpuBufferUsage usage, bool randomGpuWrite, bool useCounter)
-		: GpuBufferCore(elementCount, elementSize, type, usage, randomGpuWrite, useCounter)
+	GLGpuBufferCore::GLGpuBufferCore(UINT32 elementCount, UINT32 elementSize, GpuBufferType type, GpuBufferFormat format,
+		GpuBufferUsage usage, bool randomGpuWrite, bool useCounter)
+		: GpuBufferCore(elementCount, elementSize, type, format, usage, randomGpuWrite, useCounter), mTextureID(0), mFormat(0)
 	{
+		if(type != GBT_STANDARD)
+			LOGERR("Only standard buffers are support on OpenGL.");
+
+		if (useCounter)
+			LOGERR("Buffer counters not supported on OpenGL.");
+
+		// Note: Implement OpenGL shader storage buffers, append/consume buffers, transform feedback buffers, 
+		// indirect argument buffers and counter buffers
+
+		mFormat = GLPixelUtil::getBufferFormat(format);
 	}
 
 	GLGpuBufferCore::~GLGpuBufferCore()
 	{
+		glDeleteTextures(1, &mTextureID);
+
 		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_GpuBuffer);
 		clearBufferViews();
 	}
 
 	void GLGpuBufferCore::initialize()
 	{
-		LOGWRN("Generic buffers are not supported in OpenGL. Creating a dummy buffer. All operations on it will either be no-op or return a nullptr.");
+		// Create buffer
+		const auto& props = getProperties();
+		UINT32 size = props.getElementCount() * props.getElementSize();
+		mBuffer = GLBuffer(GL_TEXTURE_BUFFER, size, props.getUsage());
+		
+		// Create texture
+		glGenTextures(1, &mTextureID);
+		glBindTexture(GL_TEXTURE_BUFFER, mTextureID);
+		glTexBuffer(GL_TEXTURE_BUFFER, mFormat, mBuffer.getGLBufferId());
 
 		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_GpuBuffer);
 		GpuBufferCore::initialize();
@@ -39,34 +62,45 @@ namespace BansheeEngine
 		}
 #endif
 
-		return nullptr;
+		return mBuffer.lock(offset, length, options);
 	}
 
 	void GLGpuBufferCore::unlock()
 	{
+		mBuffer.unlock();
 	}
 
 	void GLGpuBufferCore::readData(UINT32 offset, UINT32 length, void* pDest)
 	{
+		mBuffer.readData(offset, length, pDest);
+
 		BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_GpuBuffer);
 	}
 
 	void GLGpuBufferCore::writeData(UINT32 offset, UINT32 length, const void* pSource, BufferWriteType writeFlags)
 	{
+		mBuffer.writeData(offset, length, pSource, writeFlags);
+
 		BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_GpuBuffer);
 	}
 
 	void GLGpuBufferCore::copyData(GpuBufferCore& srcBuffer, UINT32 srcOffset,
 		UINT32 dstOffset, UINT32 length, bool discardWholeBuffer)
 	{
+		GLGpuBufferCore& glSrcBuffer = static_cast<GLGpuBufferCore&>(srcBuffer);
+
+		GLuint srcId = glSrcBuffer.getGLBufferId();
+		glCopyBufferSubData(srcId, getGLBufferId(), srcOffset, dstOffset, length);
 	}
 
 	GpuBufferView* GLGpuBufferCore::createView()
 	{
+		// Not used for OpenGL
 		return nullptr;
 	}
 
 	void GLGpuBufferCore::destroyView(GpuBufferView* view)
 	{
+		// Not used for OpenGL
 	}
 }

+ 3 - 2
Source/BansheeGLRenderAPI/Source/BsGLHardwareBufferManager.cpp

@@ -38,9 +38,10 @@ namespace BansheeEngine
 	}
 
 	SPtr<GpuBufferCore> GLHardwareBufferCoreManager::createGpuBufferInternal(UINT32 elementCount, UINT32 elementSize,
-		GpuBufferType type, GpuBufferUsage usage, bool randomGpuWrite, bool useCounter)
+		GpuBufferType type, GpuBufferFormat format, GpuBufferUsage usage, bool randomGpuWrite, bool useCounter)
 	{
-		GLGpuBufferCore* buffer = new (bs_alloc<GLGpuBufferCore>()) GLGpuBufferCore(elementCount, elementSize, type, usage, randomGpuWrite, useCounter);
+		GLGpuBufferCore* buffer = new (bs_alloc<GLGpuBufferCore>()) GLGpuBufferCore(elementCount, elementSize, type, format,
+			usage, randomGpuWrite, useCounter);
 
 		SPtr<GpuBufferCore> bufferPtr = bs_shared_ptr<GLGpuBufferCore>(buffer);
 		bufferPtr->_setThisPtr(bufferPtr);

+ 16 - 103
Source/BansheeGLRenderAPI/Source/BsGLIndexBuffer.cpp

@@ -8,127 +8,40 @@
 namespace BansheeEngine 
 {
 	GLIndexBufferCore::GLIndexBufferCore(IndexType idxType, UINT32 numIndices, GpuBufferUsage usage)
-		:IndexBufferCore(idxType, numIndices, usage), mZeroLocked(false)
+		:IndexBufferCore(idxType, numIndices, usage)
 	{  }
 
 	GLIndexBufferCore::~GLIndexBufferCore()
 	{
-		glDeleteBuffers(1, &mBufferId);
-
 		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_IndexBuffer);
 	}
 
 	void GLIndexBufferCore::initialize()
 	{
-		glGenBuffers(1, &mBufferId );
-
-		if (!mBufferId)
-		{
-			BS_EXCEPT(InternalErrorException, "Cannot create GL index buffer");
-		}
-
-		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mBufferId);
-
-		glBufferData(GL_ELEMENT_ARRAY_BUFFER, mSizeInBytes, NULL, 
-			GLHardwareBufferCoreManager::getGLUsage(mUsage));
+		mBuffer = GLBuffer(GL_ELEMENT_ARRAY_BUFFER, mSizeInBytes, mUsage);
 
 		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_IndexBuffer);
 		IndexBufferCore::initialize();
 	}
 
 	void* GLIndexBufferCore::lockImpl(UINT32 offset, UINT32 length, GpuLockOptions options)
-    {
-        GLenum access = 0;
-        if(mIsLocked)
-        {
-            BS_EXCEPT(InternalErrorException, 
-                "Invalid attempt to lock an index buffer that has already been locked");
-        }
-
-#if BS_PROFILING_ENABLED
-		if (options == GBL_READ_ONLY || options == GBL_READ_WRITE)
-		{
-			BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_IndexBuffer);
-		}
-
-		if (options == GBL_READ_WRITE || options == GBL_WRITE_ONLY || options == GBL_WRITE_ONLY_DISCARD || options == GBL_WRITE_ONLY_NO_OVERWRITE)
-		{
-			BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_IndexBuffer);
-		}
-#endif
-
-		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mBufferId);
-
-		if ((options == GBL_WRITE_ONLY) || (options == GBL_WRITE_ONLY_NO_OVERWRITE) || (options == GBL_WRITE_ONLY_DISCARD))
-		{
-			access = GL_MAP_WRITE_BIT;
-
-			if(options == GBL_WRITE_ONLY_DISCARD)
-				access |= GL_MAP_INVALIDATE_BUFFER_BIT;
-			else if(options == GBL_WRITE_ONLY_NO_OVERWRITE)
-				access |= GL_MAP_UNSYNCHRONIZED_BIT;
-		}
-		else if (options == GBL_READ_ONLY)
-			access = GL_MAP_READ_BIT;
-		else
-			access = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
-
-		void* pBuffer = nullptr;
-		
-		if (length > 0)
-		{
-			pBuffer = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, offset, length, access);
-
-			if (pBuffer == nullptr)
-			{
-				BS_EXCEPT(InternalErrorException, "Index Buffer: Out of memory");
-			}
-
-			mZeroLocked = false;
-		}
-		else
-			mZeroLocked = true;
-
-		void* retPtr = static_cast<void*>(static_cast<unsigned char*>(pBuffer));
-
-		mIsLocked = true;
-		return retPtr;
-    }
+	{
+		return mBuffer.lock(offset, length, options);
+	}
 
 	void GLIndexBufferCore::unlockImpl()
-    {
-		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mBufferId);
-
-		if (!mZeroLocked)
-		{
-			if (!glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER))
-			{
-				BS_EXCEPT(InternalErrorException, "Buffer data corrupted, please reload");
-			}
-		}
-
-		mIsLocked = false;
-    }
+	{
+		mBuffer.unlock();
+	}
 
-	void GLIndexBufferCore::readData(UINT32 offset, UINT32 length,
-        void* pDest)
-    {
-		void* bufferData = lock(offset, length, GBL_READ_ONLY);
-		memcpy(pDest, bufferData, length);
-		unlock();
-    }
+	void GLIndexBufferCore::readData(UINT32 offset, UINT32 length, void* pDest)
+	{
+		mBuffer.readData(offset, length, pDest);
+	}
 
-    void GLIndexBufferCore::writeData(UINT32 offset, UINT32 length, 
+	void GLIndexBufferCore::writeData(UINT32 offset, UINT32 length,
 		const void* pSource, BufferWriteType writeFlags)
-    {
-		GpuLockOptions lockOption = GBL_WRITE_ONLY;
-		if(writeFlags == BufferWriteType::Discard)
-			lockOption = GBL_WRITE_ONLY_DISCARD;
-		else if(writeFlags == BufferWriteType::NoOverwrite)
-			lockOption = GBL_WRITE_ONLY_NO_OVERWRITE;
-
-		void* bufferData = lock(offset, length, lockOption);
-		memcpy(bufferData, pSource, length);
-		unlock();
-    }
+	{
+		mBuffer.writeData(offset, length, pSource, writeFlags);
+	}
 }

+ 50 - 0
Source/BansheeGLRenderAPI/Source/BsGLPixelFormat.cpp

@@ -379,4 +379,54 @@ namespace BansheeEngine
 			return PF_UNKNOWN;
 		}
 	}
+
+	GLenum GLPixelUtil::getBufferFormat(GpuBufferFormat format)
+	{
+		static bool lookupInitialized = false;
+
+		static GLenum lookup[BF_COUNT];
+		if (!lookupInitialized)
+		{
+			lookup[BF_16X1F] = GL_R16F;
+			lookup[BF_16X2F] = GL_RG16F;
+			lookup[BF_16X4F] = GL_RGBA16F;
+			lookup[BF_32X1F] = GL_R32F;
+			lookup[BF_32X2F] = GL_RG32F;
+			lookup[BF_32X3F] = GL_RGB32F;
+			lookup[BF_32X4F] = GL_RGBA32F;
+			lookup[BF_8X1] = GL_R8;
+			lookup[BF_8X2] = GL_RG8;
+			lookup[BF_8X4] = GL_RGBA8;
+			lookup[BF_16X1] = GL_R16;
+			lookup[BF_16X2] = GL_RG16;
+			lookup[BF_16X4] = GL_RGBA16;
+			lookup[BF_8X1S] = GL_R8I;
+			lookup[BF_8X2S] = GL_RG8I;
+			lookup[BF_8X4S] = GL_RGBA8I;
+			lookup[BF_16X1S] = GL_R16I;
+			lookup[BF_16X2S] = GL_RG16I;
+			lookup[BF_16X4S] = GL_RGBA16I;
+			lookup[BF_32X1S] = GL_R32I;
+			lookup[BF_32X2S] = GL_RG32I;
+			lookup[BF_32X3S] = GL_RGB32I;
+			lookup[BF_32X4S] = GL_RGBA32I;
+			lookup[BF_8X1U] = GL_R8UI;
+			lookup[BF_8X2U] = GL_RG8UI;
+			lookup[BF_8X4U] = GL_RGBA8UI;
+			lookup[BF_16X1U] = GL_R16UI;
+			lookup[BF_16X2U] = GL_RG16UI;
+			lookup[BF_16X4U] = GL_RGBA16UI;
+			lookup[BF_32X1U] = GL_R32UI;
+			lookup[BF_32X2U] = GL_RG32UI;
+			lookup[BF_32X3U] = GL_RGB32UI;
+			lookup[BF_32X4U] = GL_RGBA32UI;
+
+			lookupInitialized = true;
+		}
+
+		if (format >= BF_COUNT)
+			return GL_NONE;
+
+		return lookup[(UINT32)format];
+	}
 };

+ 18 - 0
Source/BansheeGLRenderAPI/Source/BsGLRenderAPI.cpp

@@ -24,6 +24,7 @@
 #include "BsDebug.h"
 #include "BsRenderStats.h"
 #include "BsGpuParamDesc.h"
+#include "BsGLGpuBuffer.h"
 
 namespace BansheeEngine 
 {
@@ -460,6 +461,23 @@ namespace BansheeEngine
 		BS_INC_RENDER_STAT(NumTextureBinds);
 	}
 
+	/** @copydoc RenderAPICore::setBuffer */
+	void GLRenderAPI::setBuffer(GpuProgramType gptype, UINT16 unit, const SPtr<GpuBufferCore>& buffer, bool loadStore)
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		if (buffer != nullptr)
+		{
+			SPtr<GLGpuBufferCore> glBuffer = std::static_pointer_cast<GLGpuBufferCore>(buffer);
+			glBindImageTexture(unit, glBuffer->getGLTextureId(), 0, false,
+				0, glBuffer->getGLFormat(), GL_READ_WRITE);
+		}
+		else
+			glBindImageTexture(unit, 0, 0, false, 0, 0, GL_READ_WRITE);
+
+		BS_INC_RENDER_STAT(NumTextureBinds);
+	}
+
 	void GLRenderAPI::setBlendState(const SPtr<BlendStateCore>& blendState)
 	{
 		THROW_IF_NOT_CORE_THREAD;

+ 18 - 0
Source/BansheeGLRenderAPI/Source/BsGLSLParamParser.cpp

@@ -266,6 +266,7 @@ namespace BansheeEngine
 
 			bool isSampler = false;
 			bool isImage = false;
+			bool isBuffer = false;
 			switch (uniformType)
 			{
 			case GL_SAMPLER_1D:
@@ -282,6 +283,10 @@ namespace BansheeEngine
 			case GL_IMAGE_2D_MULTISAMPLE:
 				isImage = true;
 				break;
+			case GL_SAMPLER_BUFFER:
+			case GL_IMAGE_BUFFER:
+				isBuffer = false;
+				break;
 			}
 
 			if (isSampler)
@@ -345,6 +350,19 @@ namespace BansheeEngine
 
 				returnParamDesc.loadStoreTextures.insert(std::make_pair(paramName, textureParam));
 			}
+			else if (isBuffer)
+			{
+				GpuParamObjectDesc bufferParam;
+				bufferParam.name = paramName;
+				bufferParam.slot = glGetUniformLocation(glProgram, uniformName);
+
+				if (uniformType == GL_IMAGE_BUFFER)
+					bufferParam.type = GPOT_RWSTRUCTURED_BUFFER;
+				else // Sampler buffer
+					bufferParam.type = GPOT_STRUCTURED_BUFFER;
+
+				returnParamDesc.buffers.insert(std::make_pair(paramName, bufferParam));
+			}
 			else
 			{
 				// If array index is larger than 0 and uniform is not a part of a struct,

+ 7 - 95
Source/BansheeGLRenderAPI/Source/BsGLVertexBuffer.cpp

@@ -9,15 +9,13 @@
 namespace BansheeEngine 
 {
 	GLVertexBufferCore::GLVertexBufferCore(UINT32 vertexSize, UINT32 numVertices, GpuBufferUsage usage, bool streamOut)
-		:VertexBufferCore(vertexSize, numVertices, usage, streamOut), mZeroLocked(false)
+		:VertexBufferCore(vertexSize, numVertices, usage, streamOut)
     {
 
     }
 
 	GLVertexBufferCore::~GLVertexBufferCore()
 	{
-		glDeleteBuffers(1, &mBufferId);
-
 		while (mVAObjects.size() > 0)
 			GLVertexArrayObjectManager::instance().notifyBufferDestroyed(mVAObjects[0]);
 
@@ -26,19 +24,8 @@ namespace BansheeEngine
 
 	void GLVertexBufferCore::initialize()
 	{
-		glGenBuffers(1, &mBufferId);
-
-		if (!mBufferId)
-		{
-			BS_EXCEPT(InternalErrorException,
-				"Cannot create GL vertex buffer");
-		}
-
-		glBindBuffer(GL_ARRAY_BUFFER, mBufferId);
-
-		glBufferData(GL_ARRAY_BUFFER, mSizeInBytes, NULL,
-			GLHardwareBufferCoreManager::getGLUsage(mUsage));
-
+		mBuffer = GLBuffer(GL_ARRAY_BUFFER, mSizeInBytes, mUsage);
+		
 		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_VertexBuffer);
 		VertexBufferCore::initialize();
 	}
@@ -58,97 +45,22 @@ namespace BansheeEngine
 
 	void* GLVertexBufferCore::lockImpl(UINT32 offset, UINT32 length, GpuLockOptions options)
     {
-        GLenum access = 0;
-
-        if(mIsLocked)
-        {
-			BS_EXCEPT(InternalErrorException,
-                "Invalid attempt to lock a vertex buffer that has already been locked");
-        }
-
-#if BS_PROFILING_ENABLED
-		if (options == GBL_READ_ONLY || options == GBL_READ_WRITE)
-		{
-			BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_VertexBuffer);
-		}
-
-		if (options == GBL_READ_WRITE || options == GBL_WRITE_ONLY || options == GBL_WRITE_ONLY_DISCARD || options == GBL_WRITE_ONLY_NO_OVERWRITE)
-		{
-			BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_VertexBuffer);
-		}
-#endif
-
-		glBindBuffer(GL_ARRAY_BUFFER, mBufferId);
-
-		if ((options == GBL_WRITE_ONLY) || (options == GBL_WRITE_ONLY_NO_OVERWRITE) || (options == GBL_WRITE_ONLY_DISCARD))
-		{
-			access = GL_MAP_WRITE_BIT;
-
-			if(options == GBL_WRITE_ONLY_DISCARD)
-				access |= GL_MAP_INVALIDATE_BUFFER_BIT;
-			else if(options == GBL_WRITE_ONLY_NO_OVERWRITE)
-				access |= GL_MAP_UNSYNCHRONIZED_BIT;
-		}
-		else if (options == GBL_READ_ONLY)
-			access = GL_MAP_READ_BIT;
-		else
-			access = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
-
-		void* buffer = nullptr;
-
-		if (length > 0)
-		{
-			buffer = glMapBufferRange(GL_ARRAY_BUFFER, offset, length, access);
-
-			if (buffer == nullptr)
-			{
-				BS_EXCEPT(InternalErrorException, "Cannot map vertex buffer.");
-			}
-
-			mZeroLocked = false;
-		}
-		else
-			mZeroLocked = true;
-
-		void* retPtr = static_cast<void*>(static_cast<unsigned char*>(buffer));
-
-		mIsLocked = true;
-		return retPtr;
+		return mBuffer.lock(offset, length, options);
     }
 
 	void GLVertexBufferCore::unlockImpl()
     {
-		glBindBuffer(GL_ARRAY_BUFFER, mBufferId);
-
-		if (!mZeroLocked)
-		{
-			if (!glUnmapBuffer(GL_ARRAY_BUFFER))
-			{
-				BS_EXCEPT(InternalErrorException, "Buffer data corrupted, please reload.");
-			}
-		}
-
-        mIsLocked = false;
+		mBuffer.unlock();
     }
 
 	void GLVertexBufferCore::readData(UINT32 offset, UINT32 length, void* pDest)
     {
-		void* bufferData = lock(offset, length, GBL_READ_ONLY);
-		memcpy(pDest, bufferData, length);
-		unlock();
+		mBuffer.readData(offset, length, pDest);
     }
 
 	void GLVertexBufferCore::writeData(UINT32 offset, UINT32 length,
 		const void* pSource, BufferWriteType writeFlags)
     {
-		GpuLockOptions lockOption = GBL_WRITE_ONLY;
-		if(writeFlags == BufferWriteType::Discard)
-			lockOption = GBL_WRITE_ONLY_DISCARD;
-		else if(writeFlags == BufferWriteType::NoOverwrite)
-			lockOption = GBL_WRITE_ONLY_NO_OVERWRITE;
-
-		void* bufferData = lock(offset, length, lockOption);
-		memcpy(bufferData, pSource, length);
-		unlock();
+		mBuffer.writeData(offset, length, pSource, writeFlags);
     }
 }