Przeglądaj źródła

Fix a vulkan bug with undefined state

Panagiotis Christopoulos Charitos 7 lat temu
rodzic
commit
029c81d085

+ 55 - 1
src/anki/gr/vulkan/CommandBufferImpl.cpp

@@ -260,10 +260,11 @@ void CommandBufferImpl::endRenderPass()
 	m_activeFb.reset(nullptr);
 	m_state.endRenderPass();
 
-	// After pushing second level command buffers the state is undefined. Reset the tracker
+	// After pushing second level command buffers the state is undefined. Reset the tracker and rebind the dynamic state
 	if(m_subpassContents == VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS)
 	{
 		m_state.reset();
+		rebindDynamicState();
 	}
 }
 
@@ -801,4 +802,57 @@ void CommandBufferImpl::copyBufferToTextureViewInternal(
 	m_microCmdb->pushObjectRef(buff);
 }
 
+void CommandBufferImpl::rebindDynamicState()
+{
+	m_viewportDirty = true;
+	m_lastViewport = {};
+	m_scissorDirty = true;
+	m_lastScissor = {};
+
+	// Rebind the stencil compare mask
+	if(m_stencilCompareMasks[0] == m_stencilCompareMasks[1])
+	{
+		ANKI_CMD(vkCmdSetStencilCompareMask(
+					 m_handle, VK_STENCIL_FACE_FRONT_BIT | VK_STENCIL_FACE_BACK_BIT, m_stencilCompareMasks[0]),
+			ANY_OTHER_COMMAND);
+	}
+	else
+	{
+		ANKI_CMD(vkCmdSetStencilCompareMask(m_handle, VK_STENCIL_FACE_FRONT_BIT, m_stencilCompareMasks[0]),
+			ANY_OTHER_COMMAND);
+		ANKI_CMD(vkCmdSetStencilCompareMask(m_handle, VK_STENCIL_FACE_BACK_BIT, m_stencilCompareMasks[1]),
+			ANY_OTHER_COMMAND);
+	}
+
+	// Rebind the stencil write mask
+	if(m_stencilWriteMasks[0] == m_stencilWriteMasks[1])
+	{
+		ANKI_CMD(vkCmdSetStencilWriteMask(
+					 m_handle, VK_STENCIL_FACE_FRONT_BIT | VK_STENCIL_FACE_BACK_BIT, m_stencilWriteMasks[0]),
+			ANY_OTHER_COMMAND);
+	}
+	else
+	{
+		ANKI_CMD(
+			vkCmdSetStencilWriteMask(m_handle, VK_STENCIL_FACE_FRONT_BIT, m_stencilWriteMasks[0]), ANY_OTHER_COMMAND);
+		ANKI_CMD(
+			vkCmdSetStencilWriteMask(m_handle, VK_STENCIL_FACE_BACK_BIT, m_stencilWriteMasks[1]), ANY_OTHER_COMMAND);
+	}
+
+	// Rebind the stencil reference
+	if(m_stencilReferenceMasks[0] == m_stencilReferenceMasks[1])
+	{
+		ANKI_CMD(vkCmdSetStencilReference(
+					 m_handle, VK_STENCIL_FACE_FRONT_BIT | VK_STENCIL_FACE_BACK_BIT, m_stencilReferenceMasks[0]),
+			ANY_OTHER_COMMAND);
+	}
+	else
+	{
+		ANKI_CMD(vkCmdSetStencilReference(m_handle, VK_STENCIL_FACE_FRONT_BIT, m_stencilReferenceMasks[0]),
+			ANY_OTHER_COMMAND);
+		ANKI_CMD(vkCmdSetStencilReference(m_handle, VK_STENCIL_FACE_BACK_BIT, m_stencilReferenceMasks[1]),
+			ANY_OTHER_COMMAND);
+	}
+}
+
 } // end namespace anki

+ 3 - 0
src/anki/gr/vulkan/CommandBufferImpl.h

@@ -374,6 +374,9 @@ private:
 	Array<U32, 2> m_stencilCompareMasks = {{0x5A5A5A5A, 0x5A5A5A5A}}; ///< Use a stupid number to initialize.
 	Array<U32, 2> m_stencilWriteMasks = {{0x5A5A5A5A, 0x5A5A5A5A}};
 	Array<U32, 2> m_stencilReferenceMasks = {{0x5A5A5A5A, 0x5A5A5A5A}};
+
+	/// Rebind the above dynamic state. Needed after pushing secondary command buffers (they dirty the state).
+	void rebindDynamicState();
 	/// @}
 
 	/// @name barrier_batch

+ 12 - 12
src/anki/gr/vulkan/Pipeline.cpp

@@ -31,9 +31,9 @@ Bool PipelineStateTracker::updateHashes()
 	Bool stateDirty = false;
 
 	// Prog
-	if(m_dirty.m_prog)
+	if(!!(m_dirty.m_other & DirtyBit::PROG))
 	{
-		m_dirty.m_prog = false;
+		m_dirty.m_other &= ~DirtyBit::PROG;
 		stateDirty = true;
 		m_hashes.m_prog = m_state.m_prog->getUuid();
 	}
@@ -76,33 +76,33 @@ Bool PipelineStateTracker::updateHashes()
 	}
 
 	// IA
-	if(m_dirty.m_ia)
+	if(!!(m_dirty.m_other & DirtyBit::IA))
 	{
-		m_dirty.m_ia = false;
+		m_dirty.m_other &= ~DirtyBit::IA;
 		m_hashes.m_ia = computeHash(&m_state.m_inputAssembler, sizeof(m_state.m_inputAssembler));
 		stateDirty = true;
 	}
 
 	// Rasterizer
-	if(m_dirty.m_raster)
+	if(!!(m_dirty.m_other & DirtyBit::RASTER))
 	{
-		m_dirty.m_raster = false;
+		m_dirty.m_other &= ~DirtyBit::RASTER;
 		stateDirty = true;
 		m_hashes.m_raster = computeHash(&m_state.m_rasterizer, sizeof(m_state.m_rasterizer));
 	}
 
 	// Depth
-	if(m_fbDepth && m_dirty.m_depth)
+	if(m_fbDepth && !!(m_dirty.m_other & DirtyBit::DEPTH))
 	{
-		m_dirty.m_depth = false;
+		m_dirty.m_other &= ~DirtyBit::DEPTH;
 		stateDirty = true;
 		m_hashes.m_depth = computeHash(&m_state.m_depth, sizeof(m_state.m_depth));
 	}
 
 	// Stencil
-	if(m_fbStencil && m_dirty.m_stencil)
+	if(m_fbStencil && !!(m_dirty.m_other & DirtyBit::STENCIL))
 	{
-		m_dirty.m_stencil = false;
+		m_dirty.m_other &= ~DirtyBit::STENCIL;
 		stateDirty = true;
 		m_hashes.m_stencil = computeHash(&m_state.m_stencil, sizeof(m_state.m_stencil));
 	}
@@ -113,9 +113,9 @@ Bool PipelineStateTracker::updateHashes()
 		ANKI_ASSERT(m_fbColorAttachmentMask == m_shaderColorAttachmentWritemask
 					&& "Shader and fb should have same attachment mask");
 
-		if(m_dirty.m_color)
+		if(!!(m_dirty.m_other & DirtyBit::COLOR))
 		{
-			m_dirty.m_color = false;
+			m_dirty.m_other &= ~DirtyBit::COLOR;
 			m_hashes.m_color = m_state.m_color.m_alphaToCoverageEnabled ? 1 : 2;
 			stateDirty = true;
 		}

+ 29 - 19
src/anki/gr/vulkan/Pipeline.h

@@ -215,7 +215,7 @@ public:
 		if(m_state.m_inputAssembler.m_primitiveRestartEnabled != enable)
 		{
 			m_state.m_inputAssembler.m_primitiveRestartEnabled = enable;
-			m_dirty.m_ia = true;
+			m_dirty.m_other |= DirtyBit::IA;
 		}
 	}
 
@@ -224,7 +224,7 @@ public:
 		if(m_state.m_rasterizer.m_fillMode != mode)
 		{
 			m_state.m_rasterizer.m_fillMode = mode;
-			m_dirty.m_raster = true;
+			m_dirty.m_other |= DirtyBit::RASTER;
 		}
 	}
 
@@ -233,7 +233,7 @@ public:
 		if(m_state.m_rasterizer.m_cullMode != mode)
 		{
 			m_state.m_rasterizer.m_cullMode = mode;
-			m_dirty.m_raster = true;
+			m_dirty.m_other |= DirtyBit::RASTER;
 		}
 	}
 
@@ -244,7 +244,7 @@ public:
 		{
 			m_state.m_rasterizer.m_depthBiasConstantFactor = factor;
 			m_state.m_rasterizer.m_depthBiasSlopeFactor = units;
-			m_dirty.m_raster = true;
+			m_dirty.m_other |= DirtyBit::RASTER;
 		}
 	}
 
@@ -261,7 +261,7 @@ public:
 			m_state.m_stencil.m_face[0].m_stencilFailOperation = stencilFail;
 			m_state.m_stencil.m_face[0].m_stencilPassDepthFailOperation = stencilPassDepthFail;
 			m_state.m_stencil.m_face[0].m_stencilPassDepthPassOperation = stencilPassDepthPass;
-			m_dirty.m_stencil = true;
+			m_dirty.m_other |= DirtyBit::STENCIL;
 		}
 
 		if(!!(face & FaceSelectionBit::BACK)
@@ -272,7 +272,7 @@ public:
 			m_state.m_stencil.m_face[1].m_stencilFailOperation = stencilFail;
 			m_state.m_stencil.m_face[1].m_stencilPassDepthFailOperation = stencilPassDepthFail;
 			m_state.m_stencil.m_face[1].m_stencilPassDepthPassOperation = stencilPassDepthPass;
-			m_dirty.m_stencil = true;
+			m_dirty.m_other |= DirtyBit::STENCIL;
 		}
 	}
 
@@ -281,13 +281,13 @@ public:
 		if(!!(face & FaceSelectionBit::FRONT) && m_state.m_stencil.m_face[0].m_compareFunction != comp)
 		{
 			m_state.m_stencil.m_face[0].m_compareFunction = comp;
-			m_dirty.m_stencil = true;
+			m_dirty.m_other |= DirtyBit::STENCIL;
 		}
 
 		if(!!(face & FaceSelectionBit::BACK) && m_state.m_stencil.m_face[1].m_compareFunction != comp)
 		{
 			m_state.m_stencil.m_face[1].m_compareFunction = comp;
-			m_dirty.m_stencil = true;
+			m_dirty.m_other |= DirtyBit::STENCIL;
 		}
 	}
 
@@ -296,7 +296,7 @@ public:
 		if(m_state.m_depth.m_depthWriteEnabled != enable)
 		{
 			m_state.m_depth.m_depthWriteEnabled = enable;
-			m_dirty.m_depth = true;
+			m_dirty.m_other |= DirtyBit::DEPTH;
 		}
 	}
 
@@ -305,7 +305,7 @@ public:
 		if(m_state.m_depth.m_depthCompareFunction != op)
 		{
 			m_state.m_depth.m_depthCompareFunction = op;
-			m_dirty.m_depth = true;
+			m_dirty.m_other |= DirtyBit::DEPTH;
 		}
 	}
 
@@ -314,7 +314,7 @@ public:
 		if(m_state.m_color.m_alphaToCoverageEnabled != enable)
 		{
 			m_state.m_color.m_alphaToCoverageEnabled = enable;
-			m_dirty.m_color = true;
+			m_dirty.m_other |= DirtyBit::COLOR;
 		}
 	}
 
@@ -360,7 +360,7 @@ public:
 			m_shaderColorAttachmentWritemask = impl.getReflectionInfo().m_colorAttachmentWritemask;
 			m_shaderAttributeMask = impl.getReflectionInfo().m_attributeMask;
 			m_state.m_prog = prog;
-			m_dirty.m_prog = true;
+			m_dirty.m_other |= DirtyBit::PROG;
 		}
 	}
 
@@ -389,7 +389,7 @@ public:
 		if(m_state.m_inputAssembler.m_topology != topology)
 		{
 			m_state.m_inputAssembler.m_topology = topology;
-			m_dirty.m_ia = true;
+			m_dirty.m_other |= DirtyBit::IA;
 		}
 	}
 
@@ -451,18 +451,28 @@ private:
 		}
 	} m_hashes;
 
+	enum class DirtyBit : U8
+	{
+		PROG = 1 << 0,
+		IA = 1 << 1,
+		RASTER = 1 << 2,
+		STENCIL = 1 << 3,
+		DEPTH = 1 << 4,
+		COLOR = 1 << 5,
+
+		NONE = 0,
+		ALL = PROG | IA | RASTER | STENCIL | DEPTH | COLOR
+	};
+	ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(DirtyBit, friend)
+
 	class DirtyBits
 	{
 	public:
-		Bool8 m_prog = true;
+		DirtyBit m_other = DirtyBit::ALL;
+
 		BitSet<MAX_VERTEX_ATTRIBUTES, U8> m_attribs = {true};
 		BitSet<MAX_VERTEX_ATTRIBUTES, U8> m_vertBindings = {true};
 
-		Bool8 m_ia = true;
-		Bool8 m_raster = true;
-		Bool8 m_stencil = true;
-		Bool8 m_depth = true;
-		Bool8 m_color = true;
 		BitSet<MAX_COLOR_ATTACHMENTS, U8> m_colAttachments = {true};
 	} m_dirty;