Browse Source

Remove some references of objects from the VK pipeline manager

Panagiotis Christopoulos Charitos 4 years ago
parent
commit
c29fa12ae9

+ 4 - 3
AnKi/Gr/Vulkan/CommandBufferImpl.cpp

@@ -52,7 +52,8 @@ Error CommandBufferImpl::init(const CommandBufferInitInfo& init)
 		m_activeFb = init.m_framebuffer;
 		m_colorAttachmentUsages = init.m_colorAttachmentUsages;
 		m_depthStencilAttachmentUsage = init.m_depthStencilAttachmentUsage;
-		m_state.beginRenderPass(m_activeFb);
+		m_state.beginRenderPass(static_cast<FramebufferImpl*>(m_activeFb.get()));
+		m_microCmdb->pushObjectRef(m_activeFb);
 	}
 
 	for(DescriptorSetState& state : m_dsetState)
@@ -148,10 +149,10 @@ void CommandBufferImpl::beginRenderPass(FramebufferPtr fb,
 
 void CommandBufferImpl::beginRenderPassInternal()
 {
-	m_state.beginRenderPass(m_activeFb);
-
 	FramebufferImpl& impl = static_cast<FramebufferImpl&>(*m_activeFb);
 
+	m_state.beginRenderPass(&impl);
+
 	VkRenderPassBeginInfo bi = {};
 	bi.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
 	bi.clearValueCount = impl.getAttachmentCount();

+ 2 - 2
AnKi/Gr/Vulkan/CommandBufferImpl.inl.h

@@ -631,7 +631,7 @@ inline void CommandBufferImpl::drawcallCommon()
 	// Get or create ppline
 	Pipeline ppline;
 	Bool stateDirty;
-	m_graphicsProg->getPipelineFactory().newPipeline(m_state, ppline, stateDirty);
+	m_graphicsProg->getPipelineFactory().getOrCreatePipeline(m_state, ppline, stateDirty);
 
 	if(stateDirty)
 	{
@@ -840,7 +840,7 @@ inline void CommandBufferImpl::bindShaderProgram(ShaderProgramPtr& prog)
 		m_graphicsProg = &impl;
 		m_computeProg = nullptr; // Unbind the compute prog. Doesn't work like vulkan
 		m_rtProg = nullptr; // See above
-		m_state.bindShaderProgram(prog);
+		m_state.bindShaderProgram(&impl);
 	}
 	else if(!!(impl.getStages() & ShaderTypeBit::COMPUTE))
 	{

+ 1 - 0
AnKi/Gr/Vulkan/Common.h

@@ -79,6 +79,7 @@ enum class VulkanExtensions : U32
 	KHR_SHADER_FLOAT16_INT8 = 1 << 17,
 	KHR_SHADER_ATOMIC_INT64 = 1 << 18,
 	KHR_SPIRV_1_4 = 1 << 19,
+	KHR_SHADER_FLOAT_CONTROLS = 1 << 20,
 };
 ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(VulkanExtensions)
 

+ 11 - 0
AnKi/Gr/Vulkan/GrManagerImpl.cpp

@@ -652,6 +652,11 @@ Error GrManagerImpl::initDevice(const GrManagerInitInfo& init)
 				m_extensions |= VulkanExtensions::KHR_SPIRV_1_4;
 				extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
 			}
+			else if(extensionName == VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME)
+			{
+				m_extensions |= VulkanExtensions::KHR_SHADER_FLOAT_CONTROLS;
+				extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
+			}
 		}
 
 		ANKI_VK_LOGI("Will enable the following device extensions:");
@@ -916,6 +921,12 @@ Error GrManagerImpl::initDevice(const GrManagerInitInfo& init)
 		return Error::FUNCTION_FAILED;
 	}
 
+	if(!(m_extensions & VulkanExtensions::KHR_SHADER_FLOAT_CONTROLS))
+	{
+		ANKI_VK_LOGE(VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME " is not supported");
+		return Error::FUNCTION_FAILED;
+	}
+
 	return Error::NONE;
 }
 

+ 62 - 41
AnKi/Gr/Vulkan/Pipeline.cpp

@@ -23,8 +23,6 @@ void PipelineStateTracker::reset()
 	m_fbStencil = false;
 	m_defaultFb = false;
 	m_fbColorAttachmentMask.unsetAll();
-	m_rpass = VK_NULL_HANDLE;
-	m_fb.reset(nullptr);
 }
 
 Bool PipelineStateTracker::updateHashes()
@@ -32,13 +30,21 @@ Bool PipelineStateTracker::updateHashes()
 	Bool stateDirty = false;
 
 	// Prog
-	if(!!(m_dirty.m_other & DirtyBit::PROG))
+	if(m_dirty.m_prog)
 	{
-		m_dirty.m_other &= ~DirtyBit::PROG;
+		m_dirty.m_prog = false;
 		stateDirty = true;
 		m_hashes.m_prog = m_state.m_prog->getUuid();
 	}
 
+	// Rpass
+	if(m_dirty.m_rpass)
+	{
+		m_dirty.m_rpass = false;
+		stateDirty = true;
+		m_hashes.m_rpass = ptrToNumber(m_state.m_rpass);
+	}
+
 	// Vertex
 	if(m_dirty.m_attribs.getAny() || m_dirty.m_vertBindings.getAny())
 	{
@@ -56,6 +62,8 @@ Bool PipelineStateTracker::updateHashes()
 				}
 
 				const U binding = m_state.m_vertex.m_attributes[i].m_binding;
+				ANKI_ASSERT(m_set.m_vertBindings.get(binding) && "Forgot to set a vertex binding");
+
 				if(m_dirty.m_vertBindings.get(binding))
 				{
 					m_dirty.m_vertBindings.unset(binding);
@@ -77,33 +85,33 @@ Bool PipelineStateTracker::updateHashes()
 	}
 
 	// IA
-	if(!!(m_dirty.m_other & DirtyBit::IA))
+	if(m_dirty.m_inputAssembler)
 	{
-		m_dirty.m_other &= ~DirtyBit::IA;
-		m_hashes.m_ia = computeHash(&m_state.m_inputAssembler, sizeof(m_state.m_inputAssembler));
+		m_dirty.m_inputAssembler = false;
 		stateDirty = true;
+		m_hashes.m_ia = computeHash(&m_state.m_inputAssembler, sizeof(m_state.m_inputAssembler));
 	}
 
 	// Rasterizer
-	if(!!(m_dirty.m_other & DirtyBit::RASTER))
+	if(m_dirty.m_rasterizer)
 	{
-		m_dirty.m_other &= ~DirtyBit::RASTER;
+		m_dirty.m_rasterizer = false;
 		stateDirty = true;
 		m_hashes.m_raster = computeHash(&m_state.m_rasterizer, sizeof(m_state.m_rasterizer));
 	}
 
 	// Depth
-	if(m_fbDepth && !!(m_dirty.m_other & DirtyBit::DEPTH))
+	if(m_fbDepth && m_dirty.m_depth)
 	{
-		m_dirty.m_other &= ~DirtyBit::DEPTH;
+		m_dirty.m_depth = false;
 		stateDirty = true;
 		m_hashes.m_depth = computeHash(&m_state.m_depth, sizeof(m_state.m_depth));
 	}
 
 	// Stencil
-	if(m_fbStencil && !!(m_dirty.m_other & DirtyBit::STENCIL))
+	if(m_fbStencil && m_dirty.m_stencil)
 	{
-		m_dirty.m_other &= ~DirtyBit::STENCIL;
+		m_dirty.m_stencil = false;
 		stateDirty = true;
 		m_hashes.m_stencil = computeHash(&m_state.m_stencil, sizeof(m_state.m_stencil));
 	}
@@ -114,9 +122,9 @@ Bool PipelineStateTracker::updateHashes()
 		ANKI_ASSERT(m_fbColorAttachmentMask == m_shaderColorAttachmentWritemask
 					&& "Shader and fb should have same attachment mask");
 
-		if(!!(m_dirty.m_other & DirtyBit::COLOR))
+		if(m_dirty.m_color)
 		{
-			m_dirty.m_other &= ~DirtyBit::COLOR;
+			m_dirty.m_color = false;
 			m_hashes.m_color = m_state.m_color.m_alphaToCoverageEnabled ? 1 : 2;
 			stateDirty = true;
 		}
@@ -147,6 +155,9 @@ void PipelineStateTracker::updateSuperHash()
 	// Prog
 	buff[count++] = m_hashes.m_prog;
 
+	// Rpass
+	buff[count++] = m_hashes.m_rpass;
+
 	// Vertex
 	if(!!m_shaderAttributeMask)
 	{
@@ -343,7 +354,7 @@ const VkGraphicsPipelineCreateInfo& PipelineStateTracker::updatePipelineCreateIn
 		{
 			ANKI_ASSERT(m_shaderColorAttachmentWritemask.get(i) && "No gaps are allowed");
 			VkPipelineColorBlendAttachmentState& out = m_ci.m_colAttachments[i];
-			const PPColorAttachmentStateInfo& in = m_state.m_color.m_attachments[i];
+			const ColorAttachmentState& in = m_state.m_color.m_attachments[i];
 
 			out.blendEnable = !blendingDisabled(in.m_srcBlendFactorRgb, in.m_dstBlendFactorRgb, in.m_srcBlendFactorA,
 												in.m_dstBlendFactorA, in.m_blendFunctionRgb, in.m_blendFunctionA);
@@ -377,7 +388,7 @@ const VkGraphicsPipelineCreateInfo& PipelineStateTracker::updatePipelineCreateIn
 
 	// The rest
 	ci.layout = static_cast<const ShaderProgramImpl&>(*m_state.m_prog).getPipelineLayout().getHandle();
-	ci.renderPass = m_rpass;
+	ci.renderPass = m_state.m_rpass;
 	ci.subpass = 0;
 
 	return ci;
@@ -387,10 +398,6 @@ class PipelineFactory::PipelineInternal
 {
 public:
 	VkPipeline m_handle = VK_NULL_HANDLE;
-
-	/// The pipeline needs a render pass and the framebuffers are the owners of that. So the internal pipeline will
-	/// hold a ref to the FB in order to hold a ref to the render pass.
-	FramebufferPtr m_fb;
 };
 
 class PipelineFactory::Hasher
@@ -409,15 +416,16 @@ void PipelineFactory::destroy()
 		if(it.m_handle)
 		{
 			vkDestroyPipeline(m_dev, it.m_handle, nullptr);
-			it.m_fb.reset(nullptr);
 		}
 	}
 
 	m_pplines.destroy(m_alloc);
 }
 
-void PipelineFactory::newPipeline(PipelineStateTracker& state, Pipeline& ppline, Bool& stateDirty)
+void PipelineFactory::getOrCreatePipeline(PipelineStateTracker& state, Pipeline& ppline, Bool& stateDirty)
 {
+	ANKI_TRACE_SCOPED_EVENT(VK_PIPELINE_GET_OR_CREATE);
+
 	U64 hash;
 	state.flush(hash, stateDirty);
 
@@ -427,34 +435,47 @@ void PipelineFactory::newPipeline(PipelineStateTracker& state, Pipeline& ppline,
 		return;
 	}
 
-	LockGuard<SpinLock> lock(m_pplinesMtx);
+	// Check if ppline exists
+	{
+		RLockGuard<RWMutex> lock(m_pplinesMtx);
+		auto it = m_pplines.find(hash);
+		if(it != m_pplines.getEnd())
+		{
+			ppline.m_handle = (*it).m_handle;
+			ANKI_TRACE_INC_COUNTER(VK_PIPELINES_CACHE_HIT, 1);
+			return;
+		}
+	}
+
+	// Doesnt exist. Need to create it
 
+	WLockGuard<RWMutex> lock(m_pplinesMtx);
+
+	// Check again
 	auto it = m_pplines.find(hash);
 	if(it != m_pplines.getEnd())
 	{
 		ppline.m_handle = (*it).m_handle;
+		return;
 	}
-	else
-	{
-		PipelineInternal pp;
-		const VkGraphicsPipelineCreateInfo& ci = state.updatePipelineCreateInfo();
-		pp.m_fb = state.getFb();
 
-		{
-			ANKI_TRACE_SCOPED_EVENT(VK_PIPELINE_CREATE);
-			ANKI_VK_CHECKF(vkCreateGraphicsPipelines(m_dev, m_pplineCache, 1, &ci, nullptr, &pp.m_handle));
-		}
+	// Create it for real
+	PipelineInternal pp;
+	const VkGraphicsPipelineCreateInfo& ci = state.updatePipelineCreateInfo();
+
+	{
+		ANKI_TRACE_SCOPED_EVENT(VK_PIPELINE_CREATE);
+		ANKI_VK_CHECKF(vkCreateGraphicsPipelines(m_dev, m_pplineCache, 1, &ci, nullptr, &pp.m_handle));
+	}
 
-		ANKI_TRACE_INC_COUNTER(VK_PIPELINE_CREATE, 1);
+	ANKI_TRACE_INC_COUNTER(VK_PIPELINES_CACHE_MISS, 1);
 
-		m_pplines.emplace(m_alloc, hash, pp);
-		ppline.m_handle = pp.m_handle;
+	m_pplines.emplace(m_alloc, hash, pp);
+	ppline.m_handle = pp.m_handle;
 
-		// Print shader info
-		const ShaderProgramImpl& shaderImpl = static_cast<const ShaderProgramImpl&>(*state.m_state.m_prog);
-		shaderImpl.getGrManagerImpl().printPipelineShaderInfo(pp.m_handle, shaderImpl.getName(), shaderImpl.getStages(),
-															  hash);
-	}
+	// Print shader info
+	state.m_state.m_prog->getGrManagerImpl().printPipelineShaderInfo(pp.m_handle, state.m_state.m_prog->getName(),
+																	 state.m_state.m_prog->getStages(), hash);
 }
 
 } // end namespace anki

+ 99 - 127
AnKi/Gr/Vulkan/Pipeline.h

@@ -18,86 +18,85 @@ namespace anki
 /// @addtogroup vulkan
 /// @{
 
-/// @note Non copyable because that complicates the hashing.
-class PPVertexBufferBinding
+class VertexBufferBindingPipelineState
 {
 public:
 	U32 m_stride = MAX_U32; ///< Vertex stride.
 	VertexStepRate m_stepRate = VertexStepRate::VERTEX;
+	Array<U8, 3> m_padding = {};
 
-	Bool operator==(const PPVertexBufferBinding& b) const
+	Bool operator==(const VertexBufferBindingPipelineState& b) const
 	{
 		return m_stride == b.m_stride && m_stepRate == b.m_stepRate;
 	}
 
-	Bool operator!=(const PPVertexBufferBinding& b) const
+	Bool operator!=(const VertexBufferBindingPipelineState& b) const
 	{
 		return !(*this == b);
 	}
 };
+static_assert(sizeof(VertexBufferBindingPipelineState) == 2 * sizeof(U32), "Packed because it will be hashed");
 
-class PPVertexAttributeBinding
+class VertexAttributeBindingPipelineState
 {
 public:
 	PtrSize m_offset = 0;
 	Format m_format = Format::NONE;
 	U8 m_binding = 0;
+	Array<U8, 3> m_padding = {};
 
-	Bool operator==(const PPVertexAttributeBinding& b) const
+	Bool operator==(const VertexAttributeBindingPipelineState& b) const
 	{
 		return m_format == b.m_format && m_offset == b.m_offset && m_binding == b.m_binding;
 	}
 
-	Bool operator!=(const PPVertexAttributeBinding& b) const
+	Bool operator!=(const VertexAttributeBindingPipelineState& b) const
 	{
 		return !(*this == b);
 	}
 };
+static_assert(sizeof(VertexAttributeBindingPipelineState) == 2 * sizeof(PtrSize), "Packed because it will be hashed");
 
-class PPVertexStateInfo
+class VertexPipelineState
 {
 public:
-	Array<PPVertexBufferBinding, MAX_VERTEX_ATTRIBUTES> m_bindings;
-	Array<PPVertexAttributeBinding, MAX_VERTEX_ATTRIBUTES> m_attributes;
+	Array<VertexBufferBindingPipelineState, MAX_VERTEX_ATTRIBUTES> m_bindings;
+	Array<VertexAttributeBindingPipelineState, MAX_VERTEX_ATTRIBUTES> m_attributes;
 };
+static_assert(sizeof(VertexPipelineState)
+				  == sizeof(VertexBufferBindingPipelineState) * MAX_VERTEX_ATTRIBUTES
+						 + sizeof(VertexAttributeBindingPipelineState) * MAX_VERTEX_ATTRIBUTES,
+			  "Packed because it will be hashed");
 
-class PPInputAssemblerStateInfo
+class InputAssemblerPipelineState
 {
 public:
 	PrimitiveTopology m_topology = PrimitiveTopology::TRIANGLES;
 	Bool m_primitiveRestartEnabled = false;
 };
+static_assert(sizeof(InputAssemblerPipelineState) == sizeof(U8) * 2, "Packed because it will be hashed");
 
-class PPTessellationStateInfo
-{
-public:
-	U32 m_patchControlPointCount = 3;
-};
-
-class PPViewportStateInfo
-{
-public:
-	Bool m_scissorEnabled = false;
-};
-
-class PPRasterizerStateInfo
+class RasterizerPipelineState
 {
 public:
 	FillMode m_fillMode = FillMode::SOLID;
 	FaceSelectionBit m_cullMode = FaceSelectionBit::BACK;
 	RasterizationOrder m_rasterizationOrder = RasterizationOrder::ORDERED;
+	U8 m_padding = 0;
 	F32 m_depthBiasConstantFactor = 0.0f;
 	F32 m_depthBiasSlopeFactor = 0.0f;
 };
+static_assert(sizeof(RasterizerPipelineState) == sizeof(U32) * 3, "Packed because it will be hashed");
 
-class PPDepthStateInfo
+class DepthPipelineState
 {
 public:
 	Bool m_depthWriteEnabled = true;
 	CompareOperation m_depthCompareFunction = CompareOperation::LESS;
 };
+static_assert(sizeof(DepthPipelineState) == sizeof(U8) * 2, "Packed because it will be hashed");
 
-class PPStencilStateInfo
+class StencilPipelineState
 {
 public:
 	class S
@@ -111,8 +110,9 @@ public:
 
 	Array<S, 2> m_face;
 };
+static_assert(sizeof(StencilPipelineState) == sizeof(U32) * 2, "Packed because it will be hashed");
 
-class PPColorAttachmentStateInfo
+class ColorAttachmentState
 {
 public:
 	BlendFactor m_srcBlendFactorRgb = BlendFactor::ONE;
@@ -123,53 +123,33 @@ public:
 	BlendOperation m_blendFunctionA = BlendOperation::ADD;
 	ColorBit m_channelWriteMask = ColorBit::ALL;
 };
+static_assert(sizeof(ColorAttachmentState) == sizeof(U8) * 7, "Packed because it will be hashed");
 
-class PPColorStateInfo
+class ColorPipelineState
 {
 public:
 	Bool m_alphaToCoverageEnabled = false;
-	Array<PPColorAttachmentStateInfo, MAX_COLOR_ATTACHMENTS> m_attachments;
+	Array<ColorAttachmentState, MAX_COLOR_ATTACHMENTS> m_attachments;
 };
+static_assert(sizeof(ColorPipelineState) == sizeof(ColorAttachmentState) * MAX_COLOR_ATTACHMENTS + sizeof(U8),
+			  "Packed because it will be hashed");
 
-class PipelineInfoState
+class AllPipelineState
 {
 public:
-	PipelineInfoState()
-	{
-		reset();
-	}
+	const ShaderProgramImpl* m_prog = nullptr;
+	VkRenderPass m_rpass = VK_NULL_HANDLE;
 
-	ShaderProgramPtr m_prog;
-	PPVertexStateInfo m_vertex;
-	PPInputAssemblerStateInfo m_inputAssembler;
-	PPTessellationStateInfo m_tessellation;
-	PPViewportStateInfo m_viewport;
-	PPRasterizerStateInfo m_rasterizer;
-	PPDepthStateInfo m_depth;
-	PPStencilStateInfo m_stencil;
-	PPColorStateInfo m_color;
+	VertexPipelineState m_vertex;
+	InputAssemblerPipelineState m_inputAssembler;
+	RasterizerPipelineState m_rasterizer;
+	DepthPipelineState m_depth;
+	StencilPipelineState m_stencil;
+	ColorPipelineState m_color;
 
 	void reset()
 	{
-		m_prog.reset(nullptr);
-
-		// Do a special construction. The state will be hashed and the padding may contain garbage. With this trick
-		// zero the padding
-		zeroMemory(*this);
-
-#define ANKI_CONSTRUCT_AND_ZERO_PADDING(memb_) new(&memb_) decltype(memb_)()
-
-		ANKI_CONSTRUCT_AND_ZERO_PADDING(m_prog);
-		ANKI_CONSTRUCT_AND_ZERO_PADDING(m_vertex);
-		ANKI_CONSTRUCT_AND_ZERO_PADDING(m_inputAssembler);
-		ANKI_CONSTRUCT_AND_ZERO_PADDING(m_tessellation);
-		ANKI_CONSTRUCT_AND_ZERO_PADDING(m_viewport);
-		ANKI_CONSTRUCT_AND_ZERO_PADDING(m_rasterizer);
-		ANKI_CONSTRUCT_AND_ZERO_PADDING(m_depth);
-		ANKI_CONSTRUCT_AND_ZERO_PADDING(m_stencil);
-		ANKI_CONSTRUCT_AND_ZERO_PADDING(m_color);
-
-#undef ANKI_CONSTRUCT_AND_ZERO_PADDING
+		::new(this) AllPipelineState();
 	}
 };
 
@@ -189,13 +169,12 @@ public:
 
 	void bindVertexBuffer(U32 binding, PtrSize stride, VertexStepRate stepRate)
 	{
-		PPVertexBufferBinding b;
+		VertexBufferBindingPipelineState b;
 		b.m_stride = U32(stride);
 		b.m_stepRate = stepRate;
 		if(m_state.m_vertex.m_bindings[binding] != b)
 		{
-			m_state.m_vertex.m_bindings[binding].m_stride = b.m_stride;
-			m_state.m_vertex.m_bindings[binding].m_stepRate = b.m_stepRate;
+			m_state.m_vertex.m_bindings[binding] = b;
 			m_dirty.m_vertBindings.set(binding);
 		}
 		m_set.m_vertBindings.set(binding);
@@ -203,15 +182,13 @@ public:
 
 	void setVertexAttribute(U32 location, U32 buffBinding, const Format fmt, PtrSize relativeOffset)
 	{
-		PPVertexAttributeBinding b;
+		VertexAttributeBindingPipelineState b;
 		b.m_binding = U8(buffBinding);
 		b.m_format = fmt;
 		b.m_offset = relativeOffset;
 		if(m_state.m_vertex.m_attributes[location] != b)
 		{
-			m_state.m_vertex.m_attributes[location].m_binding = U8(buffBinding);
-			m_state.m_vertex.m_attributes[location].m_format = fmt;
-			m_state.m_vertex.m_attributes[location].m_offset = relativeOffset;
+			m_state.m_vertex.m_attributes[location] = b;
 			m_dirty.m_attribs.set(location);
 		}
 		m_set.m_attribs.set(location);
@@ -222,7 +199,7 @@ public:
 		if(m_state.m_inputAssembler.m_primitiveRestartEnabled != enable)
 		{
 			m_state.m_inputAssembler.m_primitiveRestartEnabled = enable;
-			m_dirty.m_other |= DirtyBit::IA;
+			m_dirty.m_inputAssembler = true;
 		}
 	}
 
@@ -231,7 +208,7 @@ public:
 		if(m_state.m_rasterizer.m_fillMode != mode)
 		{
 			m_state.m_rasterizer.m_fillMode = mode;
-			m_dirty.m_other |= DirtyBit::RASTER;
+			m_dirty.m_rasterizer = true;
 		}
 	}
 
@@ -240,7 +217,7 @@ public:
 		if(m_state.m_rasterizer.m_cullMode != mode)
 		{
 			m_state.m_rasterizer.m_cullMode = mode;
-			m_dirty.m_other |= DirtyBit::RASTER;
+			m_dirty.m_rasterizer = true;
 		}
 	}
 
@@ -251,7 +228,7 @@ public:
 		{
 			m_state.m_rasterizer.m_depthBiasConstantFactor = factor;
 			m_state.m_rasterizer.m_depthBiasSlopeFactor = units;
-			m_dirty.m_other |= DirtyBit::RASTER;
+			m_dirty.m_rasterizer = true;
 		}
 	}
 
@@ -260,7 +237,7 @@ public:
 		if(m_state.m_rasterizer.m_rasterizationOrder != order)
 		{
 			m_state.m_rasterizer.m_rasterizationOrder = order;
-			m_dirty.m_other |= DirtyBit::RASTER;
+			m_dirty.m_rasterizer = true;
 		}
 	}
 
@@ -275,7 +252,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_other |= DirtyBit::STENCIL;
+			m_dirty.m_stencil = true;
 		}
 
 		if(!!(face & FaceSelectionBit::BACK)
@@ -286,7 +263,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_other |= DirtyBit::STENCIL;
+			m_dirty.m_stencil = true;
 		}
 	}
 
@@ -295,13 +272,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_other |= DirtyBit::STENCIL;
+			m_dirty.m_stencil = true;
 		}
 
 		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_other |= DirtyBit::STENCIL;
+			m_dirty.m_stencil = true;
 		}
 	}
 
@@ -310,7 +287,7 @@ public:
 		if(m_state.m_depth.m_depthWriteEnabled != enable)
 		{
 			m_state.m_depth.m_depthWriteEnabled = enable;
-			m_dirty.m_other |= DirtyBit::DEPTH;
+			m_dirty.m_depth = true;
 		}
 	}
 
@@ -319,7 +296,7 @@ public:
 		if(m_state.m_depth.m_depthCompareFunction != op)
 		{
 			m_state.m_depth.m_depthCompareFunction = op;
-			m_dirty.m_other |= DirtyBit::DEPTH;
+			m_dirty.m_depth = true;
 		}
 	}
 
@@ -328,7 +305,7 @@ public:
 		if(m_state.m_color.m_alphaToCoverageEnabled != enable)
 		{
 			m_state.m_color.m_alphaToCoverageEnabled = enable;
-			m_dirty.m_other |= DirtyBit::COLOR;
+			m_dirty.m_color = true;
 		}
 	}
 
@@ -343,7 +320,7 @@ public:
 
 	void setBlendFactors(U32 attachment, BlendFactor srcRgb, BlendFactor dstRgb, BlendFactor srcA, BlendFactor dstA)
 	{
-		PPColorAttachmentStateInfo& c = m_state.m_color.m_attachments[attachment];
+		ColorAttachmentState& c = m_state.m_color.m_attachments[attachment];
 		if(c.m_srcBlendFactorRgb != srcRgb || c.m_dstBlendFactorRgb != dstRgb || c.m_srcBlendFactorA != srcA
 		   || c.m_dstBlendFactorA != dstA)
 		{
@@ -357,7 +334,7 @@ public:
 
 	void setBlendOperation(U32 attachment, BlendOperation funcRgb, BlendOperation funcA)
 	{
-		PPColorAttachmentStateInfo& c = m_state.m_color.m_attachments[attachment];
+		ColorAttachmentState& c = m_state.m_color.m_attachments[attachment];
 		if(c.m_blendFunctionRgb != funcRgb || c.m_blendFunctionA != funcA)
 		{
 			c.m_blendFunctionRgb = funcRgb;
@@ -366,36 +343,34 @@ public:
 		}
 	}
 
-	void bindShaderProgram(const ShaderProgramPtr& prog)
+	void bindShaderProgram(const ShaderProgramImpl* prog)
 	{
 		if(prog != m_state.m_prog)
 		{
-			const ShaderProgramImpl& impl = static_cast<const ShaderProgramImpl&>(*prog);
-			m_shaderColorAttachmentWritemask = impl.getReflectionInfo().m_colorAttachmentWritemask;
-			m_shaderAttributeMask = impl.getReflectionInfo().m_attributeMask;
+			m_shaderColorAttachmentWritemask = prog->getReflectionInfo().m_colorAttachmentWritemask;
+			m_shaderAttributeMask = prog->getReflectionInfo().m_attributeMask;
 			m_state.m_prog = prog;
-			m_dirty.m_other |= DirtyBit::PROG;
+			m_dirty.m_prog = true;
 		}
 	}
 
-	void beginRenderPass(const FramebufferPtr& fb)
+	void beginRenderPass(const FramebufferImpl* fb)
 	{
-		ANKI_ASSERT(m_rpass == VK_NULL_HANDLE);
+		ANKI_ASSERT(m_state.m_rpass == VK_NULL_HANDLE);
 		Bool d, s;
-		const FramebufferImpl& fbimpl = static_cast<const FramebufferImpl&>(*fb);
-		fbimpl.getAttachmentInfo(m_fbColorAttachmentMask, d, s);
+		fb->getAttachmentInfo(m_fbColorAttachmentMask, d, s);
 		m_fbDepth = d;
 		m_fbStencil = s;
-		m_rpass = fbimpl.getCompatibleRenderPass();
-		m_defaultFb = fbimpl.hasPresentableTexture();
-		m_fb = fb;
+		m_defaultFb = fb->hasPresentableTexture();
+
+		m_state.m_rpass = fb->getCompatibleRenderPass();
+		m_dirty.m_rpass = true;
 	}
 
 	void endRenderPass()
 	{
-		ANKI_ASSERT(m_rpass);
-		m_rpass = VK_NULL_HANDLE;
-		m_fb.reset(nullptr);
+		ANKI_ASSERT(m_state.m_rpass);
+		m_state.m_rpass = VK_NULL_HANDLE;
 	}
 
 	void setPrimitiveTopology(PrimitiveTopology topology)
@@ -403,7 +378,7 @@ public:
 		if(m_state.m_inputAssembler.m_topology != topology)
 		{
 			m_state.m_inputAssembler.m_topology = topology;
-			m_dirty.m_other |= DirtyBit::IA;
+			m_dirty.m_inputAssembler = true;
 		}
 	}
 
@@ -415,7 +390,7 @@ public:
 	/// Flush state
 	void flush(U64& pipelineHash, Bool& stateDirty)
 	{
-		Bool dirtyHashes = updateHashes();
+		const Bool dirtyHashes = updateHashes();
 		if(dirtyHashes)
 		{
 			updateSuperHash();
@@ -438,40 +413,38 @@ public:
 	/// Populate the internal pipeline create info structure.
 	const VkGraphicsPipelineCreateInfo& updatePipelineCreateInfo();
 
-	FramebufferPtr getFb() const
-	{
-		ANKI_ASSERT(m_fb.isCreated());
-		return m_fb;
-	}
-
 	void reset();
 
 private:
-	PipelineInfoState m_state;
-
-	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_FRIEND(DirtyBit)
+	AllPipelineState m_state;
 
 	class DirtyBits
 	{
 	public:
-		DirtyBit m_other = DirtyBit::ALL;
-
+		Bool m_prog : 1;
+		Bool m_rpass : 1;
+		Bool m_inputAssembler : 1;
+		Bool m_rasterizer : 1;
+		Bool m_depth : 1;
+		Bool m_stencil : 1;
+		Bool m_color : 1;
+
+		// Vertex
 		BitSet<MAX_VERTEX_ATTRIBUTES, U8> m_attribs = {true};
 		BitSet<MAX_VERTEX_ATTRIBUTES, U8> m_vertBindings = {true};
 
 		BitSet<MAX_COLOR_ATTACHMENTS, U8> m_colAttachments = {true};
+
+		DirtyBits()
+			: m_prog(true)
+			, m_rpass(true)
+			, m_inputAssembler(true)
+			, m_rasterizer(true)
+			, m_depth(true)
+			, m_stencil(true)
+			, m_color(true)
+		{
+		}
 	} m_dirty;
 
 	class SetBits
@@ -486,8 +459,6 @@ private:
 	BitSet<MAX_COLOR_ATTACHMENTS, U8> m_shaderColorAttachmentWritemask = {false};
 
 	// Renderpass info
-	VkRenderPass m_rpass = VK_NULL_HANDLE;
-	FramebufferPtr m_fb; ///< Hold the reference.
 	Bool m_fbDepth = false;
 	Bool m_fbStencil = false;
 	Bool m_defaultFb = false;
@@ -497,6 +468,7 @@ private:
 	{
 	public:
 		U64 m_prog;
+		U64 m_rpass;
 		Array<U64, MAX_VERTEX_ATTRIBUTES> m_vertexAttribs;
 		U64 m_ia;
 		U64 m_raster;
@@ -576,7 +548,7 @@ public:
 	void destroy();
 
 	/// @note Thread-safe.
-	void newPipeline(PipelineStateTracker& state, Pipeline& ppline, Bool& stateDirty);
+	void getOrCreatePipeline(PipelineStateTracker& state, Pipeline& ppline, Bool& stateDirty);
 
 private:
 	class PipelineInternal;
@@ -587,7 +559,7 @@ private:
 	VkPipelineCache m_pplineCache = VK_NULL_HANDLE;
 
 	HashMap<U64, PipelineInternal, Hasher> m_pplines;
-	SpinLock m_pplinesMtx;
+	RWMutex m_pplinesMtx;
 };
 /// @}
 

+ 1 - 0
AnKi/Importer/ImageImporter.cpp

@@ -426,6 +426,7 @@ static ANKI_USE_RESULT Error compressAstc(GenericMemoryPoolAllocator<U8> alloc,
 										  U32 inHeight, UVec2 blockSize, WeakArray<U8, PtrSize> outPixels)
 {
 	const PtrSize blockBytes = 16;
+	(void)blockBytes;
 	const PtrSize channelCount = 4;
 	ANKI_ASSERT(inPixels.getSizeInBytes() == PtrSize(inWidth) * inHeight * channelCount);
 	ANKI_ASSERT(inWidth > 0 && isPowerOfTwo(inWidth) && inHeight > 0 && isPowerOfTwo(inHeight));