Browse Source

Vulkan: Refactoring and more bug fixes

Panagiotis Christopoulos Charitos 9 years ago
parent
commit
02762daef7

+ 1 - 2
shaders/Dbg.frag.glsl

@@ -6,8 +6,7 @@
 #include "shaders/Common.glsl"
 
 layout(location = 0) in vec4 in_color;
-
-out vec4 out_color;
+layout(location = 0) out vec4 out_color;
 
 void main()
 {

+ 3 - 0
src/anki/gr/CommandBuffer.h

@@ -285,6 +285,9 @@ public:
 	/// @name Other
 	/// @{
 
+	/// Reset query before beginOcclusionQuery.
+	void resetOcclusionQuery(OcclusionQueryPtr query);
+
 	/// Begin query.
 	void beginOcclusionQuery(OcclusionQueryPtr query);
 

+ 6 - 0
src/anki/gr/gl/CommandBuffer.cpp

@@ -286,6 +286,12 @@ void CommandBuffer::dispatchCompute(
 	m_impl->dispatchCompute(groupCountX, groupCountY, groupCountZ);
 }
 
+//==============================================================================
+void CommandBuffer::resetOcclusionQuery(OcclusionQueryPtr query)
+{
+	// Nothing for GL
+}
+
 //==============================================================================
 class OqBeginCommand final : public GlCommand
 {

+ 6 - 0
src/anki/gr/vulkan/CommandBuffer.cpp

@@ -239,6 +239,12 @@ void CommandBuffer::setBufferBarrier(
 {
 }
 
+//==============================================================================
+void CommandBuffer::resetOcclusionQuery(OcclusionQueryPtr query)
+{
+	m_impl->resetOcclusionQuery(query);
+}
+
 //==============================================================================
 void CommandBuffer::beginOcclusionQuery(OcclusionQueryPtr query)
 {

+ 5 - 3
src/anki/gr/vulkan/CommandBufferImpl.cpp

@@ -332,14 +332,16 @@ void CommandBufferImpl::generateMipmaps2d(TexturePtr tex, U face, U layer)
 			srcWidth > 0 && srcHeight > 0 && dstWidth > 0 && dstHeight > 0);
 
 		VkImageBlit blit;
-		blit.srcSubresource.aspectMask = impl.m_aspect;
+		blit.srcSubresource.aspectMask =
+			impl.m_aspect & (~VK_IMAGE_ASPECT_STENCIL_BIT);
 		blit.srcSubresource.baseArrayLayer = layer;
 		blit.srcSubresource.layerCount = 1;
 		blit.srcSubresource.mipLevel = i;
 		blit.srcOffsets[0] = {0, 0, 0};
 		blit.srcOffsets[1] = {srcWidth, srcHeight, 1};
 
-		blit.dstSubresource.aspectMask = impl.m_aspect;
+		blit.dstSubresource.aspectMask =
+			impl.m_aspect & (~VK_IMAGE_ASPECT_STENCIL_BIT);
 		blit.dstSubresource.baseArrayLayer = layer;
 		blit.dstSubresource.layerCount = 1;
 		blit.dstSubresource.mipLevel = i + 1;
@@ -355,7 +357,7 @@ void CommandBufferImpl::generateMipmaps2d(TexturePtr tex, U face, U layer)
 			VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
 			1,
 			&blit,
-			VK_FILTER_LINEAR);
+			(impl.m_depthStencil) ? VK_FILTER_NEAREST : VK_FILTER_LINEAR);
 	}
 
 	// Hold the reference

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

@@ -77,6 +77,8 @@ public:
 		vkCmdDispatch(m_handle, groupCountX, groupCountY, groupCountZ);
 	}
 
+	void resetOcclusionQuery(OcclusionQueryPtr query);
+
 	void beginOcclusionQuery(OcclusionQueryPtr query);
 
 	void endOcclusionQuery(OcclusionQueryPtr query);

+ 21 - 5
src/anki/gr/vulkan/CommandBufferImpl.inl.h

@@ -208,17 +208,32 @@ inline void CommandBufferImpl::drawElements(U32 count,
 		m_handle, count, instanceCount, firstIndex, baseVertex, baseInstance);
 }
 
+//==============================================================================
+inline void CommandBufferImpl::resetOcclusionQuery(OcclusionQueryPtr query)
+{
+	commandCommon();
+	flushBarriers();
+
+	VkQueryPool handle = query->getImplementation().m_handle.m_pool;
+	U32 idx = query->getImplementation().m_handle.m_queryIndex;
+	ANKI_ASSERT(handle);
+
+	vkCmdResetQueryPool(m_handle, handle, idx, 0);
+
+	m_queryList.pushBack(m_alloc, query);
+}
+
 //==============================================================================
 inline void CommandBufferImpl::beginOcclusionQuery(OcclusionQueryPtr query)
 {
 	commandCommon();
 	flushBarriers();
 
-	VkQueryPool handle = query->getImplementation().m_handle;
+	VkQueryPool handle = query->getImplementation().m_handle.m_pool;
+	U32 idx = query->getImplementation().m_handle.m_queryIndex;
 	ANKI_ASSERT(handle);
 
-	vkCmdResetQueryPool(m_handle, handle, 0, 0);
-	vkCmdBeginQuery(m_handle, handle, 0, 0);
+	vkCmdBeginQuery(m_handle, handle, idx, 0);
 
 	m_queryList.pushBack(m_alloc, query);
 }
@@ -228,10 +243,11 @@ inline void CommandBufferImpl::endOcclusionQuery(OcclusionQueryPtr query)
 {
 	commandCommon();
 
-	VkQueryPool handle = query->getImplementation().m_handle;
+	VkQueryPool handle = query->getImplementation().m_handle.m_pool;
+	U32 idx = query->getImplementation().m_handle.m_queryIndex;
 	ANKI_ASSERT(handle);
 
-	vkCmdEndQuery(m_handle, handle, 0);
+	vkCmdEndQuery(m_handle, handle, idx);
 
 	m_queryList.pushBack(m_alloc, query);
 }

+ 44 - 1
src/anki/gr/vulkan/GrManagerImpl.cpp

@@ -219,6 +219,33 @@ Error GrManagerImpl::initInternal(const GrManagerInitInfo& init)
 	m_texUploader = getAllocator().newInstance<TextureFallbackUploader>(this);
 	ANKI_CHECK(m_texUploader->init());
 
+	m_queryAlloc.init(getAllocator(), m_device);
+
+	// Set m_r8g8b8ImagesSupported
+	{
+		VkImageFormatProperties props = {};
+		VkResult res = vkGetPhysicalDeviceImageFormatProperties(
+			m_physicalDevice,
+			VK_FORMAT_R8G8B8_UNORM,
+			VK_IMAGE_TYPE_2D,
+			VK_IMAGE_TILING_OPTIMAL,
+			VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
+			0,
+			&props);
+
+		if(res == VK_ERROR_FORMAT_NOT_SUPPORTED)
+		{
+			ANKI_LOGI("R8G8B8 Images are not supported. Will workaround this");
+			m_r8g8b8ImagesSupported = false;
+		}
+		else
+		{
+			ANKI_ASSERT(res == VK_SUCCESS);
+			ANKI_LOGI("R8G8B8 Images are supported");
+			m_r8g8b8ImagesSupported = true;
+		}
+	}
+
 	return ErrorCode::NONE;
 }
 
@@ -647,9 +674,25 @@ VkRenderPass GrManagerImpl::getOrCreateCompatibleRenderPass(
 		for(U i = 0; i < init.m_color.m_attachmentCount; ++i)
 		{
 			// We only care about samples and format
+
+			// Workaround unsupported formats
+			VkFormat fmt;
+			if(init.m_color.m_attachments[i].m_format.m_components
+					== ComponentFormat::R8G8B8
+				&& !m_r8g8b8ImagesSupported)
+			{
+				PixelFormat newFmt = init.m_color.m_attachments[i].m_format;
+				newFmt.m_components = ComponentFormat::R8G8B8A8;
+				fmt = convertFormat(newFmt);
+			}
+			else
+			{
+				fmt = convertFormat(init.m_color.m_attachments[i].m_format);
+			}
+
 			VkAttachmentDescription& desc = attachmentDescriptions[i];
 			desc.format = (!init.m_color.m_drawsToDefaultFramebuffer)
-				? convertFormat(init.m_color.m_attachments[i].m_format)
+				? fmt
 				: m_surfaceFormat;
 			desc.samples = VK_SAMPLE_COUNT_1_BIT;
 			desc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;

+ 15 - 0
src/anki/gr/vulkan/GrManagerImpl.h

@@ -11,6 +11,7 @@
 #include <anki/gr/vulkan/Semaphore.h>
 #include <anki/gr/vulkan/Fence.h>
 #include <anki/gr/vulkan/TransientMemoryManager.h>
+#include <anki/gr/vulkan/QueryAllocator.h>
 #include <anki/util/HashMap.h>
 
 namespace anki
@@ -189,6 +190,16 @@ public:
 		return m_vendor;
 	}
 
+	QueryAllocator& getQueryAllocator()
+	{
+		return m_queryAlloc;
+	}
+
+	Bool r8g8b8ImagesSupported() const
+	{
+		return m_r8g8b8ImagesSupported;
+	}
+
 private:
 	GrManager* m_manager = nullptr;
 
@@ -288,6 +299,10 @@ private:
 
 	TextureFallbackUploader* m_texUploader = nullptr;
 
+	QueryAllocator m_queryAlloc;
+
+	Bool8 m_r8g8b8ImagesSupported = false;
+
 	ANKI_USE_RESULT Error initInternal(const GrManagerInitInfo& init);
 	ANKI_USE_RESULT Error initInstance(const GrManagerInitInfo& init);
 	ANKI_USE_RESULT Error initSurface(const GrManagerInitInfo& init);

+ 5 - 9
src/anki/gr/vulkan/OcclusionQueryImpl.cpp

@@ -4,6 +4,7 @@
 // http://www.anki3d.org/LICENSE
 
 #include <anki/gr/vulkan/OcclusionQueryImpl.h>
+#include <anki/gr/vulkan/GrManagerImpl.h>
 
 namespace anki
 {
@@ -13,7 +14,7 @@ OcclusionQueryImpl::~OcclusionQueryImpl()
 {
 	if(m_handle)
 	{
-		vkDestroyQueryPool(getDevice(), m_handle, nullptr);
+		getGrManagerImpl().getQueryAllocator().deleteQuery(m_handle);
 	}
 }
 
@@ -22,12 +23,7 @@ Error OcclusionQueryImpl::init(OcclusionQueryResultBit condRenderingBit)
 {
 	m_condRenderingBit = condRenderingBit;
 
-	VkQueryPoolCreateInfo ci = {};
-	ci.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
-	ci.queryType = VK_QUERY_TYPE_OCCLUSION;
-	ci.queryCount = 1;
-
-	ANKI_VK_CHECK(vkCreateQueryPool(getDevice(), &ci, nullptr, &m_handle));
+	ANKI_CHECK(getGrManagerImpl().getQueryAllocator().newQuery(m_handle));
 
 	return ErrorCode::NONE;
 }
@@ -41,8 +37,8 @@ OcclusionQueryResult OcclusionQueryImpl::getResult() const
 	VkResult res;
 	ANKI_VK_CHECKF(
 		res = vkGetQueryPoolResults(getDevice(),
-			m_handle,
-			0,
+			m_handle.m_pool,
+			m_handle.m_queryIndex,
 			1,
 			sizeof(out),
 			&out,

+ 2 - 1
src/anki/gr/vulkan/OcclusionQueryImpl.h

@@ -6,6 +6,7 @@
 #pragma once
 
 #include <anki/gr/vulkan/VulkanObject.h>
+#include <anki/gr/vulkan/QueryAllocator.h>
 
 namespace anki
 {
@@ -17,7 +18,7 @@ namespace anki
 class OcclusionQueryImpl : public VulkanObject
 {
 public:
-	VkQueryPool m_handle = VK_NULL_HANDLE;
+	QueryAllocationHandle m_handle;
 
 	OcclusionQueryImpl(GrManager* manager)
 		: VulkanObject(manager)

+ 113 - 0
src/anki/gr/vulkan/QueryAllocator.cpp

@@ -0,0 +1,113 @@
+// Copyright (C) 2009-2016, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <anki/gr/vulkan/QueryAllocator.h>
+
+namespace anki
+{
+
+//==============================================================================
+QueryAllocator::~QueryAllocator()
+{
+	if(!m_chunks.isEmpty())
+	{
+		ANKI_LOGW("Forgot the delete some queries");
+	}
+}
+
+//==============================================================================
+Error QueryAllocator::newQuery(QueryAllocationHandle& handle)
+{
+	ANKI_ASSERT(!handle);
+
+	LockGuard<Mutex> lock(m_mtx);
+
+	// Find a not-full chunk
+	Chunk* chunk = nullptr;
+	for(Chunk& c : m_chunks)
+	{
+		if(c.m_subAllocationCount < MAX_SUB_ALLOCATIONS_PER_QUERY_CHUNK)
+		{
+			// Found one
+
+			if(chunk == nullptr)
+			{
+				chunk = &c;
+			}
+			else if(c.m_subAllocationCount > chunk->m_subAllocationCount)
+			{
+				// To decrease fragmentation use the most full chunk
+				chunk = &c;
+			}
+		}
+	}
+
+	if(chunk == nullptr)
+	{
+		// Create new chunk
+		chunk = m_alloc.newInstance<Chunk>();
+
+		VkQueryPoolCreateInfo ci = {};
+		ci.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
+		ci.queryType = VK_QUERY_TYPE_OCCLUSION;
+		ci.queryCount = MAX_SUB_ALLOCATIONS_PER_QUERY_CHUNK;
+
+		ANKI_VK_CHECK(vkCreateQueryPool(m_dev, &ci, nullptr, &chunk->m_pool));
+		m_chunks.pushBack(chunk);
+	}
+
+	ANKI_ASSERT(chunk);
+
+	// Allocate from chunk
+	for(U i = 0; i < MAX_SUB_ALLOCATIONS_PER_QUERY_CHUNK; ++i)
+	{
+		if(chunk->m_allocatedMask.get(i) == 0)
+		{
+			chunk->m_allocatedMask.set(i);
+			++chunk->m_subAllocationCount;
+
+			handle.m_pool = chunk->m_pool;
+			handle.m_queryIndex = i;
+			handle.m_chunk = chunk;
+			break;
+		}
+	}
+
+	ANKI_ASSERT(handle == true);
+	return ErrorCode::NONE;
+}
+
+//==============================================================================
+void QueryAllocator::deleteQuery(QueryAllocationHandle& handle)
+{
+	ANKI_ASSERT(
+		handle.m_pool && handle.m_queryIndex != MAX_U32 && handle.m_chunk);
+
+	LockGuard<Mutex> lock(m_mtx);
+
+	Chunk* chunk = handle.m_chunk;
+	ANKI_ASSERT(chunk->m_subAllocationCount > 0);
+	--chunk->m_subAllocationCount;
+
+	if(chunk->m_subAllocationCount == 0)
+	{
+		// Delete the chunk
+
+		ANKI_ASSERT(chunk->m_allocatedMask.getAny());
+		vkDestroyQueryPool(m_dev, chunk->m_pool, nullptr);
+
+		m_chunks.erase(chunk);
+		m_alloc.deleteInstance(chunk);
+	}
+	else
+	{
+		ANKI_ASSERT(chunk->m_allocatedMask.get(handle.m_queryIndex));
+		chunk->m_allocatedMask.unset(handle.m_queryIndex);
+	}
+
+	handle = {};
+}
+
+} // end namespace anki

+ 82 - 0
src/anki/gr/vulkan/QueryAllocator.h

@@ -0,0 +1,82 @@
+// Copyright (C) 2009-2016, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <anki/gr/vulkan/Common.h>
+#include <anki/util/BitSet.h>
+#include <anki/util/List.h>
+
+namespace anki
+{
+
+// Forward
+class QueryAllocatorChunk;
+
+/// @addtogroup vulkan
+/// @{
+
+const U MAX_SUB_ALLOCATIONS_PER_QUERY_CHUNK = 64;
+
+/// The return handle of a query allocation.
+class QueryAllocationHandle
+{
+	friend class QueryAllocator;
+
+public:
+	VkQueryPool m_pool = VK_NULL_HANDLE;
+	U32 m_queryIndex = MAX_U32;
+
+	operator Bool() const
+	{
+		return m_pool != VK_NULL_HANDLE;
+	}
+
+private:
+	QueryAllocatorChunk* m_chunk = nullptr;
+};
+
+/// An allocation chunk.
+class QueryAllocatorChunk : public IntrusiveListEnabled<QueryAllocatorChunk>
+{
+	friend class QueryAllocator;
+
+private:
+	VkQueryPool m_pool = VK_NULL_HANDLE;
+	BitSet<MAX_SUB_ALLOCATIONS_PER_QUERY_CHUNK> m_allocatedMask = {false};
+	U32 m_subAllocationCount = 0;
+};
+
+/// Batch allocator of queries.
+class QueryAllocator
+{
+public:
+	QueryAllocator()
+	{
+	}
+
+	~QueryAllocator();
+
+	void init(GrAllocator<U8> alloc, VkDevice dev)
+	{
+		m_alloc = alloc;
+		m_dev = dev;
+	}
+
+	ANKI_USE_RESULT Error newQuery(QueryAllocationHandle& handle);
+
+	void deleteQuery(QueryAllocationHandle& handle);
+
+private:
+	using Chunk = QueryAllocatorChunk;
+
+	GrAllocator<U8> m_alloc;
+	VkDevice m_dev;
+	IntrusiveList<Chunk> m_chunks;
+	Mutex m_mtx;
+};
+/// @}
+
+} // end namespace anki

+ 0 - 1
src/anki/gr/vulkan/TransientMemoryManager.h

@@ -69,7 +69,6 @@ private:
 	{
 	public:
 		PtrSize m_size = 0;
-		GpuMemoryAllocationHandle m_handle;
 		BufferImpl* m_buff = nullptr;
 		U8* m_mappedMem = nullptr;
 		VkBuffer m_bufferHandle = VK_NULL_HANDLE; ///< Cache it.

+ 6 - 3
src/anki/math/Vec4.h

@@ -15,23 +15,26 @@ namespace anki
 
 /// Template struct that gives the type of the TVec4 SIMD
 template<typename T>
-struct TVec4Simd
+class TVec4Simd
 {
+public:
 	using Type = Array<T, 4>;
 };
 
 #if ANKI_SIMD == ANKI_SIMD_SSE
 // Specialize for F32
 template<>
-struct TVec4Simd<F32>
+class TVec4Simd<F32>
 {
+public:
 	using Type = __m128;
 };
 #elif ANKI_SIMD == ANKI_SIMD_NEON
 // Specialize for F32
 template<>
-struct TVec4Simd<F32>
+class TVec4Simd<F32>
 {
+public:
 	using Type = float32x4_t;
 };
 #endif

+ 38 - 1
src/anki/renderer/Lf.cpp

@@ -83,6 +83,7 @@ Error Lf::initSprite(const ConfigSet& config)
 	init.m_inputAssembler.m_topology = PrimitiveTopology::TRIANGLE_STRIP;
 	init.m_depthStencil.m_depthWriteEnabled = false;
 	init.m_depthStencil.m_depthCompareFunction = CompareOperation::ALWAYS;
+	init.m_depthStencil.m_format = MS_DEPTH_ATTACHMENT_PIXEL_FORMAT;
 	init.m_color.m_attachmentCount = 1;
 	init.m_color.m_attachments[0].m_format = IS_COLOR_ATTACHMENT_PIXEL_FORMAT;
 	init.m_color.m_attachments[0].m_srcBlendMethod = BlendMethod::ONE;
@@ -157,6 +158,41 @@ Error Lf::initInternal(const ConfigSet& config)
 	return ErrorCode::NONE;
 }
 
+//==============================================================================
+void Lf::resetOcclusionQueries(RenderingContext& ctx, CommandBufferPtr cmdb)
+{
+	const FrustumComponent& camFr = *ctx.m_frustumComponent;
+	const VisibilityTestResults& vi = camFr.getVisibilityTestResults();
+
+	if(vi.getCount(VisibilityGroupType::FLARES) > m_maxFlares)
+	{
+		ANKI_LOGW("Visible flares exceed the limit. Increase lf.maxFlares");
+	}
+
+	U totalCount =
+		min<U>(vi.getCount(VisibilityGroupType::FLARES), m_maxFlares);
+	U count = 0;
+	if(totalCount > 0)
+	{
+		ctx.m_lf.m_queriesToTest.create(totalCount);
+
+		auto it = vi.getBegin(VisibilityGroupType::FLARES);
+		auto end = vi.getBegin(VisibilityGroupType::FLARES) + totalCount;
+		for(; it != end; ++it)
+		{
+			LensFlareComponent& lf =
+				(it->m_node)->getComponent<LensFlareComponent>();
+
+			OcclusionQueryPtr query = lf.getOcclusionQueryToTest();
+			ctx.m_lf.m_queriesToTest[count++] = query;
+
+			cmdb->resetOcclusionQuery(query);
+		}
+	}
+
+	ANKI_ASSERT(count == totalCount);
+}
+
 //==============================================================================
 void Lf::runOcclusionTests(RenderingContext& ctx, CommandBufferPtr cmdb)
 {
@@ -171,6 +207,7 @@ void Lf::runOcclusionTests(RenderingContext& ctx, CommandBufferPtr cmdb)
 
 	U totalCount =
 		min<U>(vi.getCount(VisibilityGroupType::FLARES), m_maxFlares);
+	U count = 0;
 	if(totalCount > 0)
 	{
 		// Setup MVP UBO
@@ -205,7 +242,7 @@ void Lf::runOcclusionTests(RenderingContext& ctx, CommandBufferPtr cmdb)
 			*positions = lf.getWorldPosition().xyz();
 
 			// Draw and query
-			OcclusionQueryPtr& query = lf.getOcclusionQueryToTest();
+			OcclusionQueryPtr query = ctx.m_lf.m_queriesToTest[count++];
 			cmdb->beginOcclusionQuery(query);
 
 			cmdb->drawArrays(1, 1, positions - initialPositions);

+ 2 - 0
src/anki/renderer/Lf.h

@@ -29,6 +29,8 @@ anki_internal:
 
 	ANKI_USE_RESULT Error init(const ConfigSet& config);
 
+	void resetOcclusionQueries(RenderingContext& ctx, CommandBufferPtr cmdb);
+
 	void runOcclusionTests(RenderingContext& ctx, CommandBufferPtr cmdb);
 
 	void run(RenderingContext& ctx, CommandBufferPtr cmdb);

+ 2 - 0
src/anki/renderer/Renderer.cpp

@@ -241,6 +241,8 @@ Error Renderer::render(RenderingContext& ctx)
 	ANKI_CHECK(m_ir->run(ctx));
 
 	ANKI_CHECK(m_is->binLights(ctx));
+
+	m_lf->resetOcclusionQueries(ctx, cmdb);
 	ANKI_CHECK(buildCommandBuffers(ctx));
 
 	// Perform image transitions

+ 15 - 0
src/anki/renderer/Renderer.h

@@ -47,6 +47,20 @@ public:
 	} m_ms;
 	/// @}
 
+	/// @name LF
+	/// @{
+	class Lf
+	{
+	public:
+		DynamicArrayAuto<OcclusionQueryPtr> m_queriesToTest;
+
+		Lf(const StackAllocator<U8>& alloc)
+			: m_queriesToTest(alloc)
+		{
+		}
+	} m_lf;
+	/// @}
+
 	/// @name IS
 	/// @{
 	class Is
@@ -101,6 +115,7 @@ public:
 
 	RenderingContext(const StackAllocator<U8>& alloc)
 		: m_tempAllocator(alloc)
+		, m_lf(alloc)
 		, m_sm(alloc)
 	{
 	}

+ 1 - 0
src/anki/renderer/Sslf.cpp

@@ -38,6 +38,7 @@ Error Sslf::initInternal(const ConfigSet& config)
 
 	ColorStateInfo colorState;
 	colorState.m_attachmentCount = 1;
+	colorState.m_attachments[0].m_format = Bloom::RT_PIXEL_FORMAT;
 	colorState.m_attachments[0].m_srcBlendMethod = BlendMethod::ONE;
 	colorState.m_attachments[0].m_dstBlendMethod = BlendMethod::ONE;
 

+ 12 - 5
src/anki/renderer/Volumetric.cpp

@@ -24,12 +24,19 @@ Error Volumetric::init(const ConfigSet& config)
 		"shaders/Volumetric.frag.glsl", m_frag));
 
 	// Create ppline
-	ColorStateInfo colorState;
-	colorState.m_attachmentCount = 1;
-	colorState.m_attachments[0].m_srcBlendMethod = BlendMethod::ONE;
-	colorState.m_attachments[0].m_dstBlendMethod = BlendMethod::ONE;
+	PipelineInitInfo init;
+	init.m_inputAssembler.m_topology = PrimitiveTopology::TRIANGLE_STRIP;
+	init.m_depthStencil.m_depthWriteEnabled = false;
+	init.m_depthStencil.m_depthCompareFunction = CompareOperation::ALWAYS;
+	init.m_depthStencil.m_format = MS_DEPTH_ATTACHMENT_PIXEL_FORMAT;
+	init.m_color.m_attachmentCount = 1;
+	init.m_color.m_attachments[0].m_format = IS_COLOR_ATTACHMENT_PIXEL_FORMAT;
+	init.m_color.m_attachments[0].m_srcBlendMethod = BlendMethod::ONE;
+	init.m_color.m_attachments[0].m_dstBlendMethod = BlendMethod::ONE;
+	init.m_shaders[ShaderType::VERTEX] = m_r->getDrawQuadVertexShader();
+	init.m_shaders[ShaderType::FRAGMENT] = m_frag->getGrShader();
 
-	m_r->createDrawQuadPipeline(m_frag->getGrShader(), colorState, m_ppline);
+	m_ppline = getGrManager().newInstance<Pipeline>(init);
 
 	// Create the resource group
 	ResourceGroupInitInfo rcInit;