瀏覽代碼

VAO management to OpenGL (untested)
More documentation

Marko Pintera 11 年之前
父節點
當前提交
d19ac30b58

+ 0 - 7
BoostPort.txt

@@ -9,13 +9,6 @@ DEBUG CODE in GLRenderSystem::beginDraw()
 I'll probably want a system like PipelineManager where it saves all VS and VB combinations and retuns vertex array for it.
  - Those vertex arrays should probably be saved in the vertex shader
 
-Each VertexDeclaration needs unique ID. 
- - Attempt to make vertex declarations immutable. Once created they get a unique ID.
- - Do the same for vertex buffers and vertex shaders
- - Remove hash from vertex declaration and replace it with ID, also fix the comparison functions because
-   in DX11 finding input layout will involve going over every single element in the declaration since it's
-   stored in an unordered map.
-
 Create a proper git repo of dependencies folder
 
 Shutdown issues (can't repro atm but they're there):

+ 151 - 179
CamelotCore/Include/CmCommonEnums.h

@@ -1,33 +1,4 @@
-/*
------------------------------------------------------------------------------
-This source file is part of OGRE
-    (Object-oriented Graphics Rendering Engine)
-For the latest info, see http://www.ogre3d.org/
-
-Copyright (c) 2000-2011 Torus Knot Software Ltd
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
------------------------------------------------------------------------------
-*/
-#ifndef __Common_H__
-#define __Common_H__
-// Common stuff
+#pragma once
 
 #include "CmString.h"
 
@@ -42,199 +13,180 @@ THE SOFTWARE.
 #   pragma GCC visibility pop
 #endif
 
-namespace BansheeEngine {
-	/** \addtogroup Core
-	*  @{
-	*/
-	/** \addtogroup General
-	*  @{
-	*/
-
-	/** Blending factors for manually blending objects with the scene. If there isn't a predefined
-        SceneBlendType that you like, then you can specify the blending factors directly to affect the
-        combination of object and the existing scene. See Material::setSceneBlending for more details.
-    */
+namespace BansheeEngine 
+{
+	/**
+	 * @brief	Factors used when blending new pixels with existing pixels.
+	 */
     enum BlendFactor
     {
-        BF_ONE,
-        BF_ZERO,
-        BF_DEST_COLOR,
-        BF_SOURCE_COLOR,
-        BF_INV_DEST_COLOR,
-        BF_INV_SOURCE_COLOR,
-        BF_DEST_ALPHA,
-        BF_SOURCE_ALPHA,
-        BF_INV_DEST_ALPHA,
-        BF_INV_SOURCE_ALPHA
+		BF_ONE, /**< Use a value of one for all pixel components. */
+		BF_ZERO, /**< Use a value of zero for all pixel components. */
+		BF_DEST_COLOR, /**< Use the existing pixel value. */
+		BF_SOURCE_COLOR, /**< Use the newly generated pixel value. */
+		BF_INV_DEST_COLOR, /**< Use the inverse of the existing value. */
+		BF_INV_SOURCE_COLOR, /**< Use the inverse of the newly generated pixel value. */
+		BF_DEST_ALPHA, /**< Use the existing alpha value. */
+		BF_SOURCE_ALPHA, /**< Use the newly generated alpha value. */
+		BF_INV_DEST_ALPHA, /**< Use the inverse of the existing alpha value. */
+		BF_INV_SOURCE_ALPHA /**< Use the inverse of the newly generated alpha value. */
     };
 
-	/** Blending operations controls how objects are blended into the scene. The default operation
-		is add (+) but by changing this you can change how drawn objects are blended into the
-		existing scene.
-	*/
+	/**
+	 * @brief	Operations that determines how are blending factors combined.
+	 */
 	enum BlendOperation
 	{
-		BO_ADD,
-		BO_SUBTRACT,
-		BO_REVERSE_SUBTRACT,
-		BO_MIN,
-		BO_MAX
+		BO_ADD, /**< Blend factors are added together. */
+		BO_SUBTRACT, /**< Blend factors are subtracted in "srcFactor - dstFactor" order. */
+		BO_REVERSE_SUBTRACT, /**< Blend factors are subtracted in "dstFactor - srcFactor" order. */
+		BO_MIN, /**< Minimum of the two factors is chosen. */
+		BO_MAX /**< Maximum of the two factors is chosen. */
 	};
 
-    /** Comparison functions used for the depth/stencil buffer operations and 
-		others. */
+	/**
+	 * @brief	Comparison functions used for the depth/stencil buffer.
+	 */
     enum CompareFunction
     {
-        CMPF_ALWAYS_FAIL,
-        CMPF_ALWAYS_PASS,
-        CMPF_LESS,
-        CMPF_LESS_EQUAL,
-        CMPF_EQUAL,
-        CMPF_NOT_EQUAL,
-        CMPF_GREATER_EQUAL,
-        CMPF_GREATER
+		CMPF_ALWAYS_FAIL, /**< Operation will always fail. */
+		CMPF_ALWAYS_PASS, /**< Operation will always pass. */
+		CMPF_LESS, /**< Operation will pass if the new value is less than existing value. */
+        CMPF_LESS_EQUAL, /**< Operation will pass if the new value is less or equal than existing value. */
+        CMPF_EQUAL, /**< Operation will pass if the new value is equal to the existing value. */
+        CMPF_NOT_EQUAL, /**< Operation will pass if the new value is not equal to the existing value. */
+        CMPF_GREATER_EQUAL, /**< Operation will pass if the new value greater or equal than the existing value. */
+        CMPF_GREATER /**< Operation will pass if the new value greater than the existing value. */
     };
 
-    /** Texture addressing modes - default is TAM_WRAP.
-    @note
-        These settings are relevant in both the fixed-function and the
-        programmable pipeline.
-    */
+	/**
+	 * @brief	Types of texture addressing modes that determine what happens when texture
+	 *			coordinates are outside of the valid range.
+	 */
     enum TextureAddressingMode
     {
-        /// Texture wraps at values over 1.0
-        TAM_WRAP,
-        /// Texture mirrors (flips) at joins over 1.0
-        TAM_MIRROR,
-        /// Texture clamps at 1.0
-        TAM_CLAMP,
-        /// Texture coordinates outside the range [0.0, 1.0] are set to the border color
-        TAM_BORDER
-    };
-
-    /** High-level filtering options providing shortcuts to settings the
-        minification, magnification and mip filters. */
-    enum TextureFilterOptions
-    {
-        /// Equal to: min=FO_POINT, mag=FO_POINT, mip=FO_NONE
-        TFO_NONE,
-        /// Equal to: min=FO_LINEAR, mag=FO_LINEAR, mip=FO_POINT
-        TFO_BILINEAR,
-        /// Equal to: min=FO_LINEAR, mag=FO_LINEAR, mip=FO_LINEAR
-        TFO_TRILINEAR,
-        /// Equal to: min=FO_ANISOTROPIC, max=FO_ANISOTROPIC, mip=FO_LINEAR
-		TFO_ANISOTROPIC
+		TAM_WRAP, /**< Coordinates wrap back to the valid range. */
+		TAM_MIRROR, /**< Coordinates flip every time the size of the valid range is passed. */
+		TAM_CLAMP, /**< Coordinates are clamped within the valid range. */
+		TAM_BORDER /**< Coordinates outside of the valid range will return a separately set border color. */
     };
 
+	/**
+	 * @brief	Types of available filtering situations.
+	 */
     enum FilterType
     {
-        /// The filter used when shrinking a texture
-        FT_MIN,
-        /// The filter used when magnifying a texture
-        FT_MAG,
-        /// The filter used when determining the mipmap
-        FT_MIP
+		FT_MIN, /**< The filter used when shrinking a texture. */
+        FT_MAG, /**< The filter used when magnifying a texture. */
+        FT_MIP /**< The filter used when filtering between mipmaps. */
     };
-    /** Filtering options for textures / mipmaps. */
+
+	/**
+	 * @brief	Filtering options for textures.
+	 */
     enum FilterOptions
     {
-        /// No filtering, used for FILT_MIP to turn off mipmapping
-        FO_NONE = 0,
-        /// Use the closest pixel
-        FO_POINT = 1,
-        /// Average of a 2x2 pixel area, denotes bilinear for MIN and MAG, trilinear for MIP
-        FO_LINEAR = 2,
-        /// Similar to FO_LINEAR, but compensates for the angle of the texture plane
-        FO_ANISOTROPIC = 3,
-		/// Specifies that the sampled values will be compared against existing sampled data. 
-		/// Should be OR-ed with other filtering options.
-		FO_USE_COMPARISON = 4
+		FO_NONE = 0, /**< Use no filtering. Only relevant for mipmap filtering. */
+		FO_POINT = 1, /**< Filter using the nearest found pixel. Most basic filtering. */
+		FO_LINEAR = 2, /**< Average a 2x2 pixel area, signifies bilinear filtering for texture, trilinear for mipmaps. */
+		FO_ANISOTROPIC = 3, /**< More advanced filtering that improves quality when viewing textures at a steep angle */
+		FO_USE_COMPARISON = 4 /**< Specifies that the sampled values will be compared against existing sampled data. Should be OR-ed with other filtering options. */
     };
 
-    /** Hardware culling modes based on vertex winding.
-        This setting applies to how the hardware API culls triangles it is sent. */
+	/**
+	 * @brief	Types of frame buffers.
+	 */
+	enum FrameBufferType
+	{
+		FBT_COLOR = 0x1,
+		FBT_DEPTH = 0x2,
+		FBT_STENCIL = 0x4
+	};
+
+	/**
+	 * @brief	Types of culling that determine how (and if) hardware discards faces with certain
+	 *			winding order. Winding order can be used for determining front or back facing polygons by
+	 *			checking the order of its vertices from the render perspective.
+	 */
     enum CullingMode
     {
-        /// Hardware never culls triangles and renders everything it receives.
-        CULL_NONE = 1,
-        /// Hardware culls triangles whose vertices are listed clockwise in the view (default).
-        CULL_CLOCKWISE = 2,
-        /// Hardware culls triangles whose vertices are listed anticlockwise in the view.
-        CULL_COUNTERCLOCKWISE = 3
+		CULL_NONE = 1, /**< Hardware performs no culling and renders both sides. */
+		CULL_CLOCKWISE = 2, /**< Hardware culls faces that have a clockwise vertex ordering. */
+        CULL_COUNTERCLOCKWISE = 3 /**< Hardware culls faces that have a counter-clockwise vertex ordering. */
     };
 
-    /** The polygon mode to use when rasterising. */
+	/**
+	 * @brief	Polygon mode to use when rasterizing.
+	 */
     enum PolygonMode
     {
-		/// Wireframe models are rendered.
-        PM_WIREFRAME = 1,
-		/// Solid polygons are rendered.
-        PM_SOLID = 2
-    };
-
-    /** Defines the frame buffer types. */
-    enum FrameBufferType {
-        FBT_COLOR  = 0x1,
-        FBT_DEPTH   = 0x2,
-        FBT_STENCIL = 0x4
+		PM_WIREFRAME = 1, /**< Render as wireframe showing only polygon outlines. */
+        PM_SOLID = 2 /**< Render as solid showing whole polygons. */
     };
 
-	/// Enum describing the various actions which can be taken onthe stencil buffer
+	/**
+	 * @brief	Types of action that can happen on the stencil buffer.
+	 */
 	enum StencilOperation
 	{
-		/// Leave the stencil buffer unchanged
-		SOP_KEEP,
-		/// Set the stencil value to zero
-		SOP_ZERO,
-		/// Set the stencil value to the reference value
-		SOP_REPLACE,
-		/// Increase the stencil value by 1, clamping at the maximum value
-		SOP_INCREMENT,
-		/// Decrease the stencil value by 1, clamping at 0
-		SOP_DECREMENT,
-		/// Increase the stencil value by 1, wrapping back to 0 when incrementing the maximum value
-		SOP_INCREMENT_WRAP,
-		/// Decrease the stencil value by 1, wrapping when decrementing 0
-		SOP_DECREMENT_WRAP,
-		/// Invert the bits of the stencil buffer
-		SOP_INVERT
+		SOP_KEEP, /**< Leave the stencil buffer unchanged. */
+		SOP_ZERO, /**< Set the stencil value to zero. */
+		SOP_REPLACE, /**< Replace the stencil value with the reference value. */
+		SOP_INCREMENT, /**< Increase the stencil value by 1, clamping at the maximum value. */
+		SOP_DECREMENT, /**< Decrease the stencil value by 1, clamping at 0. */
+		SOP_INCREMENT_WRAP, /**< Increase the stencil value by 1, wrapping back to 0 when incrementing past the maximum value. */
+		SOP_DECREMENT_WRAP, /**< Decrease the stencil value by 1, wrapping when decrementing 0. */
+		SOP_INVERT /**< Invert the bits of the stencil buffer. */
 	};
 
-	/// Locking options
+	/**
+	* @brief	These values represent a hint to the driver when locking a hardware buffer.
+	*
+	*			GBL_WRITE_ONLY - Allows you to write to the buffer. Can cause a CPU-GPU sync point
+	*			so avoid using it often (i.e. every frame) as that might limit your performance significantly.
+	*			GBL_WRITE_ONLY_DISCARD - Allows you to write to the buffer. Tells the driver to completely discard the contents of the 
+	*			buffer you are writing to. The driver will (most likely) internally allocate another buffer with same specifications 
+	*			(which is fairly fast) and you will avoid CPU-GPU stalls.
+	*			GBL_WRITE_ONLY_NO_OVERWRITE - Allows you to write to the buffer. Guarantees the driver that you will not be updating any part of 
+	*			the buffer that is currently used. This will also avoid CPU-GPU stalls, without requiring you to discard the entire buffer. However 
+	*			it is hard to guarantee when GPU has finished using a buffer.
+	*			GBL_READ_ONLY - Allows you to read from a buffer. Be aware that reading is usually a very slow operation.
+	*			GBL_READ_WRITE - Allows you to both read and write to a buffer. 
+	*/
 	enum GpuLockOptions
 	{
-        /** Normal mode, ie allows read/write and contents are preserved. */
         GBL_READ_WRITE,
-		/** Discards the <em>entire</em> buffer while locking; this allows optimisation to be 
-		performed because synchronisation issues are relaxed. 
-		*/
 		GBL_WRITE_ONLY_DISCARD,
-		/** Lock the buffer for reading only. Not allowed in buffers which are created with HBU_WRITE_ONLY. 
-		*/ 
 		GBL_READ_ONLY,
-        /** As HBL_NORMAL, except the application guarantees not to overwrite any 
-        region of the buffer which has already been used in this frame, can allow
-        some optimisation on some APIs. */
         GBL_WRITE_ONLY_NO_OVERWRITE,
-		/** Lock for writing only */
 		GBL_WRITE_ONLY	
 	};
 
-	/// Enums describing buffer usage; not mutually exclusive
+	/**
+	 * @brief	Values that represent hardware buffer usage. These usually determine in what
+	 *			type of memory is buffer placed in, however that depends on rendering API.
+	 * 
+	 *			GBU_STATIC - Signifies that you don't plan on modifying the buffer often (or at all)
+	 *			after creation. Modifying such buffer will involve a larger performance hit.
+	 *			GBU_DYNAMIC - Signifies that you will modify this buffer fairly often.
+	 */
 	enum GpuBufferUsage 
 	{
-        /** Static buffer which the application rarely modifies once created. Modifying 
-        the contents of this buffer will involve a performance hit.
-        */
         GBU_STATIC = 1,
-		/** Indicates the application would like to modify this buffer with the CPU
-		fairly often. 
-		*/
 		GBU_DYNAMIC = 2
 	};
 
 	/**
 	 * @brief	Types of generic GPU buffers that may be attached to GPU programs.
+	 *
+	 *			GBT_STRUCTURED - Buffer containing an array of structures. Structure parameters
+	 *			can usually be easily accessed from within the GPU program.
+	 *			GBT_RAW - Buffer containing raw bytes. It is up to the user to interpret the data.
+	 *			GBT_INDIRECTARGUMENT - Special type of buffer allowing you to specify arguments for
+	 *			draw operations inside the buffer instead of providing them directly. Useful when you want
+	 *			to control drawing directly from GPU.
+	 *			GBT_APPENDCONSUME - A stack-like buffer that allows you to add or remove elements to/from the buffer
+	 *			from within the GPU program.
 	 */
 	enum GpuBufferType
 	{
@@ -245,7 +197,12 @@ namespace BansheeEngine {
 	};
 
 	/**
-	 * @brief	Different types of gpu views
+	 * @brief	Different types of GPU views that control how GPU sees a hardware buffer.
+	 *
+	 *			GVU_DEFAULT - Buffer is seen as a default shader resource, used primarily for reading. (e.g. a texture for sampling)
+	 *			GVU_RENDERTARGET - Buffer is seen as a render target that color pixels will be written to after pixel shader stage.
+	 *			GVU_DEPTHSTENCIL - Buffer is seen as a depth stencil target that depth and stencil information is written to.
+	 *			GVU_RANDOMWRITE - Buffer that allows you to write to any part of it from within a GPU program.
 	 */
 	enum GpuViewUsage
 	{
@@ -255,18 +212,33 @@ namespace BansheeEngine {
 		GVU_RANDOMWRITE = 0x08
 	};
 
+	/**
+	 * @brief	Type of parameter block usages. Signifies how often will parameter blocks be changed.
+	 *
+	 *			GPBU_STATIC - Buffer will be rarely, if ever, updated.
+	 *			GPBU_DYNAMIC - Buffer will be updated often (e.g. every frame).
+	 */
 	enum GpuParamBlockUsage
 	{
 		GPBU_STATIC,
 		GPBU_DYNAMIC
 	};
 
+	/**
+	 * @brief	Type of GPU parameter.
+	 *
+	 *			GPT_DATA - Raw data type like float, Vector3, Color, etc.
+	 *			GPT_OBJECT - Reference to some GPU object like Texture, Sampler, etc.
+	 */
 	enum GpuParamType
 	{
 		GPT_DATA,
 		GPT_OBJECT
 	};
 
+	/**
+	 * @brief	Type of GPU data parameters that can be used as inputs to a GPU program.
+	 */
 	enum GpuParamDataType
 	{
 		GPDT_FLOAT1 = 1,
@@ -291,6 +263,9 @@ namespace BansheeEngine {
 		GPDT_UNKNOWN = 0xffff
 	};
 
+	/**
+	 * @brief	Type of GPU object parameters that can be used as inputs to a GPU program.
+	 */
 	enum GpuParamObjectType
 	{
 		GPOT_SAMPLER1D = 1,
@@ -335,7 +310,9 @@ namespace BansheeEngine {
 		NoOverwrite
 	};
 
-	/** Texture addressing mode for each texture coordinate. */
+	/**
+	 * @brief	Texture addressing mode, per component.
+	 */
 	struct UVWAddressingMode
 	{
 		UVWAddressingMode()
@@ -345,10 +322,5 @@ namespace BansheeEngine {
 		TextureAddressingMode u, v, w;
 	};
     
-	/// Name / value parameter pair (first = name, second = value)
 	typedef Map<String, String> NameValuePairList;
-
-	/** @} */
-}
-
-#endif
+}

+ 161 - 194
CamelotCore/Include/CmHardwareBuffer.h

@@ -1,207 +1,174 @@
-/*
------------------------------------------------------------------------------
-This source file is part of OGRE
-    (Object-oriented Graphics Rendering Engine)
-For the latest info, see http://www.ogre3d.org/
-
-Copyright (c) 2000-2011 Torus Knot Software Ltd
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
------------------------------------------------------------------------------
-*/
-#ifndef __HardwareBuffer__
-#define __HardwareBuffer__
-
-// Precompiler options
+#pragma once
+
 #include "CmPrerequisites.h"
 #include "CmCommonEnums.h"
 
 namespace BansheeEngine 
 {
-	/** \addtogroup Core
-	*  @{
-	*/
-	/** \addtogroup RenderSystem
-	*  @{
-	*/
-	/** Abstract class defining common features of hardware buffers.
-    @remarks
- 	    A 'hardware buffer' is any area of memory held outside of core system ram,
-	    and in our case refers mostly to video ram, although in theory this class
-	    could be used with other memory areas such as sound card memory, custom
-	    coprocessor memory etc.
-    @par
- 	    This reflects the fact that memory held outside of main system RAM must 
-	    be interacted with in a more formal fashion in order to promote
-	    cooperative and optimal usage of the buffers between the various 
-	    processing units which manipulate them.
-    @par
- 	    This abstract class defines the core interface which is common to all
-	    buffers, whether it be vertex buffers, index buffers, texture memory
-	    or framebuffer memory etc.
-	@par
-		Buffers have the ability to be 'shadowed' in system memory, this is because
-		the kinds of access allowed on hardware buffers is not always as flexible as
-		that allowed for areas of system memory - for example it is often either 
-		impossible, or extremely undesirable from a performance standpoint to read from
-		a hardware buffer; when writing to hardware buffers, you should also write every
-		byte and do it sequentially. In situations where this is too restrictive, 
-		it is possible to create a hardware, write-only buffer (the most efficient kind) 
-		and to back it with a system memory 'shadow' copy which can be read and updated arbitrarily.
-		Ogre handles synchronising this buffer with the real hardware buffer (which should still be
-		created with the HBU_DYNAMIC flag if you intend to update it very frequently). Whilst this
-		approach does have it's own costs, such as increased memory overhead, these costs can 
-		often be outweighed by the performance benefits of using a more hardware efficient buffer.
-		You should look for the 'useShadowBuffer' parameter on the creation methods used to create
-		the buffer of the type you require (see HardwareBufferManager) to enable this feature.
-    */
+	/**
+	 * @brief	Abstract class defining common features of hardware buffers. Hardware buffers usually
+	 *			represent areas of memory the GPU or the driver can access directly.
+	 *
+	 * @note	Be aware that reading from non-system memory hardware buffers is usually slow and should be avoided.
+	 */
 	class CM_EXPORT HardwareBuffer
     {
-	    protected:
-		    UINT32 mSizeInBytes;
-		    GpuBufferUsage mUsage;
-		    bool mIsLocked;
-			UINT32 mLockStart;
-			UINT32 mLockSize;
-			bool mSystemMemory;
-    		
-            /// Internal implementation of lock()
-		    virtual void* lockImpl(UINT32 offset, UINT32 length, GpuLockOptions options) = 0;
-            /// Internal implementation of unlock()
-		    virtual void unlockImpl(void) = 0;
-
     public:
-		    /// Constructor, to be called by HardwareBufferManager only
-            HardwareBuffer(GpuBufferUsage usage, bool systemMemory) 
-				: mUsage(usage), mIsLocked(false), mSystemMemory(systemMemory)
-            {  }
-            virtual ~HardwareBuffer() {}
-		    /** Lock the buffer for (potentially) reading / writing.
-		    @param offset The byte offset from the start of the buffer to lock
-		    @param length The size of the area to lock, in bytes
-		    @param options Locking options
-		    @returns Pointer to the locked memory
-		    */
-		    virtual void* lock(UINT32 offset, UINT32 length, GpuLockOptions options)
-            {
-                assert(!isLocked() && "Cannot lock this buffer, it is already locked!");
-                void* ret = lockImpl(offset, length, options);
-                mIsLocked = true;
-
-				mLockStart = offset;
-				mLockSize = length;
-                return ret;
-            }
-
-            /** Lock the entire buffer for (potentially) reading / writing.
-		    @param options Locking options
-		    @returns Pointer to the locked memory
-            */
-            void* lock(GpuLockOptions options)
-            {
-                return this->lock(0, mSizeInBytes, options);
-            }
-		    /** Releases the lock on this buffer. 
-            @remarks 
-                Locking and unlocking a buffer can, in some rare circumstances such as 
-                switching video modes whilst the buffer is locked, corrupt the 
-                contents of a buffer. This is pretty rare, but if it occurs, 
-                this method will throw an exception, meaning you
-                must re-upload the data.
-            @par
-                Note that using the 'read' and 'write' forms of updating the buffer does not
-                suffer from this problem, so if you want to be 100% sure your
-                data will not be lost, use the 'read' and 'write' forms instead.
-            */
-		    virtual void unlock(void)
-            {
-                assert(isLocked() && "Cannot unlock this buffer, it is not locked!");
-
-                unlockImpl();
-                mIsLocked = false;
-            }
-
-            /** Reads data from the buffer and places it in the memory pointed to by pDest.
-		    @param offset The byte offset from the start of the buffer to read
-		    @param length The size of the area to read, in bytes
-            @param pDest The area of memory in which to place the data, must be large enough to 
-                accommodate the data!
-            */
-            virtual void readData(UINT32 offset, UINT32 length, void* pDest) = 0;
-            /** Writes data to the buffer from an area of system memory; note that you must
-                ensure that your buffer is big enough.
-		    @param offset The byte offset from the start of the buffer to start writing
-		    @param length The size of the data to write to, in bytes
-            @param pSource The source of the data to be written
-			@param discardWholeBuffer If true, this allows the driver to discard the entire buffer when writing,
-				such that stalls can be avoided. Always use when you can.
-			@param noOverwrite If true, you are guaranteeing to the driver that you will not write to any area of the
-				buffer the GPU is currently using. This will avoid stalls. Be aware that guaranteeing that
-				something isn't used on the GPU is problematic.
-            */
-            virtual void writeData(UINT32 offset, UINT32 length, const void* pSource,
-					BufferWriteType writeFlags = BufferWriteType::Normal) = 0;
-
-			/** Copy data from another buffer into this one.
-			@remarks
-				Note that the source buffer must not be created with the
-                usage HBU_WRITE_ONLY otherwise this will fail. 
-			@param srcBuffer The buffer from which to read the copied data
-			@param srcOffset Offset in the source buffer at which to start reading
-			@param dstOffset Offset in the destination buffer to start writing
-			@param length Length of the data to copy, in bytes.
-			@param discardWholeBuffer If true, will discard the entire contents of this buffer before copying
-			*/
-			virtual void copyData(HardwareBuffer& srcBuffer, UINT32 srcOffset, 
-				UINT32 dstOffset, UINT32 length, bool discardWholeBuffer = false)
-			{
-				const void *srcData = srcBuffer.lock(
-					srcOffset, length, GBL_READ_ONLY);
-				this->writeData(dstOffset, length, srcData, discardWholeBuffer ? BufferWriteType::Discard : BufferWriteType::Normal);
-				srcBuffer.unlock();
-			}
-
-			/** Copy all data from another buffer into this one. 
-			@remarks
-				Normally these buffers should be of identical size, but if they're
-				not, the routine will use the smallest of the two sizes.
-			*/
-			virtual void copyData(HardwareBuffer& srcBuffer)
-			{
-				UINT32 sz = std::min(getSizeInBytes(), srcBuffer.getSizeInBytes()); 
-				copyData(srcBuffer, 0, 0, sz, true);
-			}
+        virtual ~HardwareBuffer() {}
+
+		/**
+		 * @brief	Locks a portion of the buffer and returns pointer to the locked area.
+		 *			You must call "unlock" when done.
+		 *
+		 * @param	offset	Offset in bytes from which to lock the buffer.
+		 * @param	length	Length of the area you want to lock, in bytes.
+		 * @param	options	Signifies what you want to do with the returned pointer.
+		 *					Caller must ensure not to do anything he hasn't requested.
+		 *					(e.g. don't try to read from the buffer unless you requested
+		 *					it here).
+		 */
+		virtual void* lock(UINT32 offset, UINT32 length, GpuLockOptions options)
+        {
+            assert(!isLocked() && "Cannot lock this buffer, it is already locked!");
+            void* ret = lockImpl(offset, length, options);
+            mIsLocked = true;
+
+			mLockStart = offset;
+			mLockSize = length;
+            return ret;
+        }
+
+		/**
+		 * @brief	Locks the entire buffer and returns pointer to the locked area.
+		 *			You must call "unlock" when done.
+		 *
+		 * @param	options	Signifies what you want to do with the returned pointer.
+		 *					Caller must ensure not to do anything he hasn't requested.
+		 *					(e.g. don't try to read from the buffer unless you requested
+		 *					it here).
+		 */
+        void* lock(GpuLockOptions options)
+        {
+            return this->lock(0, mSizeInBytes, options);
+        }
+
+		/**
+		 * @brief	Releases the lock on this buffer. 
+		 */
+		virtual void unlock()
+        {
+            assert(isLocked() && "Cannot unlock this buffer, it is not locked!");
+
+            unlockImpl();
+            mIsLocked = false;
+        }
+
+		/**
+		 * @brief	Reads data from a portion of the buffer and copies it to the destination
+		 *			buffer. Caller must ensure destination buffer is large enough.
+		 *
+		 * @param	offset	Offset in bytes from which to copy the data.
+		 * @param	length	Length of the area you want to copy, in bytes.
+		 * @param	dest	Destination buffer large enough to store the read data.
+		 */
+        virtual void readData(UINT32 offset, UINT32 length, void* dest) = 0;
+
+		/**
+		 * @brief	Writes data into a portion of the buffer from the source memory. 
+		 *
+		 * @param	offset		Offset in bytes from which to copy the data.
+		 * @param	length		Length of the area you want to copy, in bytes.
+		 * @param	source		Source buffer containing the data to write.
+		 * @param	writeFlags	Optional write flags that may affect performance.
+		 */
+        virtual void writeData(UINT32 offset, UINT32 length, const void* source,
+				BufferWriteType writeFlags = BufferWriteType::Normal) = 0;
+
+		/**
+		 * @brief	Copies data from a specific portion of the source buffer into a specific portion
+		 *			of this buffer.
+		 *
+		 * @param	srcBuffer			Buffer to copy from.
+		 * @param	srcOffset			Offset into the source buffer to start copying from, in bytes.
+		 * @param	dstOffset			Offset into this buffer to start copying to, in bytes.
+		 * @param	length				Size of the data to copy, in bytes.
+		 * @param	discardWholeBuffer	Specify true if the data in the current buffer can be entirely discarded. This
+		 *								may improve performance.
+		 */
+		virtual void copyData(HardwareBuffer& srcBuffer, UINT32 srcOffset, 
+			UINT32 dstOffset, UINT32 length, bool discardWholeBuffer = false)
+		{
+			const void *srcData = srcBuffer.lock(
+				srcOffset, length, GBL_READ_ONLY);
+			this->writeData(dstOffset, length, srcData, discardWholeBuffer ? BufferWriteType::Discard : BufferWriteType::Normal);
+			srcBuffer.unlock();
+		}
+
+		/**
+		 * @brief	Copy data from the provided buffer into this buffer. If buffers
+		 *			are not the same size, smaller size will be used.
+		 */
+		virtual void copyData(HardwareBuffer& srcBuffer)
+		{
+			UINT32 sz = std::min(getSizeInBytes(), srcBuffer.getSizeInBytes()); 
+			copyData(srcBuffer, 0, 0, sz, true);
+		}
 			
-            /// Returns the size of this buffer in bytes
-            UINT32 getSizeInBytes(void) const { return mSizeInBytes; }
-            /// Returns the Usage flags with which this buffer was created
-            GpuBufferUsage getUsage(void) const { return mUsage; }
-			/// Returns whether this buffer is held in system memory
-			bool isSystemMemory(void) const { return mSystemMemory; }
-            /// Returns whether or not this buffer is currently locked.
-            bool isLocked(void) const { 
-                return mIsLocked; 
-            }	
+		/**
+		 * @brief	Returns the size of this buffer in bytes.
+		 */
+        UINT32 getSizeInBytes(void) const { return mSizeInBytes; }
+
+		/**
+		 * @brief	Returns the Usage flags with which this buffer was created.
+		 */
+        GpuBufferUsage getUsage() const { return mUsage; }
+
+		/**
+		 * @brief	Returns whether this buffer is held in system memory.
+		 */
+		bool isSystemMemory() const { return mSystemMemory; }
+
+		/**
+		 * @brief	Returns whether or not this buffer is currently locked.
+		 */
+        bool isLocked() const { return mIsLocked; }	
+
+	protected:
+		friend class HardwareBufferManager;
+
+		/**
+		 * @brief	Constructs a new buffer.
+		 *
+		 * @param	usage			Determines most common usage of the buffer. Usually has effect on what
+		 *							type of memory will be buffer allocated in but that depends on render API.
+		 *							Specify dynamic if you plan on modifying it often, static otherwise.
+		 * @param	systemMemory	If enabled the the buffer will be kept in the system memory. System memory
+		 *							buffers are often used as a source or destination for copies from/to other
+		 *							buffers. Some APIs don't allow reading from non-system memory buffers.
+		 */
+		HardwareBuffer(GpuBufferUsage usage, bool systemMemory)
+			: mUsage(usage), mIsLocked(false), mSystemMemory(systemMemory)
+		{  }
+
+		/**
+		 * @copydoc	lock
+		 */
+		virtual void* lockImpl(UINT32 offset, UINT32 length, GpuLockOptions options) = 0;
+
+		/**
+		 * @copydoc	unlock
+		 */
+		virtual void unlockImpl() = 0;
+
+	protected:
+		UINT32 mSizeInBytes;
+		GpuBufferUsage mUsage;
+		bool mIsLocked;
+		UINT32 mLockStart;
+		UINT32 mLockSize;
+		bool mSystemMemory;
     };
-	/** @} */
-	/** @} */
 }
-#endif
 
 

+ 19 - 51
CamelotCore/Include/CmVertexBuffer.h

@@ -1,34 +1,5 @@
-/*
------------------------------------------------------------------------------
-This source file is part of OGRE
-    (Object-oriented Graphics Rendering Engine)
-For the latest info, see http://www.ogre3d.org/
+#pragma once
 
-Copyright (c) 2000-2011 Torus Knot Software Ltd
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
------------------------------------------------------------------------------
-*/
-#ifndef __HardwareVertexBuffer__
-#define __HardwareVertexBuffer__
-
-// Precompiler options
 #include "CmPrerequisites.h"
 #include "CmHardwareBuffer.h"
 #include "CmCoreObject.h"
@@ -36,39 +7,36 @@ THE SOFTWARE.
 
 namespace BansheeEngine 
 {
-	/** \addtogroup Core
-	*  @{
-	*/
-	/** \addtogroup RenderSystem
-	*  @{
-	*/
-	/** Specialisation of HardwareBuffer for a vertex buffer. */
+	/**
+	 * @brief	Specialization of a hardware buffer used for holding vertex data.
+	 */
     class CM_EXPORT VertexBuffer : public HardwareBuffer, public CoreObject
     {
 	public:
-        ~VertexBuffer();
+		virtual ~VertexBuffer() { }
 
-		/// Return the manager of this buffer, if any
-		HardwareBufferManager* getManager() const { return mMgr; }
-        /// Gets the size in bytes of a single vertex in this buffer
-        UINT32 getVertexSize(void) const { return mVertexSize; }
-        /// Get the number of vertices in this buffer
-        UINT32 getNumVertices(void) const { return mNumVertices; }
+		/**
+		 * @brief	Gets the size in bytes of a single vertex in this buffer.
+		 */
+        UINT32 getVertexSize() const { return mVertexSize; }
+
+		/**
+		 * @brief	Get the number of vertices in this buffer.
+		 */
+        UINT32 getNumVertices() const { return mNumVertices; }
 
 		/**
 		 * @brief	Some render systems expect vertex color bits in an order different than
-		 * 			RGBA, in which case override this to flip the RGB order.
+		 * 			RGBA, in which case override this to flip the RGBA order.
 		 */
 		virtual bool vertexColorReqRGBFlip() { return false; }
 
 		static const int MAX_SEMANTIC_IDX = 8;
 	protected:
-		HardwareBufferManager* mMgr;
+		VertexBuffer(UINT32 vertexSize, UINT32 numVertices, GpuBufferUsage usage, bool useSystemMemory);
+
+	protected:
 		UINT32 mNumVertices;
 		UINT32 mVertexSize;
-
-		VertexBuffer(HardwareBufferManager* mgr, UINT32 vertexSize, UINT32 numVertices, GpuBufferUsage usage, bool useSystemMemory);
     };
-}
-#endif
-
+}

+ 2 - 40
CamelotCore/Source/CmVertexBuffer.cpp

@@ -1,31 +1,3 @@
-/*
------------------------------------------------------------------------------
-This source file is part of OGRE
-    (Object-oriented Graphics Rendering Engine)
-For the latest info, see http://www.ogre3d.org/
-
-Copyright (c) 2000-2011 Torus Knot Software Ltd
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
------------------------------------------------------------------------------
-*/
-
 #include "CmVertexBuffer.h"
 #include "CmColor.h"
 #include "CmException.h"
@@ -35,19 +7,9 @@ THE SOFTWARE.
 
 namespace BansheeEngine 
 {
-    VertexBuffer::VertexBuffer(HardwareBufferManager* mgr, UINT32 vertexSize,  
-        UINT32 numVertices, GpuBufferUsage usage, 
-        bool useSystemMemory) 
-        : HardwareBuffer(usage, useSystemMemory), 
-		  mMgr(mgr),
-          mNumVertices(numVertices),
-          mVertexSize(vertexSize)
+    VertexBuffer::VertexBuffer(UINT32 vertexSize,  UINT32 numVertices, GpuBufferUsage usage, bool useSystemMemory) 
+        : HardwareBuffer(usage, useSystemMemory), mNumVertices(numVertices), mVertexSize(vertexSize)
     {
         mSizeInBytes = mVertexSize * numVertices;
     }
-
-    VertexBuffer::~VertexBuffer()
-    {
-
-    }
 }

+ 1 - 1
CamelotD3D11RenderSystem/Include/CmD3D11VertexBuffer.h

@@ -34,7 +34,7 @@ namespace BansheeEngine
 	protected: 
 		friend class D3D11HardwareBufferManager;
 
-		D3D11VertexBuffer(D3D11Device& device, HardwareBufferManager* mgr, UINT32 vertexSize, UINT32 numVertices, 
+		D3D11VertexBuffer(D3D11Device& device, UINT32 vertexSize, UINT32 numVertices, 
 			GpuBufferUsage usage, bool useSystemMem, bool streamOut);
 
 		/**

+ 1 - 1
CamelotD3D11RenderSystem/Source/CmD3D11HardwareBufferManager.cpp

@@ -19,7 +19,7 @@ namespace BansheeEngine
 	VertexBufferPtr D3D11HardwareBufferManager::createVertexBufferImpl(UINT32 vertexSize, 
 		UINT32 numVerts, GpuBufferUsage usage, bool streamOut)
 	{
-		D3D11VertexBuffer* buffer = new (cm_alloc<D3D11VertexBuffer, PoolAlloc>()) D3D11VertexBuffer(mDevice, this, vertexSize, numVerts, usage, false, streamOut);
+		D3D11VertexBuffer* buffer = new (cm_alloc<D3D11VertexBuffer, PoolAlloc>()) D3D11VertexBuffer(mDevice, vertexSize, numVerts, usage, false, streamOut);
 
 		return cm_core_ptr<D3D11VertexBuffer, PoolAlloc>(buffer);
 	}

+ 2 - 2
CamelotD3D11RenderSystem/Source/CmD3D11VertexBuffer.cpp

@@ -3,9 +3,9 @@
 
 namespace BansheeEngine
 {
-	D3D11VertexBuffer::D3D11VertexBuffer(D3D11Device& device, HardwareBufferManager* mgr, UINT32 vertexSize, UINT32 numVertices, 
+	D3D11VertexBuffer::D3D11VertexBuffer(D3D11Device& device, UINT32 vertexSize, UINT32 numVertices, 
 		GpuBufferUsage usage, bool useSystemMem, bool streamOut)
-		:VertexBuffer(mgr, vertexSize, numVertices, usage, useSystemMem), mDevice(device), mStreamOut(streamOut)
+		:VertexBuffer(vertexSize, numVertices, usage, useSystemMem), mDevice(device), mStreamOut(streamOut)
 	{ }
 
 	D3D11VertexBuffer::~D3D11VertexBuffer()

+ 1 - 1
CamelotD3D9Renderer/Include/CmD3D9VertexBuffer.h

@@ -77,7 +77,7 @@ namespace BansheeEngine {
 
 		friend class D3D9HardwareBufferManager;
 
-		D3D9VertexBuffer(HardwareBufferManager* mgr, UINT32 vertexSize, 
+		D3D9VertexBuffer(UINT32 vertexSize, 
 			UINT32 numVertices, GpuBufferUsage usage, bool useSystemMem);
 	
 		/** See HardwareBuffer. */

+ 1 - 1
CamelotD3D9Renderer/Source/CmD3D9HardwareBufferManager.cpp

@@ -20,7 +20,7 @@ namespace BansheeEngine
     {
 		assert (numVerts > 0);
 
-        D3D9VertexBuffer* buffer = new (cm_alloc<D3D9VertexBuffer, PoolAlloc>()) D3D9VertexBuffer(this, vertexSize, numVerts, usage, false);
+        D3D9VertexBuffer* buffer = new (cm_alloc<D3D9VertexBuffer, PoolAlloc>()) D3D9VertexBuffer(vertexSize, numVerts, usage, false);
 		return cm_core_ptr<D3D9VertexBuffer, PoolAlloc>(buffer);
     }
 

+ 2 - 2
CamelotD3D9Renderer/Source/CmD3D9VertexBuffer.cpp

@@ -36,10 +36,10 @@ THE SOFTWARE.
 namespace BansheeEngine {
 
 	//---------------------------------------------------------------------
-    D3D9VertexBuffer::D3D9VertexBuffer(HardwareBufferManager* mgr, UINT32 vertexSize, 
+    D3D9VertexBuffer::D3D9VertexBuffer(UINT32 vertexSize, 
         UINT32 numVertices, GpuBufferUsage usage, 
         bool useSystemMemory)
-		: VertexBuffer(mgr, vertexSize, numVertices, usage, useSystemMemory)
+		: VertexBuffer(vertexSize, numVertices, usage, useSystemMemory)
     {    }
 	//---------------------------------------------------------------------
     D3D9VertexBuffer::~D3D9VertexBuffer()

+ 2 - 0
CamelotGLRenderer/CamelotGLRenderer.vcxproj

@@ -234,6 +234,7 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClInclude Include="Include\BsGLVertexArrayObjectManager.h" />
     <ClInclude Include="Include\CmGLContext.h" />
     <ClInclude Include="Include\CmGLEventQuery.h" />
     <ClInclude Include="Include\CmGLFrameBufferObject.h" />
@@ -270,6 +271,7 @@
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="CmGLPlugin.cpp" />
+    <ClCompile Include="Source\BsGLVertexArrayObjectManager.cpp" />
     <ClCompile Include="Source\CmGLContext.cpp" />
     <ClCompile Include="Source\CmGLEventQuery.cpp" />
     <ClCompile Include="Source\CmGLFrameBufferObject.cpp" />

+ 6 - 0
CamelotGLRenderer/CamelotGLRenderer.vcxproj.filters

@@ -129,6 +129,9 @@
     <ClInclude Include="Include\CmWin32Window.h">
       <Filter>Header Files\Win32</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsGLVertexArrayObjectManager.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\CmGLContext.cpp">
@@ -221,5 +224,8 @@
     <ClCompile Include="Source\CmWin32Window.cpp">
       <Filter>Source Files\Win32</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsGLVertexArrayObjectManager.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 75 - 0
CamelotGLRenderer/Include/BsGLVertexArrayObjectManager.h

@@ -0,0 +1,75 @@
+#pragma once
+
+#include "CmGLPrerequisites.h"
+#include "CmModule.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Vertex array object that contains vertex buffer object bindings and vertex
+	 *			attribute pointers for a specific set of vertex buffers and a vertex declaration.
+	 */
+	class CM_RSGL_EXPORT GLVertexArrayObject
+	{
+	private:
+		class Hash
+		{
+		public:
+			::std::size_t operator()(const GLVertexArrayObject &vao) const;
+		};
+
+		class Equal
+		{
+		public:
+			bool operator()(const GLVertexArrayObject &a, const GLVertexArrayObject &b) const;
+		};
+
+	public:
+		bool operator== (const GLVertexArrayObject& obj);
+		bool operator!= (const GLVertexArrayObject& obj);
+
+		/**
+		 * @brief	Returns internal OpenGL VBO handle.
+		 */
+		GLuint getGLHandle() const { return mHandle;  }
+
+	private:
+		friend class GLVertexArrayObjectManager;
+
+		GLVertexArrayObject();
+		GLVertexArrayObject(GLuint handle, UINT64 vertexProgramId, GLVertexBuffer** attachedBuffers, UINT32 numBuffers);
+
+		GLuint mHandle;
+		UINT64 mVertProgId;
+		GLVertexBuffer** mAttachedBuffers;
+		UINT32 mNumBuffers;
+	};
+
+	/**
+	 * @brief	Manager that handles creation and destruction of vertex array objects.
+	 */
+	class CM_RSGL_EXPORT GLVertexArrayObjectManager : public Module<GLVertexArrayObjectManager>
+	{
+	public:
+		~GLVertexArrayObjectManager();
+
+		/**
+		 * @brief	Attempts to find an existing vertex array object matching the provided set of vertex buffers,
+		 *			vertex declaration, and vertex shader input parameters. If one cannot be found new one is created
+		 *			and returned.
+		 *
+		 *			Lifetime of returned VAO is managed by the vertex buffers that it binds.
+		 */
+		const GLVertexArrayObject& getVAO(const GLSLGpuProgramPtr& vertexProgram, 
+			const VertexDeclarationPtr& vertexDecl, const Vector<VertexBufferPtr>& boundBuffers);
+
+		/**
+		 * @brief	Called when a vertex buffer containing the provided VAO is destroyed.
+		 */
+		void notifyBufferDestroyed(const GLVertexArrayObject& vao);
+	private:
+		typedef UnorderedSet<GLVertexArrayObject, GLVertexArrayObject::Hash, GLVertexArrayObject::Equal> VAOMap;
+
+		VAOMap mVAObjects;
+	};
+}

+ 2 - 0
CamelotGLRenderer/Include/CmGLPrerequisites.h

@@ -38,6 +38,7 @@ namespace BansheeEngine
     class GLSupport;
     class GLRenderSystem;
     class GLTexture;
+	class GLVertexBuffer;
     class GLTextureManager;
     class GLSLGpuProgram;
     class GLContext;
@@ -45,6 +46,7 @@ namespace BansheeEngine
     class GLPixelBuffer;
 	class GLGpuParamBlock;
 	class GLSLGpuProgram;
+	class GLVertexArrayObject;
 	struct GLSLProgramPipeline;
 	class GLSLProgramPipelineManager;
 

+ 1 - 2
CamelotGLRenderer/Include/CmGLRenderSystem.h

@@ -546,7 +546,7 @@ namespace BansheeEngine
 		UINT32 mDomainUBOffset;
 		UINT32 mComputeUBOffset;
 
-		UnorderedMap<UINT32, VertexBufferPtr> mBoundVertexBuffers;
+		Vector<VertexBufferPtr> mBoundVertexBuffers;
 		VertexDeclarationPtr mBoundVertexDeclaration;
 		IndexBufferPtr mBoundIndexBuffer;
 		DrawOperationType mCurrentDrawOperation;
@@ -554,7 +554,6 @@ namespace BansheeEngine
 		GLContext *mMainContext;
 		GLContext *mCurrentContext;
 
-		Vector<GLuint> mBoundAttributes; // Only full between begin/endDraw calls
 		bool mDrawCallInProgress;
 
 		UINT16 mActiveTextureUnit;

+ 48 - 47
CamelotGLRenderer/Include/CmGLVertexBuffer.h

@@ -1,71 +1,72 @@
-/*
------------------------------------------------------------------------------
-This source file is part of OGRE
-    (Object-oriented Graphics Rendering Engine)
-For the latest info, see http://www.ogre3d.org/
-
-Copyright (c) 2000-2011 Torus Knot Software Ltd
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
------------------------------------------------------------------------------
-*/
 #pragma once
 
 #include "CmGLPrerequisites.h"
 #include "CmVertexBuffer.h"
+#include "BsGLVertexArrayObjectManager.h"
 
-namespace BansheeEngine {
-
-    /// Specialisation of HardwareVertexBuffer for OpenGL
+namespace BansheeEngine 
+{
+	/**
+	 * @copydoc	VertexBuffer
+	 */
     class CM_RSGL_EXPORT GLVertexBuffer : public VertexBuffer 
     {
     public:
         ~GLVertexBuffer();
-        /** See HardwareBuffer. */
+
+		/**
+		 * @copydoc	HardwareBuffer::readData
+		 */
         void readData(UINT32 offset, UINT32 length, void* pDest);
-        /** See HardwareBuffer. */
-        void writeData(UINT32 offset, UINT32 length, 
-            const void* pSource, BufferWriteType writeFlags = BufferWriteType::Normal);
 
-        GLuint getGLBufferId(void) const { return mBufferId; }
+		/**
+		* @copydoc	HardwareBuffer::writeData
+		*/
+        void writeData(UINT32 offset, UINT32 length, const void* pSource, BufferWriteType writeFlags = BufferWriteType::Normal);
+
+		/**
+		 * @brief	Returns internal OpenGL buffer ID.
+		 */
+        GLuint getGLBufferId() const { return mBufferId; }
+
+		/**
+		 * @brief	Registers a new VertexArrayObject that uses this vertex buffer.
+		 */
+		void registerVAO(const GLVertexArrayObject& vao);
+
+		/**
+		 * @brief	Unregisters a VAO from this vertex buffer. Does not destroy it.
+		 */
+		void unregisterVAO(const GLVertexArrayObject& vao);
 
 	protected:
 		friend class GLHardwareBufferManager;
 
-		GLVertexBuffer(HardwareBufferManager* mgr, UINT32 vertexSize, UINT32 numVertices, GpuBufferUsage usage); 
-
-		/** See HardwareBuffer. */
-		void* lockImpl(UINT32 offset, UINT32 length, GpuLockOptions options);
-		/** See HardwareBuffer. */
-		void unlockImpl(void);
+		GLVertexBuffer(UINT32 vertexSize, UINT32 numVertices, GpuBufferUsage usage); 
 
 		/**
-		 * @copydoc VertexBuffer::initialize_internal()
-		 */
-		void initialize_internal();	
-		
+		* @copydoc VertexBuffer::initialize_internal()
+		*/
+		void initialize_internal();
+
 		/**
-		 * @copydoc VertexBuffer::destroy_internal()
-		 */
+		* @copydoc VertexBuffer::destroy_internal()
+		*/
 		void destroy_internal();
 
+		/**
+		* @copydoc	HardwareBuffer::lockImpl()
+		*/
+		void* lockImpl(UINT32 offset, UINT32 length, GpuLockOptions options);
+
+		/**
+		* @copydoc	HardwareBuffer::unlockImpl()
+		*/
+		void unlockImpl();
+
 	private:
 		GLuint mBufferId;
+
+		Vector<GLVertexArrayObject> mVAObjects;
     };
 }

+ 196 - 0
CamelotGLRenderer/Source/BsGLVertexArrayObjectManager.cpp

@@ -0,0 +1,196 @@
+#include "BsGLVertexArrayObjectManager.h"
+#include "CmGLVertexBuffer.h"
+#include "CmVertexDeclaration.h"
+#include "CmGLSLGpuProgram.h"
+#include "CmGLHardwareBufferManager.h"
+#include "CmUtil.h"
+
+#define VBO_BUFFER_OFFSET(i) ((char *)NULL + (i))
+
+namespace BansheeEngine
+{
+	GLVertexArrayObject::GLVertexArrayObject()
+		:mHandle(0), mVertProgId(0), mAttachedBuffers(nullptr), mNumBuffers(0)
+	{ }
+
+	GLVertexArrayObject::GLVertexArrayObject(GLuint handle, UINT64 vertexProgramId, 
+		GLVertexBuffer** attachedBuffers, UINT32 numBuffers)
+		:mHandle(handle), mVertProgId(vertexProgramId), mAttachedBuffers(attachedBuffers), mNumBuffers(numBuffers)
+	{ }
+
+	::std::size_t GLVertexArrayObject::Hash::operator()(const GLVertexArrayObject &vao) const
+	{
+		std::size_t seed = 0;
+		hash_combine(seed, vao.mVertProgId);
+
+		for (UINT32 i = 0; i < vao.mNumBuffers; i++)
+			hash_combine(seed, vao.mAttachedBuffers[i]->getInternalID());
+
+		return seed;
+	}
+
+	bool GLVertexArrayObject::Equal::operator()(const GLVertexArrayObject &a, const GLVertexArrayObject &b) const
+	{
+		if (a.mVertProgId != b.mVertProgId)
+			return false;
+
+		if (a.mNumBuffers != b.mNumBuffers)
+			return false;
+
+		for (UINT32 i = 0; i < a.mNumBuffers; i++)
+		{
+			if (a.mAttachedBuffers[i]->getInternalID() != b.mAttachedBuffers[i]->getInternalID())
+				return false;
+		}
+
+		return true;
+	}
+
+	bool GLVertexArrayObject::operator== (const GLVertexArrayObject& obj)
+	{
+		if (mVertProgId != obj.mVertProgId)
+			return false;
+
+		if (mNumBuffers != obj.mNumBuffers)
+			return false;
+
+		for (UINT32 i = 0; i < mNumBuffers; i++)
+		{
+			if (mAttachedBuffers[i]->getInternalID() != obj.mAttachedBuffers[i]->getInternalID())
+				return false;
+		}
+
+		return true;
+	}
+
+	bool GLVertexArrayObject::operator!= (const GLVertexArrayObject& obj)
+	{
+		return !operator==(obj);
+	}
+
+	GLVertexArrayObjectManager::~GLVertexArrayObjectManager()
+	{
+		assert(mVAObjects.size() == 0 && "VertexArrayObjectManager getting shut down but not all VA objects were released.");
+	}
+
+	const GLVertexArrayObject& GLVertexArrayObjectManager::getVAO(const GLSLGpuProgramPtr& vertexProgram,
+		const VertexDeclarationPtr& vertexDecl, const Vector<VertexBufferPtr>& boundBuffers)
+	{
+		UINT32 numUsedBuffers = 0;
+		INT32* streamToSeqIdx = stackAllocN<INT32>((UINT32)boundBuffers.size());
+		GLVertexBuffer** usedBuffers = stackAllocN<GLVertexBuffer*>((UINT32)boundBuffers.size());
+		
+		const VertexDeclaration::VertexElementList& decl = vertexDecl->getElements();
+		for (auto& elem : decl)
+		{
+			UINT16 streamIdx = elem.getStreamIdx();
+			if (streamIdx >= (UINT32)boundBuffers.size())
+			{
+				streamToSeqIdx[streamIdx] = -1;
+				continue;
+			}
+
+			VertexBufferPtr vertexBuffer = boundBuffers[streamIdx];
+
+			if (vertexBuffer == nullptr)
+				continue; // Skip unbound elements
+
+			streamToSeqIdx[streamIdx] = (INT32)numUsedBuffers;
+			usedBuffers[numUsedBuffers++] = static_cast<GLVertexBuffer*>(vertexBuffer.get());
+		}
+		
+		GLVertexArrayObject wantedVAO(0, vertexProgram->getInternalID(), usedBuffers, numUsedBuffers);
+
+		auto findIter = mVAObjects.find(wantedVAO);
+		if (findIter != mVAObjects.end())
+		{
+			stackDeallocLast(usedBuffers);
+			stackDeallocLast(streamToSeqIdx);
+
+			return *findIter; // Found existing, return that
+		}
+
+		// Need to create new VAO
+		const VertexDeclaration::VertexElementList& inputAttributes = vertexProgram->getInputAttributes().getElements();
+
+		glGenVertexArrays(1, &wantedVAO.mHandle);
+		glBindVertexArray(wantedVAO.mHandle);
+
+		for (auto& elem : decl)
+		{
+			UINT16 streamIdx = elem.getStreamIdx();
+			INT32 seqIdx = streamToSeqIdx[streamIdx];
+
+			if (seqIdx == -1)
+				continue;
+
+			bool foundSemantic = false;
+			GLint attribLocation = 0;
+			for (auto iter = inputAttributes.begin(); iter != inputAttributes.end(); ++iter)
+			{
+				if (iter->getSemantic() == elem.getSemantic() && iter->getSemanticIdx() == elem.getSemanticIdx())
+				{
+					foundSemantic = true;
+					attribLocation = iter->getOffset();
+					break;
+				}
+			}
+
+			if (!foundSemantic) // Shader needs to have a matching input attribute, otherwise we skip it
+				continue;
+
+			// TODO - We might also want to check the size of input and buffer, and make sure they match? Or does OpenGL handle that internally?
+
+			GLVertexBuffer* vertexBuffer = usedBuffers[seqIdx];
+			glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer->getGLBufferId());
+			void* bufferData = VBO_BUFFER_OFFSET(elem.getOffset());
+
+			GLboolean normalized = GL_FALSE;
+			switch (elem.getType())
+			{
+			case VET_COLOR:
+			case VET_COLOR_ABGR:
+			case VET_COLOR_ARGB:
+				normalized = GL_TRUE;
+				break;
+			default:
+				break;
+			};
+
+			UINT16 typeCount = VertexElement::getTypeCount(elem.getType());
+			GLenum glType = GLHardwareBufferManager::getGLType(elem.getType());
+			GLsizei vertexSize = static_cast<GLsizei>(vertexBuffer->getVertexSize());
+			glVertexAttribPointer(attribLocation, typeCount, glType, normalized,
+				vertexSize, bufferData);
+
+			glEnableVertexAttribArray(attribLocation);
+		}
+
+		wantedVAO.mAttachedBuffers = (GLVertexBuffer**)cm_alloc<GLVertexBuffer*>(numUsedBuffers);
+		for (UINT32 i = 0; i < numUsedBuffers; i++)
+		{
+			wantedVAO.mAttachedBuffers[i] = usedBuffers[i];
+			wantedVAO.mAttachedBuffers[i]->registerVAO(wantedVAO);
+		}
+
+		stackDeallocLast(usedBuffers);
+		stackDeallocLast(streamToSeqIdx);
+
+		mVAObjects.insert(wantedVAO);
+
+		return wantedVAO;
+	}
+
+	void GLVertexArrayObjectManager::notifyBufferDestroyed(const GLVertexArrayObject& vao)
+	{
+		mVAObjects.erase(vao);
+
+		for (UINT32 i = 0; i < vao.mNumBuffers; i++)
+		{
+			vao.mAttachedBuffers[i]->unregisterVAO(vao);
+		}
+
+		glDeleteVertexArrays(1, &vao.mHandle);
+		cm_free(vao.mAttachedBuffers);
+	}
+}

+ 1 - 1
CamelotGLRenderer/Source/CmGLHardwareBufferManager.cpp

@@ -83,7 +83,7 @@ namespace BansheeEngine {
     VertexBufferPtr GLHardwareBufferManager::createVertexBufferImpl(
         UINT32 vertexSize, UINT32 numVerts, GpuBufferUsage usage, bool streamOut)
     {
-		return cm_core_ptr<GLVertexBuffer, PoolAlloc>(new (cm_alloc<GLVertexBuffer, PoolAlloc>()) GLVertexBuffer(this, vertexSize, numVerts, usage));
+		return cm_core_ptr<GLVertexBuffer, PoolAlloc>(new (cm_alloc<GLVertexBuffer, PoolAlloc>()) GLVertexBuffer(vertexSize, numVerts, usage));
     }
     //-----------------------------------------------------------------------
     IndexBufferPtr 

+ 11 - 81
CamelotGLRenderer/Source/CmGLRenderSystem.cpp

@@ -16,6 +16,7 @@
 #include "CmGLRenderTexture.h"
 #include "CmGLRenderWindowManager.h"
 #include "CmGLSLProgramPipelineManager.h"
+#include "BsGLVertexArrayObjectManager.h"
 #include "CmRenderStateManager.h"
 #include "CmGpuParams.h"
 #include "CmGLGpuParamBlockBuffer.h"
@@ -23,9 +24,6 @@
 #include "CmGLQueryManager.h"
 #include "CmDebug.h"
 
-// Convenience macro from ARB_vertex_buffer_object spec
-#define VBO_BUFFER_OFFSET(i) ((char *)NULL + (i))
-
 namespace BansheeEngine 
 {
 	String MODULE_NAME = "CamelotGLRenderSystem.dll";
@@ -142,8 +140,10 @@ namespace BansheeEngine
 
 		mCurrentCapabilities = createRenderSystemCapabilities();
 		initFromCaps(mCurrentCapabilities);
+		GLVertexArrayObjectManager::startUp(cm_new<GLVertexArrayObjectManager>());
+		
 		mGLInitialised = true;
-
+		
 		RenderSystem::initialize_internal(asyncOp);
 
 		asyncOp._completeOperation(primaryWindow);
@@ -153,6 +153,8 @@ namespace BansheeEngine
 	{
 		RenderSystem::destroy_internal();
 
+		GLVertexArrayObjectManager::shutDown();
+
 		// Deleting the GLSL program factory
 		if (mGLSLProgramFactory)
 		{
@@ -605,6 +607,9 @@ namespace BansheeEngine
 	{
 		THROW_IF_NOT_CORE_THREAD;
 
+		if ((index + numBuffers) > (UINT32)mBoundVertexBuffers.size())
+			mBoundVertexBuffers.resize(index + numBuffers);
+
 		for(UINT32 i = 0; i < numBuffers; i++)
 		{
 			mBoundVertexBuffers[index + i] = buffers[i];
@@ -1304,75 +1309,8 @@ namespace BansheeEngine
 			mActivePipeline = pipeline;
 		}
 
-		void* pBufferData = 0;
-
-		const VertexDeclaration::VertexElementList& decl = mBoundVertexDeclaration->getElements();
-		VertexDeclaration::VertexElementList::const_iterator elem, elemEnd;
-		elemEnd = decl.end();
-
-		const VertexDeclaration::VertexElementList& inputAttributes = mCurrentVertexProgram->getInputAttributes().getElements();
-
-		GLuint VAOID[1];
-		glGenVertexArrays(1, &VAOID[0]);
-		glBindVertexArray(VAOID[0]); // DEBUG ONLY!!! - Store these somewhere and just rebind them when needed
-
-		for (elem = decl.begin(); elem != elemEnd; ++elem)
-		{
-			auto iterFind = mBoundVertexBuffers.find(elem->getStreamIdx());
-
-			if(iterFind == mBoundVertexBuffers.end() || iterFind->second == nullptr)
-				continue; // Skip unbound elements
-
-			VertexBufferPtr vertexBuffer = iterFind->second;
-
-			bool foundSemantic = false; 
-			GLint attribLocation = 0;
-			for(auto iter = inputAttributes.begin(); iter != inputAttributes.end(); ++iter)
-			{
-				if(iter->getSemantic() == elem->getSemantic() && iter->getSemanticIdx() == elem->getSemanticIdx())
-				{
-					foundSemantic = true;
-					attribLocation = iter->getOffset();
-					break;
-				}
-			}
-
-			if(!foundSemantic) // Shader needs to have a matching input attribute, otherwise we skip it
-				continue;
-
-			// TODO - We might also want to check the size of input and buffer, and make sure they match? Or does OpenGL handle that internally?
-
-			glBindBuffer(GL_ARRAY_BUFFER, static_cast<const GLVertexBuffer*>(vertexBuffer.get())->getGLBufferId());
-			pBufferData = VBO_BUFFER_OFFSET(elem->getOffset());
-
-			unsigned int i = 0;
-			VertexElementSemantic sem = elem->getSemantic();
-
-			unsigned short typeCount = VertexElement::getTypeCount(elem->getType());
-			GLboolean normalised = GL_FALSE;
-			switch(elem->getType())
-			{
-			case VET_COLOR:
-			case VET_COLOR_ABGR:
-			case VET_COLOR_ARGB:
-				normalised = GL_TRUE;
-				break;
-			default:
-				break;
-			};
-
-			glVertexAttribPointer(
-				attribLocation,
-				typeCount, 
-				GLHardwareBufferManager::getGLType(elem->getType()), 
-				normalised, 
-				static_cast<GLsizei>(vertexBuffer->getVertexSize()), 
-				pBufferData);
-
-			glEnableVertexAttribArray(attribLocation);
-
-			mBoundAttributes.push_back(attribLocation);
-		}
+		const GLVertexArrayObject& vao = GLVertexArrayObjectManager::instance().getVAO(mCurrentVertexProgram, mBoundVertexDeclaration, mBoundVertexBuffers);
+		glBindVertexArray(vao.getGLHandle()); 
 	}
 
 	void GLRenderSystem::endDraw()
@@ -1381,14 +1319,6 @@ namespace BansheeEngine
 			return;
 
 		mDrawCallInProgress = false;
-
-		// unbind any custom attributes
-		for (auto ai = mBoundAttributes.begin(); ai != mBoundAttributes.end(); ++ai)
-		{
-			glDisableVertexAttribArray(*ai); 
-		}
-
-		mBoundAttributes.clear();
 	}
 
 	GLfloat GLRenderSystem::getCurrentAnisotropy(UINT16 unit)

+ 50 - 62
CamelotGLRenderer/Source/CmGLVertexBuffer.cpp

@@ -1,39 +1,13 @@
-/*
------------------------------------------------------------------------------
-This source file is part of OGRE
-    (Object-oriented Graphics Rendering Engine)
-For the latest info, see http://www.ogre3d.org/
-
-Copyright (c) 2000-2011 Torus Knot Software Ltd
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
------------------------------------------------------------------------------
-*/
 #include "CmGLHardwareBufferManager.h"
 #include "CmGLVertexBuffer.h"
+#include "BsGLVertexArrayObjectManager.h"
 #include "CmException.h"
 
 namespace BansheeEngine 
 {
-    GLVertexBuffer::GLVertexBuffer(HardwareBufferManager* mgr, UINT32 vertexSize, 
+    GLVertexBuffer::GLVertexBuffer(UINT32 vertexSize, 
         UINT32 numVertices, GpuBufferUsage usage)
-        : VertexBuffer(mgr, vertexSize, numVertices, usage, false)
+        : VertexBuffer(vertexSize, numVertices, usage, false)
     {
     }
 
@@ -41,8 +15,48 @@ namespace BansheeEngine
     {
     }
 
-    void* GLVertexBuffer::lockImpl(UINT32 offset, 
-        UINT32 length, GpuLockOptions options)
+	void GLVertexBuffer::initialize_internal()
+	{
+		glGenBuffers(1, &mBufferId);
+
+		if (!mBufferId)
+		{
+			CM_EXCEPT(InternalErrorException,
+				"Cannot create GL vertex buffer");
+		}
+
+		glBindBuffer(GL_ARRAY_BUFFER, mBufferId);
+
+		glBufferData(GL_ARRAY_BUFFER, mSizeInBytes, NULL,
+			GLHardwareBufferManager::getGLUsage(mUsage));
+
+		VertexBuffer::initialize_internal();
+	}
+
+	void GLVertexBuffer::destroy_internal()
+	{
+		glDeleteBuffers(1, &mBufferId);
+
+		while (mVAObjects.size() > 0)
+			GLVertexArrayObjectManager::instance().notifyBufferDestroyed(mVAObjects[0]);
+
+		VertexBuffer::destroy_internal();
+	}
+
+	void GLVertexBuffer::registerVAO(const GLVertexArrayObject& vao)
+	{
+		mVAObjects.push_back(vao);
+	}
+
+	void GLVertexBuffer::unregisterVAO(const GLVertexArrayObject& vao)
+	{
+		auto iterFind = std::find(mVAObjects.begin(), mVAObjects.end(), vao);
+
+		if (iterFind != mVAObjects.end())
+			mVAObjects.erase(iterFind);
+	}
+
+    void* GLVertexBuffer::lockImpl(UINT32 offset, UINT32 length, GpuLockOptions options)
     {
         GLenum access = 0;
 
@@ -68,14 +82,14 @@ namespace BansheeEngine
 		else
 			access = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
 
-		void* pBuffer = glMapBufferRange(GL_ARRAY_BUFFER, offset, length, access);
+		void* buffer = glMapBufferRange(GL_ARRAY_BUFFER, offset, length, access);
 
-		if(pBuffer == 0)
+		if(buffer == nullptr)
 		{
-			CM_EXCEPT(InternalErrorException, "Vertex Buffer: Out of memory");
+			CM_EXCEPT(InternalErrorException, "Cannot map vertex buffer.");
 		}
 
-		void* retPtr = static_cast<void*>(static_cast<unsigned char*>(pBuffer));
+		void* retPtr = static_cast<void*>(static_cast<unsigned char*>(buffer));
 
 		mIsLocked = true;
 		return retPtr;
@@ -87,7 +101,7 @@ namespace BansheeEngine
 
 		if(!glUnmapBuffer(GL_ARRAY_BUFFER))
 		{
-			CM_EXCEPT(InternalErrorException, "Buffer data corrupted, please reload");
+			CM_EXCEPT(InternalErrorException, "Buffer data corrupted, please reload.");
 		}
 
         mIsLocked = false;
@@ -113,30 +127,4 @@ namespace BansheeEngine
 		memcpy(bufferData, pSource, length);
 		unlock();
     }
-
-	void GLVertexBuffer::initialize_internal()
-	{
-		glGenBuffers(1, &mBufferId);
-
-		if (!mBufferId)
-		{
-			CM_EXCEPT(InternalErrorException, 
-				"Cannot create GL vertex buffer");
-		}
-
-		glBindBuffer(GL_ARRAY_BUFFER, mBufferId);
-
-		// Initialise mapped buffer and set usage
-		glBufferData(GL_ARRAY_BUFFER, mSizeInBytes, NULL, 
-			GLHardwareBufferManager::getGLUsage(mUsage));
-
-		VertexBuffer::initialize_internal();
-	}
-
-	void GLVertexBuffer::destroy_internal()
-	{
-		glDeleteBuffers(1, &mBufferId);
-
-		VertexBuffer::destroy_internal();
-	}
 }