Browse Source

Better DX11 parameter parsing that doesn't ignore pack offsets

Marko Pintera 13 years ago
parent
commit
383e38f9c3

+ 2 - 2
CamelotClient/CamelotClient.cpp

@@ -22,9 +22,9 @@
 
 #include "CmDebugCamera.h"
 
-//#define DX11
+#define DX11
 //#define DX9
-#define GL
+//#define GL
 
 using namespace CamelotEngine;
 

+ 14 - 47
CamelotD3D11RenderSystem/Source/CmD3D11HLSLParamParser.cpp

@@ -200,17 +200,7 @@ namespace CamelotEngine
 			parseVariable(varTypeDesc, varDesc, desc, blockDesc);
 		}
 
-		// Buffer always needs to be a multiple of 4, so make it so
-		if(blockDesc.blockSize % 4 != 0)
-			blockDesc.blockSize += (4 - (blockDesc.blockSize % 4));
-
-#if CM_DEBUG_MODE
-		if(constantBufferDesc.Size != (blockDesc.blockSize * 4))
-		{
-			CM_EXCEPT(InternalErrorException, "Calculated param block size and size returned by DirectX don't match. Calculated size is: " + toString(constantBufferDesc.Size) +
-				" and DirectX size is: " + toString(blockDesc.blockSize * 4));
-		}
-#endif
+		blockDesc.blockSize = constantBufferDesc.Size / 4;
 	}
 
 	void D3D11HLSLParamParser::parseVariable(D3D11_SHADER_TYPE_DESC& varTypeDesc, D3D11_SHADER_VARIABLE_DESC& varDesc, GpuParamDesc& desc, GpuParamBlockDesc& paramBlock)
@@ -219,48 +209,25 @@ namespace CamelotEngine
 		memberDesc.name = varDesc.Name;
 		memberDesc.paramBlockSlot = paramBlock.slot;
 		memberDesc.arraySize = varTypeDesc.Elements == 0 ? 1 : varTypeDesc.Elements;
-		memberDesc.elementSize = varDesc.Size / 4; // Stored in multiples of 4
-		memberDesc.arrayElementStride = memberDesc.elementSize;
-		memberDesc.gpuMemOffset = varDesc.StartOffset;
+		memberDesc.gpuMemOffset = varDesc.StartOffset / 4;
+		memberDesc.cpuMemOffset = varDesc.StartOffset / 4;
 		
-		// Calculate buffer offset and element size
-		// This is based on "Packing Rules for Constant Variables (DX11)":
-		// http://msdn.microsoft.com/en-us/library/windows/desktop/bb509632(v=vs.85).aspx
-
-		// Elements in array always start at 16 byte (4 float) boundaries so we handle them specially
-		// (Determining individual element size in an array also takes some additional work)
-		if(memberDesc.arraySize == 1)
-		{
-			UINT32 freeSlotsInRegister = (((paramBlock.blockSize / 4) + 1) * 4) - paramBlock.blockSize;
-
-			// Fits in current register
-			if(memberDesc.elementSize <= freeSlotsInRegister)
-			{
-				memberDesc.cpuMemOffset = paramBlock.blockSize;
-				paramBlock.blockSize += memberDesc.elementSize;
-			}
-			else
-			{
-				// Doesn't fit, so skip remaining slots in register and go to new one
-				paramBlock.blockSize += freeSlotsInRegister;
-				memberDesc.cpuMemOffset = paramBlock.blockSize;
-				paramBlock.blockSize +=  memberDesc.elementSize;
-			}
-		}
-		else
+		// Determine individual element size in the array
+		if(memberDesc.arraySize > 1)
 		{
 			// Find array element size (reported size is total size of array, minus unused register slots)
-			int totalSlotsUsedByArray = (memberDesc.elementSize / 4 + 1) * 4;
-			int unusedSlotsInArray = totalSlotsUsedByArray - memberDesc.elementSize;
+			int totalArraySize = (varDesc.Size / 4);
+
+			int totalSlotsUsedByArray = (totalArraySize / 4 + 1) * 4;
+			int unusedSlotsInArray = totalSlotsUsedByArray - totalArraySize;
 
 			memberDesc.arrayElementStride = totalSlotsUsedByArray / memberDesc.arraySize;
 			memberDesc.elementSize = memberDesc.arrayElementStride - unusedSlotsInArray;
-
-			int freeSlotsInRegister = (((paramBlock.blockSize / 4) + 1) * 4) - paramBlock.blockSize;
-
-			paramBlock.blockSize += freeSlotsInRegister;
-			memberDesc.cpuMemOffset = paramBlock.blockSize;
-			paramBlock.blockSize += memberDesc.arraySize * memberDesc.arrayElementStride - unusedSlotsInArray;
+		}
+		else
+		{
+			memberDesc.elementSize = varDesc.Size / 4; // Stored in multiples of 4
+			memberDesc.arrayElementStride = memberDesc.elementSize;
 		}
 			
 		switch(varTypeDesc.Class)

+ 1 - 4
CamelotRenderer/TODO.txt

@@ -156,6 +156,7 @@ Low priority TODO:
    - Remove Response handlers from Resources
 - Cg doesn't work. Either remove it or get it to work
 - System is not yet ready for multiple rendering contexts
+- When serializing/deserializing derived classes, deserialization is done from most derived to base, while it should probably be done the other way around.
 
 Optional TODO:
  - Add precompiled headers to all projects
@@ -166,10 +167,6 @@ Optional TODO:
  - Extend texture copy so it accepts different subregions & subresources (currently only entire resource can be copied)
  - Need a way to convert MSAA render texture into a normal render texture
  - Vertex buffer start offset is not supported when calling Draw methods
- - Issue with deserialization and value types:
-  - Value types are only set at the end of deserialization, because I want to be sure all of their fields are initialized. 
-     However there is nothing stopping a custom RTTI method from accessing a (yet uninitialized) value in a ptr field. 
-	 (See CmMaterialRTTI, setTexParam). I need to initialize fields in a better order.)
  - Creating stuff like gpu program include and shader, etc. still require initialize() (call to render thread)
 
  -----------------------------------------------------------------------------------------------

+ 0 - 2
TODODoc.txt

@@ -5,8 +5,6 @@
 	- Classes that are only accessible from the render thread: GpuProgram, HardwarePixelBuffer, HardwareVertexBuffer, HardwareIndexBuffer
   - Make sure the user knows resources are shared between contexts. All resource updates are executed 
      before rendering a frame, so whichever context updated the resource last, was the version that will be used.
-  - HLSL11 limitations
-     - packoffset on parameters is not supported and will likely result in invalid constant buffer size and/or element offsets
   - GLSL limitations
      - layout(row_major) is not supported and will likely result in incorrect matrices
   - Texture limitations: Only 1D, 2D, 3D and Cube textures (and their samplers) are supported. Support for multisampled textures