Просмотр исходного кода

Manual parameter block contruction (WIP)

BearishSun 10 лет назад
Родитель
Сommit
8cea6e1db2

+ 45 - 0
BansheeCore/Include/BsCommonTypes.h

@@ -250,9 +250,54 @@ namespace BansheeEngine
 		GPDT_BOOL = 24,
 		GPDT_STRUCT = 25,
 		GPDT_COLOR = 26, // Same as GPDT_FLOAT4, but can be used to better deduce usage
+		GPDT_COUNT = 27, // Keep at end before GPDT_UNKNOWN
 		GPDT_UNKNOWN = 0xffff
 	};
 
+	/**
+	 * @brief	Contains data about a type used for GPU data parameters.
+	 */
+	struct GpuParamDataTypeInfo
+	{
+		UINT32 baseTypeSize;
+		UINT32 size;
+		UINT32 alignment;
+		UINT32 numRows;
+		UINT32 numColumns;
+	};
+
+	/**
+	 * @brief	Contains a lookup table for various information of all types used for data GPU parameters. Sizes are in bytes.
+	 */
+	struct GpuDataParamInfos
+	{
+		GpuDataParamInfos()
+		{
+			memset(lookup, 0, sizeof(lookup));
+
+			lookup[(UINT32)GPDT_FLOAT1] = { 4, 4, 4, 1, 1 };
+			lookup[(UINT32)GPDT_FLOAT2] = { 4, 8, 8, 1, 2 };
+			lookup[(UINT32)GPDT_FLOAT3] = { 4, 16, 16, 1, 3 };
+			lookup[(UINT32)GPDT_FLOAT4] = { 4, 16, 16, 1, 4 };
+			lookup[(UINT32)GPDT_MATRIX_2X2] = { 4, 16, 8, 2, 2 };
+			lookup[(UINT32)GPDT_MATRIX_2X3] = { 4, 32, 16, 2, 3 };
+			lookup[(UINT32)GPDT_MATRIX_2X4] = { 4, 32, 16, 2, 4 };
+			lookup[(UINT32)GPDT_MATRIX_3X2] = { 4, 24, 8, 3, 2 };
+			lookup[(UINT32)GPDT_MATRIX_3X3] = { 4, 48, 16, 3, 3 };
+			lookup[(UINT32)GPDT_MATRIX_3X4] = { 4, 48, 16, 3, 4 };
+			lookup[(UINT32)GPDT_MATRIX_4X2] = { 4, 32, 8, 4, 2 };
+			lookup[(UINT32)GPDT_MATRIX_4X3] = { 4, 64, 16, 4, 3 };
+			lookup[(UINT32)GPDT_MATRIX_4X4] = { 4, 64, 16, 4, 4 };
+			lookup[(UINT32)GPDT_INT1] = { 4, 4, 4, 1, 1 };
+			lookup[(UINT32)GPDT_INT2] = { 4, 8, 8, 1, 2 };
+			lookup[(UINT32)GPDT_INT3] = { 4, 12, 16, 1, 3 };
+			lookup[(UINT32)GPDT_INT4] = { 4, 16, 16, 1, 4 };
+			lookup[(UINT32)GPDT_BOOL] = { 4, 4, 4, 1, 1 };
+		}
+
+		GpuParamDataTypeInfo lookup[GPDT_COUNT];
+	};
+
 	/**
 	 * @brief	Type of GPU object parameters that can be used as inputs to a GPU program.
 	 */

+ 2 - 2
BansheeCore/Include/BsGpuParamDesc.h

@@ -16,8 +16,8 @@ namespace BansheeEngine
 		GpuParamDataType type;
 
 		UINT32 paramBlockSlot;
-		UINT32 gpuMemOffset;
-		UINT32 cpuMemOffset;
+		UINT32 gpuMemOffset; /**< In multiples of 4 bytes, or index for parameters not in a buffer. */
+		UINT32 cpuMemOffset; /**< In multiples of 4 bytes. */
 	};
 
 	/**

+ 5 - 2
BansheeCore/Include/BsGpuParams.h

@@ -5,8 +5,6 @@
 #include "BsCoreObject.h"
 #include "BsIResourceListener.h"
 
-#include "BsDebug.h"
-
 namespace BansheeEngine
 {
 	/**
@@ -349,6 +347,11 @@ namespace BansheeEngine
 		 */
 		static SPtr<GpuParams> create(const GpuParamDescPtr& paramDesc, bool transposeMatrices);
 
+		/**
+		 * @brief	Contains a lookup table for sizes of all data parameters. Sizes are in bytes.
+		 */
+		const static GpuDataParamInfos PARAM_SIZES;
+
 	protected:
 		/**
 		 * @copydoc	GpuParamsBase::GpuParamsBase

+ 15 - 1
BansheeCore/Include/BsRenderAPI.h

@@ -432,6 +432,20 @@ namespace BansheeEngine
 		 */
 		virtual bool getVertexColorFlipRequired() const { return false; }
 
+		/**
+		 * @brief	Generates a parameter block description and calculates per-parameter offsets for the provided gpu
+		 * 			data parameters. The offsets are render API specific and correspond to std140 layout for OpenGL, and
+		 * 			the default layout in DirectX.
+		 * 			
+		 * @param	name	Name to assign the parameter block.
+		 * @param	params	List of parameters in the parameter block. Only name, type and array size fields need to be
+		 * 					populated, the rest will be populated when the method returns.
+		 * 					
+		 * @returns	Descriptor for the parameter block holding the provided parameters as laid out by the default render
+		 * 			API layout.
+		 */
+		//virtual GpuParamBlockDesc generateParamBlockDesc(const String& name, Vector<GpuParamDataDesc>& params) = 0;
+
 		/************************************************************************/
 		/* 							INTERNAL METHODS				        	*/
 		/************************************************************************/
@@ -439,7 +453,7 @@ namespace BansheeEngine
 		/**
 		 * @brief	Initializes the render API system and creates a primary render window.
 		 *
-		 * @note		Although I'd like otherwise, due to the nature of some render system implementations,
+		 * @note	Although I'd like otherwise, due to the nature of some render API implementations,
 		 * 			you cannot initialize the render system without a window.
 		 *
 		 *			Sim thread.

+ 2 - 0
BansheeCore/Source/BsGpuParams.cpp

@@ -458,6 +458,8 @@ UINT32 GpuParamsBase::getDataParamSize(const String& name) const
 		return paramsPtr;
 	}
 
+	const GpuDataParamInfos GpuParams::PARAM_SIZES;
+
 	GpuParams::GpuParams(const GpuParamDescPtr& paramDesc, bool transposeMatrices)
 		: TGpuParams(paramDesc, transposeMatrices)
 	{

+ 4 - 33
BansheeCore/Source/BsShader.cpp

@@ -4,6 +4,7 @@
 #include "BsDebug.h"
 #include "BsShaderRTTI.h"
 #include "BsResources.h"
+#include "BsGpuParams.h"
 #include "BsFrameAlloc.h"
 #include "BsPass.h"
 #include "BsSamplerState.h"
@@ -423,43 +424,13 @@ namespace BansheeEngine
 		return false;
 	}
 
-	struct ShaderDataParamsSizes
-	{
-		ShaderDataParamsSizes()
-		{
-			memset(LOOKUP, 0, sizeof(LOOKUP));
-
-			LOOKUP[(UINT32)GPDT_FLOAT1] = 4;
-			LOOKUP[(UINT32)GPDT_FLOAT2] = 8;
-			LOOKUP[(UINT32)GPDT_FLOAT3] = 12;
-			LOOKUP[(UINT32)GPDT_FLOAT4] = 16;
-			LOOKUP[(UINT32)GPDT_MATRIX_2X2] = 16;
-			LOOKUP[(UINT32)GPDT_MATRIX_2X3] = 24;
-			LOOKUP[(UINT32)GPDT_MATRIX_2X4] = 32;
-			LOOKUP[(UINT32)GPDT_MATRIX_3X2] = 24;
-			LOOKUP[(UINT32)GPDT_MATRIX_3X3] = 36;
-			LOOKUP[(UINT32)GPDT_MATRIX_3X4] = 52;
-			LOOKUP[(UINT32)GPDT_MATRIX_4X2] = 32;
-			LOOKUP[(UINT32)GPDT_MATRIX_4X3 ] = 52;
-			LOOKUP[(UINT32)GPDT_MATRIX_4X4] = 64;
-			LOOKUP[(UINT32)GPDT_INT1] = 4;
-			LOOKUP[(UINT32)GPDT_INT2] = 8;
-			LOOKUP[(UINT32)GPDT_INT3] = 12;
-			LOOKUP[(UINT32)GPDT_INT4] = 16;
-			LOOKUP[(UINT32)GPDT_BOOL] = 1;
-		}
-
-		static const UINT32 NUM_DATA_PARAMS = 25;
-		UINT32 LOOKUP[NUM_DATA_PARAMS];
-	};
-
 	UINT32 Shader::getDataParamSize(GpuParamDataType type)
 	{
-		static const ShaderDataParamsSizes PARAM_SIZES;
+		static const GpuDataParamInfos PARAM_SIZES;
 
 		UINT32 idx = (UINT32)type;
-		if (idx < sizeof(PARAM_SIZES.LOOKUP))
-			return PARAM_SIZES.LOOKUP[idx];
+		if (idx < sizeof(GpuParams::PARAM_SIZES.lookup))
+			return GpuParams::PARAM_SIZES.lookup[idx].size;
 
 		return 0;
 	}

+ 5 - 0
BansheeGLRenderAPI/Include/BsGLRenderAPI.h

@@ -169,6 +169,11 @@ namespace BansheeEngine
 		 */
 		void convertProjectionMatrix(const Matrix4& matrix, Matrix4& dest) override;
 
+		/**
+		 * @copydoc RenderAPICore::generateParamBlockDesc()
+		 */
+		GpuParamBlockDesc generateParamBlockDesc(const String& name, Vector<GpuParamDataDesc>& params);
+
 		/************************************************************************/
 		/* 				Internal use by OpenGL RenderSystem only                */
 		/************************************************************************/

+ 71 - 0
BansheeGLRenderAPI/Source/BsGLRenderAPI.cpp

@@ -2118,6 +2118,77 @@ namespace BansheeEngine
 		dest = matrix;
 	}
 
+	GpuParamBlockDesc GLRenderAPI::generateParamBlockDesc(const String& name, Vector<GpuParamDataDesc>& params)
+	{
+		GpuParamBlockDesc block;
+		block.blockSize = 0;
+		block.isShareable = true;
+		block.name = name;
+		block.slot = 0;
+
+		UINT32 numParams = (UINT32)params.size();
+		UINT32 curOffset = 0;
+		for (UINT32 i = 0; i < numParams; i++)
+		{
+			GpuParamDataDesc& param = params[i];
+
+			const GpuParamDataTypeInfo& typeInfo = GpuParams::PARAM_SIZES.lookup[param.type];
+			UINT32 sizeBytes = typeInfo.size;
+			UINT32 alignment = typeInfo.alignment;
+
+			// Fix alignment if needed
+			UINT32 alignOffset = curOffset % alignment;
+			if (alignOffset != 0)
+			{
+				UINT32 padding = (alignment - alignOffset);
+				curOffset += padding;
+				block.blockSize += padding;
+			}
+
+			if (param.arraySize > 1)
+			{
+				// Array elements are always padded and aligned to vec4
+				alignOffset = sizeBytes % (4 * typeInfo.baseTypeSize);
+				if (alignOffset != 0)
+				{
+					UINT32 padding = ((4 * typeInfo.baseTypeSize) - alignOffset);
+					sizeBytes += padding;
+				}
+
+				alignOffset = curOffset % (4 * typeInfo.baseTypeSize);
+				if (alignOffset != 0)
+				{
+					UINT32 padding = ((4 * typeInfo.baseTypeSize) - alignOffset);
+					curOffset += padding;
+					block.blockSize += padding;
+				}
+
+				UINT32 size = sizeBytes / 4;
+
+				param.elementSize = size;
+				param.arrayElementStride = size;
+				param.cpuMemOffset = curOffset;
+				param.gpuMemOffset = curOffset;
+				
+				curOffset += sizeBytes * param.arraySize;
+			}
+			else
+			{
+				UINT32 size = sizeBytes / 4;
+				param.elementSize = size;
+				param.arrayElementStride = size;
+				param.cpuMemOffset = curOffset;
+				param.gpuMemOffset = curOffset;
+
+				curOffset += sizeBytes;
+			}
+
+			param.paramBlockSlot = 0;
+		}
+
+		return block;
+	}
+
 	void __stdcall openGlErrorCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, GLvoid *userParam)
 	{
 		if (type != GL_DEBUG_TYPE_PERFORMANCE && type != GL_DEBUG_TYPE_OTHER)

+ 4 - 0
TODOExperimentation.txt

@@ -18,6 +18,10 @@ Need an easy way to construct parameter buffers in C++
  - Currently I need to create a dummy shader just to extract those buffers
  - It would be better if I could manually specify the buffer in C++ and get its parameters
   - In OpenGL it means I would probably need to use std140 or std430 layouts and modify my parsing code so it uses GL_UNIFORM_BLOCK_DATA_SIZE for retrieving block size
+  - DX11 and OpenGL have different packing rules:
+   - https://msdn.microsoft.com/en-us/library/windows/desktop/bb509632(v=vs.85).aspx
+   - https://www.safaribooksonline.com/library/view/opengl-programming-guide/9780132748445/app09lev1sec3.html
+   - Finish RenderAPI::generateParamBlockDesc
 
 Next week:
  - Deferred base and light passes use different PerCamera buffers, unify them (both in shader and in code)