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

DX11 meshes now render even if their vertex declaration doesn't match the shader

BearishSun 10 лет назад
Родитель
Сommit
0ac4c456b4

+ 4 - 0
BansheeD3D11RenderAPI/Source/BsD3D11HLSLParamParser.cpp

@@ -43,6 +43,10 @@ namespace BansheeEngine
 				if (FAILED(hr))
 				if (FAILED(hr))
 					BS_EXCEPT(RenderingAPIException, "Cannot get input param desc with index: " + toString(i));
 					BS_EXCEPT(RenderingAPIException, "Cannot get input param desc with index: " + toString(i));
 
 
+				// We don't care about system value semantics
+				if (StringUtil::startsWith(String(inputParamDesc.SemanticName), "sv_"))
+					continue;
+
 				inputParams->push_back(VertexElement(inputParamDesc.Stream, inputParamDesc.Register,
 				inputParams->push_back(VertexElement(inputParamDesc.Stream, inputParamDesc.Register,
 					D3D11Mappings::getInputType(inputParamDesc.ComponentType), D3D11Mappings::get(inputParamDesc.SemanticName), inputParamDesc.SemanticIndex));
 					D3D11Mappings::getInputType(inputParamDesc.ComponentType), D3D11Mappings::get(inputParamDesc.SemanticName), inputParamDesc.SemanticIndex));
 			}
 			}

+ 53 - 23
BansheeD3D11RenderAPI/Source/BsD3D11InputLayoutManager.cpp

@@ -52,7 +52,8 @@ namespace BansheeEngine
 		}
 		}
 	}
 	}
 
 
-	ID3D11InputLayout* D3D11InputLayoutManager::retrieveInputLayout(const SPtr<VertexDeclarationCore>& vertexShaderDecl, const SPtr<VertexDeclarationCore>& vertexBufferDecl, D3D11GpuProgramCore& vertexProgram)
+	ID3D11InputLayout* D3D11InputLayoutManager::retrieveInputLayout(const SPtr<VertexDeclarationCore>& vertexShaderDecl, 
+		const SPtr<VertexDeclarationCore>& vertexBufferDecl, D3D11GpuProgramCore& vertexProgram)
 	{
 	{
 		VertexDeclarationKey pair;
 		VertexDeclarationKey pair;
 		pair.vertxDeclId = vertexBufferDecl->getId();
 		pair.vertxDeclId = vertexBufferDecl->getId();
@@ -76,29 +77,60 @@ namespace BansheeEngine
 		return iterFind->second->inputLayout;
 		return iterFind->second->inputLayout;
 	}
 	}
 
 
-	void D3D11InputLayoutManager::addNewInputLayout(const SPtr<VertexDeclarationCore>& vertexShaderDecl, const SPtr<VertexDeclarationCore>& vertexBufferDecl, D3D11GpuProgramCore& vertexProgram)
+	void D3D11InputLayoutManager::addNewInputLayout(const SPtr<VertexDeclarationCore>& vertexShaderDecl, 
+		const SPtr<VertexDeclarationCore>& vertexBufferDecl, D3D11GpuProgramCore& vertexProgram)
 	{
 	{
-		if (!vertexBufferDecl->isCompatible(vertexShaderDecl))
-			return; // Error was already reported, so just quit here
+		const VertexDeclarationProperties& bufferDeclProps = vertexBufferDecl->getProperties();
+		const VertexDeclarationProperties& shaderDeclProps = vertexShaderDecl->getProperties();
 
 
-		const VertexDeclarationProperties& declProps = vertexBufferDecl->getProperties();
+		Vector<D3D11_INPUT_ELEMENT_DESC> declElements;
 
 
-		UINT32 numElements = declProps.getElementCount();
-		D3D11_INPUT_ELEMENT_DESC* declElements = bs_newN<D3D11_INPUT_ELEMENT_DESC>(numElements);
-		ZeroMemory(declElements, sizeof(D3D11_INPUT_ELEMENT_DESC) * numElements);
+		const List<VertexElement>& bufferElems = bufferDeclProps.getElements();
+		const List<VertexElement>& shaderElems = shaderDeclProps.getElements();
 
 
-		unsigned int idx = 0;
-		for (auto iter = declProps.getElements().begin(); iter != declProps.getElements().end(); ++iter)
+		INT32 maxStreamIdx = -1;
+		for (auto iter = bufferElems.begin(); iter != bufferElems.end(); ++iter)
 		{
 		{
-			declElements[idx].SemanticName			= D3D11Mappings::get(iter->getSemantic());
-			declElements[idx].SemanticIndex			= iter->getSemanticIdx();
-			declElements[idx].Format				= D3D11Mappings::get(iter->getType());
-			declElements[idx].InputSlot				= iter->getStreamIdx();
-			declElements[idx].AlignedByteOffset		= static_cast<WORD>(iter->getOffset());
-			declElements[idx].InputSlotClass		= D3D11_INPUT_PER_VERTEX_DATA;
-			declElements[idx].InstanceDataStepRate	= 0;
-
-			idx++;
+			declElements.push_back(D3D11_INPUT_ELEMENT_DESC());
+			D3D11_INPUT_ELEMENT_DESC& elementDesc = declElements.back();
+
+			elementDesc.SemanticName = D3D11Mappings::get(iter->getSemantic());
+			elementDesc.SemanticIndex = iter->getSemanticIdx();
+			elementDesc.Format = D3D11Mappings::get(iter->getType());
+			elementDesc.InputSlot = iter->getStreamIdx();
+			elementDesc.AlignedByteOffset = static_cast<WORD>(iter->getOffset());
+			elementDesc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
+			elementDesc.InstanceDataStepRate = 0;
+
+			maxStreamIdx = std::max(maxStreamIdx, (INT32)iter->getStreamIdx());
+		}
+
+		// Find elements missing in buffer and add a dummy stream for them
+		for (auto shaderIter = shaderElems.begin(); shaderIter != shaderElems.end(); ++shaderIter)
+		{
+			bool foundElement = false;
+			for (auto bufferIter = bufferElems.begin(); bufferIter != bufferElems.end(); ++bufferIter)
+			{
+				if (shaderIter->getSemantic() == bufferIter->getSemantic() && shaderIter->getSemanticIdx() == bufferIter->getSemanticIdx())
+				{
+					foundElement = true;
+					break;
+				}
+			}
+
+			if (!foundElement)
+			{
+				declElements.push_back(D3D11_INPUT_ELEMENT_DESC());
+				D3D11_INPUT_ELEMENT_DESC& elementDesc = declElements.back();
+
+				elementDesc.SemanticName = D3D11Mappings::get(shaderIter->getSemantic());
+				elementDesc.SemanticIndex = shaderIter->getSemanticIdx();
+				elementDesc.Format = D3D11Mappings::get(shaderIter->getType());
+				elementDesc.InputSlot = (UINT32)(maxStreamIdx + 1);
+				elementDesc.AlignedByteOffset = 0;
+				elementDesc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
+				elementDesc.InstanceDataStepRate = 0;
+			}
 		}
 		}
 
 
 		D3D11RenderAPI* d3d11rs = static_cast<D3D11RenderAPI*>(RenderAPICore::instancePtr());
 		D3D11RenderAPI* d3d11rs = static_cast<D3D11RenderAPI*>(RenderAPICore::instancePtr());
@@ -110,14 +142,12 @@ namespace BansheeEngine
 		newEntry->lastUsedIdx = ++mLastUsedCounter;
 		newEntry->lastUsedIdx = ++mLastUsedCounter;
 		newEntry->inputLayout = nullptr; 
 		newEntry->inputLayout = nullptr; 
 		HRESULT hr = device.getD3D11Device()->CreateInputLayout( 
 		HRESULT hr = device.getD3D11Device()->CreateInputLayout( 
-			declElements, 
-			numElements, 
+			&declElements[0], 
+			declElements.size(),
 			&microcode[0], 
 			&microcode[0], 
 			microcode.size(),
 			microcode.size(),
 			&newEntry->inputLayout);
 			&newEntry->inputLayout);
 
 
-		bs_deleteN(declElements, numElements);
-
 		if (FAILED(hr)|| device.hasError())
 		if (FAILED(hr)|| device.hasError())
 			BS_EXCEPT(RenderingAPIException, "Unable to set D3D11 vertex declaration" + device.getErrorDescription());
 			BS_EXCEPT(RenderingAPIException, "Unable to set D3D11 vertex declaration" + device.getErrorDescription());
 
 

+ 1 - 0
BansheeD3D11RenderAPI/Source/BsD3D11RenderAPI.cpp

@@ -130,6 +130,7 @@ namespace BansheeEngine
 		GpuProgramCoreManager::instance().addFactory(mHLSLFactory);
 		GpuProgramCoreManager::instance().addFactory(mHLSLFactory);
 
 
 		mIAManager = bs_new<D3D11InputLayoutManager>();
 		mIAManager = bs_new<D3D11InputLayoutManager>();
+
 		RenderAPICore::initializePrepare();
 		RenderAPICore::initializePrepare();
 	}
 	}
 
 

+ 3 - 1
Dependencies.txt

@@ -45,8 +45,10 @@ BansheeD3D11RenderAPI & BansheeD3D9RenderAPI (both optional) rely on:
   - http://www.microsoft.com/en-us/download/details.aspx?id=6812
   - http://www.microsoft.com/en-us/download/details.aspx?id=6812
   - After installing the SDK make sure DXSDK_DIR environment variable is set up pointing to the installation path
   - After installing the SDK make sure DXSDK_DIR environment variable is set up pointing to the installation path
  - Windows SDK (Only required if on Windows 8 or higher)
  - Windows SDK (Only required if on Windows 8 or higher)
-  - Needed for DirectX 11 debug layer
+  - Needed only for DirectX 11 debug layer
   - This also contains DirectX SDK so you don't need to install it separately.
   - This also contains DirectX SDK so you don't need to install it separately.
+  - Optionally if you just need the debug layers you can enable it separately in Windows 10 by going to: 
+    - Settings panel->System->Apps & features->Manage optional Features->Add a feature->Select "Graphics Tools"
 
 
 BansheeSL (optional) relies on:
 BansheeSL (optional) relies on:
  - Bison 2.7
  - Bison 2.7

+ 1 - 3
RenderBeast/Source/BsRenderBeast.cpp

@@ -145,7 +145,7 @@ namespace BansheeEngine
 				if (renElement.material == nullptr)
 				if (renElement.material == nullptr)
 					renElement.material = renderable->getMaterial(0);
 					renElement.material = renderable->getMaterial(0);
 
 
-				if (renElement.material->getShader() == nullptr)
+				if (renElement.material != nullptr && renElement.material->getShader() == nullptr)
 					renElement.material = nullptr;
 					renElement.material = nullptr;
 
 
 				// Validate mesh <-> shader vertex bindings
 				// Validate mesh <-> shader vertex bindings
@@ -159,8 +159,6 @@ namespace BansheeEngine
 						SPtr<VertexDeclarationCore> shaderDecl = pass->getVertexProgram()->getInputDeclaration();
 						SPtr<VertexDeclarationCore> shaderDecl = pass->getVertexProgram()->getInputDeclaration();
 						if (!vertexDecl->isCompatible(shaderDecl))
 						if (!vertexDecl->isCompatible(shaderDecl))
 						{
 						{
-							renElement.material = nullptr;
-
 							Vector<VertexElement> missingElements = vertexDecl->getMissingElements(shaderDecl);
 							Vector<VertexElement> missingElements = vertexDecl->getMissingElements(shaderDecl);
 
 
 							StringStream wrnStream;
 							StringStream wrnStream;

+ 1 - 1
TODO.txt

@@ -19,7 +19,7 @@ Stage 2 polish:
 
 
 Optional:
 Optional:
  - Undocking of editor window doesn't work (they just get lost)
  - Undocking of editor window doesn't work (they just get lost)
- - Crash when adding a new directional light and then shutting down
+ - Crash when adding a new directional light and then shutting down (also crash when just deleting a directional light)
  - Start editor in fullscreen
  - Start editor in fullscreen
  - If user clears the default shader he has no way of re-assigning it - add default shader to project folder?
  - If user clears the default shader he has no way of re-assigning it - add default shader to project folder?
  - Toggle to enable/disable SceneObject in Inspector
  - Toggle to enable/disable SceneObject in Inspector

+ 5 - 3
TODOExperimentation.txt

@@ -15,20 +15,22 @@ Assign ViewOrigin, PreViewTranslation, TransViewProj
  
  
 Next week:
 Next week:
  - With no light in the scene nothing renders, but it should at least render everything with constant ambient (just for debug until I implement GI)
  - With no light in the scene nothing renders, but it should at least render everything with constant ambient (just for debug until I implement GI)
+  - Perhaps "inject" a dummy directional light when no other light is in the scene?
  - I have removed DefaultNoNormal shader as support deferred rendering with no normals complicates the pipeline too much. I should instead
  - I have removed DefaultNoNormal shader as support deferred rendering with no normals complicates the pipeline too much. I should instead
    ensure meshes always have dummy normal data. (Right now mesh with no normals/tangents keeps spamming DX11 warnings)
    ensure meshes always have dummy normal data. (Right now mesh with no normals/tangents keeps spamming DX11 warnings)
+   - Can I do this in the D3D11RenderAPI? If pieces are missing add new dummy vertex streams with 0 vertex stride and one element
 
 
 Later:
 Later:
- - Lights already existing in scene on load don't seem to render'
+ - Lights already existing in scene on load don't seem to render (seems they get converted to point lights for some reason)
  - I changed how unsupported texture formats work, I should test if I didn't break OpenGL
  - I changed how unsupported texture formats work, I should test if I didn't break OpenGL
- - Positioning of meshes seems slightly broken (selecting the dragon will sometimes select the wall behind it, and handle is displayed at wrong position)
+
  - When rendering lights right now I need to bind Gbuffer and light parameters to material, and then bind the material parameters to the pipeline
  - When rendering lights right now I need to bind Gbuffer and light parameters to material, and then bind the material parameters to the pipeline
   - Either unify these two processes by finding a better way, or hide the binding in light material class
   - Either unify these two processes by finding a better way, or hide the binding in light material class
  - Too many depth buffers. Main render surface has one, game viewport has one and gbuffer has one
  - Too many depth buffers. Main render surface has one, game viewport has one and gbuffer has one
   - Disable main depth buffer by default, disable depth buffer in SceneWindow and GameWindow RT's
   - Disable main depth buffer by default, disable depth buffer in SceneWindow and GameWindow RT's
   - When rendering to scene target use the gbuffers depth buffer (what if their sizes don't match due to quantization?)
   - When rendering to scene target use the gbuffers depth buffer (what if their sizes don't match due to quantization?)
   - Although having an extra depth buffer won't be the worst thing as even at full HD it's only 8MB
   - Although having an extra depth buffer won't be the worst thing as even at full HD it's only 8MB
- - Default(dummy) shaders need to render to gbuffer
+
  - Finish up DefferedPointLightPass by generating cone geometry in shader
  - Finish up DefferedPointLightPass by generating cone geometry in shader
  - Modify Light so it generated adequate number of vertices required for cone geometry, without actually creating the cone
  - Modify Light so it generated adequate number of vertices required for cone geometry, without actually creating the cone
  - Think about how to handle post-processing shaders (HDR tone mapping)
  - Think about how to handle post-processing shaders (HDR tone mapping)