Browse Source

GR interface: Fix bugs

Panagiotis Christopoulos Charitos 9 years ago
parent
commit
3e23855c8a

+ 6 - 7
shaders/Is.frag.glsl

@@ -238,27 +238,26 @@ void main()
 #endif
 
 #if 0
-	out_color = diffCol;
-	uint count = scount;
+	count = scount;
 	if(count == 0)
 	{
-		out_color = vec3(1.0, 0.0, 0.0);
+		out_color = vec3(0.0, 0.0, 0.0);
 	}
 	else if(count == 1)
 	{
-		out_color = vec3(0.0, 1.0, 0.0);
+		out_color = vec3(1.0, 0.0, 0.0);
 	}
 	else if(count == 2)
 	{
-		out_color = vec3(0.0, 0.0, 1.0);
+		out_color = vec3(0.0, 1.0, 0.0);
 	}
 	else if(count == 3)
 	{
-		out_color = vec3(1.0, 0.0, 1.0);
+		out_color = vec3(0.0, 0.0, 1.0);
 	}
 	else
 	{
-		out_color = vec3(1.0, 1.0, 0.0);
+		out_color = vec3(1.0, 1.0, 1.0);
 	}
 #endif
 }

+ 1 - 1
src/anki/gr/Common.h

@@ -176,7 +176,7 @@ class TransientMemoryToken
 public:
 	operator Bool() const
 	{
-		return m_offset != 0;
+		return m_range != 0;
 	}
 
 	Bool operator==(const TransientMemoryToken& b) const

+ 51 - 36
src/anki/gr/gl/CommandBuffer.cpp

@@ -46,6 +46,11 @@ void CommandBuffer::init(CommandBufferInitInfo& inf)
 #if ANKI_ASSERTIONS
 	m_impl->m_state.m_secondLevel = !!(inf.m_flags & CommandBufferFlag::SECOND_LEVEL);
 #endif
+
+	if(!!(inf.m_flags & CommandBufferFlag::SECOND_LEVEL))
+	{
+		m_impl->m_state.m_fb = inf.m_framebuffer->m_impl.get();
+	}
 }
 
 void CommandBuffer::flush()
@@ -96,6 +101,9 @@ void CommandBuffer::bindVertexBuffer(U32 binding, BufferPtr buff, PtrSize offset
 		}
 	};
 
+	ANKI_ASSERT(buff);
+	ANKI_ASSERT(stride > 0);
+
 	if(m_impl->m_state.bindVertexBuffer(binding, buff, offset, stride))
 	{
 		m_impl->pushBackNewCommand<Cmd>(binding, buff, offset, stride);
@@ -127,12 +135,18 @@ void CommandBuffer::bindVertexBuffer(U32 binding, const TransientMemoryToken& to
 		}
 	};
 
-	ANKI_ASSERT(token.m_usage == BufferUsageBit::VERTEX);
-	GLuint name = getManager().getImplementation().getTransientMemoryManager().getGlName(token);
+	ANKI_ASSERT(token);
+	ANKI_ASSERT(stride > 0);
 
-	if(m_impl->m_state.bindVertexBuffer(binding, token, stride))
+	if(!token.isUnused())
 	{
-		m_impl->pushBackNewCommand<Cmd>(binding, token, stride, name);
+		ANKI_ASSERT(token.m_usage == BufferUsageBit::VERTEX);
+		GLuint name = getManager().getImplementation().getTransientMemoryManager().getGlName(token);
+
+		if(m_impl->m_state.bindVertexBuffer(binding, token, stride))
+		{
+			m_impl->pushBackNewCommand<Cmd>(binding, token, stride, name);
+		}
 	}
 }
 
@@ -197,6 +211,8 @@ void CommandBuffer::bindIndexBuffer(BufferPtr buff, PtrSize offset, IndexType ty
 		}
 	};
 
+	ANKI_ASSERT(buff);
+
 	if(m_impl->m_state.bindIndexBuffer(buff, offset, type))
 	{
 		m_impl->pushBackNewCommand<Cmd>(buff);
@@ -682,6 +698,8 @@ void CommandBuffer::bindUniformBuffer(U32 set, U32 binding, BufferPtr buff, PtrS
 		}
 	};
 
+	ANKI_ASSERT(buff);
+
 	if(m_impl->m_state.bindUniformBuffer(set, binding, buff, offset))
 	{
 		binding = binding + MAX_UNIFORM_BUFFER_BINDINGS * set;
@@ -712,13 +730,18 @@ void CommandBuffer::bindUniformBuffer(U32 set, U32 binding, const TransientMemor
 		}
 	};
 
-	ANKI_ASSERT(!!(token.m_usage & BufferUsageBit::UNIFORM_ALL));
+	ANKI_ASSERT(token);
 
-	if(m_impl->m_state.bindUniformBuffer(set, binding, token))
+	if(!token.isUnused())
 	{
-		binding = binding + MAX_UNIFORM_BUFFER_BINDINGS * set;
-		GLuint name = getManager().getImplementation().getTransientMemoryManager().getGlName(token);
-		m_impl->pushBackNewCommand<Cmd>(binding, token, name);
+		ANKI_ASSERT(!!(token.m_usage & BufferUsageBit::UNIFORM_ALL));
+
+		if(m_impl->m_state.bindUniformBuffer(set, binding, token))
+		{
+			binding = binding + MAX_UNIFORM_BUFFER_BINDINGS * set;
+			GLuint name = getManager().getImplementation().getTransientMemoryManager().getGlName(token);
+			m_impl->pushBackNewCommand<Cmd>(binding, token, name);
+		}
 	}
 }
 
@@ -745,6 +768,8 @@ void CommandBuffer::bindStorageBuffer(U32 set, U32 binding, BufferPtr buff, PtrS
 		}
 	};
 
+	ANKI_ASSERT(buff);
+
 	if(m_impl->m_state.bindStorageBuffer(set, binding, buff, offset))
 	{
 		binding = binding + MAX_STORAGE_BUFFER_BINDINGS * set;
@@ -775,13 +800,18 @@ void CommandBuffer::bindStorageBuffer(U32 set, U32 binding, const TransientMemor
 		}
 	};
 
-	ANKI_ASSERT(!!(token.m_usage & BufferUsageBit::STORAGE_ALL));
+	ANKI_ASSERT(token);
 
-	if(m_impl->m_state.bindStorageBuffer(set, binding, token))
+	if(!token.isUnused())
 	{
-		binding = binding + MAX_STORAGE_BUFFER_BINDINGS * set;
-		GLuint name = getManager().getImplementation().getTransientMemoryManager().getGlName(token);
-		m_impl->pushBackNewCommand<Cmd>(binding, token, name);
+		ANKI_ASSERT(!!(token.m_usage & BufferUsageBit::STORAGE_ALL));
+
+		if(m_impl->m_state.bindStorageBuffer(set, binding, token))
+		{
+			binding = binding + MAX_STORAGE_BUFFER_BINDINGS * set;
+			GLuint name = getManager().getImplementation().getTransientMemoryManager().getGlName(token);
+			m_impl->pushBackNewCommand<Cmd>(binding, token, name);
+		}
 	}
 }
 
@@ -814,6 +844,8 @@ void CommandBuffer::bindImage(U32 set, U32 binding, TexturePtr img, U32 level)
 		}
 	};
 
+	ANKI_ASSERT(img);
+
 	if(m_impl->m_state.bindImage(set, binding, img, level))
 	{
 		binding = binding + set * MAX_IMAGE_BINDINGS;
@@ -840,6 +872,8 @@ void CommandBuffer::bindShaderProgram(ShaderProgramPtr prog)
 		}
 	};
 
+	ANKI_ASSERT(prog);
+
 	if(m_impl->m_state.bindShaderProgram(prog))
 	{
 		m_impl->pushBackNewCommand<Cmd>(prog);
@@ -873,25 +907,6 @@ void CommandBuffer::beginRenderPass(FramebufferPtr fb)
 
 void CommandBuffer::endRenderPass()
 {
-// Restore state
-#if 0
-	if(m_impl->m_state.m_lastSecondLevelCmdb)
-	{
-		// Renderpass had 2nd level cmdbs, need to restore the state
-
-		const StateTracker& olds = m_impl->m_state.m_lastSecondLevelCmdb->m_state;
-		StateTracker& news = m_impl->m_state;
-
-		// Vertex state
-		class VertIndexStateCmd final : public GlCommand
-		{
-		public:
-			Array<StateTracker::VertexAttribute, MAX_VERTEX_ATTRIBUTES> m_attribs;
-			Array<StateTracker::VertexBuffer, MAX_VERTEX_ATTRIBUTES> m_vertBuffs;
-		};
-	}
-#endif
-
 	m_impl->m_state.endRenderPass();
 }
 
@@ -1173,7 +1188,7 @@ void CommandBuffer::uploadTextureSurface(
 	};
 
 	ANKI_ASSERT(tex);
-	ANKI_ASSERT(token.m_range > 0);
+	ANKI_ASSERT(token);
 	ANKI_ASSERT(!m_impl->m_state.insideRenderPass());
 
 	m_impl->pushBackNewCommand<TexSurfUploadCommand>(tex, surf, token);
@@ -1210,7 +1225,7 @@ void CommandBuffer::uploadTextureVolume(TexturePtr tex, const TextureVolumeInfo&
 	};
 
 	ANKI_ASSERT(tex);
-	ANKI_ASSERT(token.m_range > 0);
+	ANKI_ASSERT(token);
 	ANKI_ASSERT(!m_impl->m_state.insideRenderPass());
 
 	m_impl->pushBackNewCommand<TexVolUploadCommand>(tex, vol, token);
@@ -1246,7 +1261,7 @@ void CommandBuffer::uploadBuffer(BufferPtr buff, PtrSize offset, const Transient
 		}
 	};
 
-	ANKI_ASSERT(token.m_range > 0);
+	ANKI_ASSERT(token);
 	ANKI_ASSERT(buff);
 	ANKI_ASSERT(!m_impl->m_state.insideRenderPass());
 

+ 32 - 4
src/anki/gr/gl/CommandBufferImpl.cpp

@@ -189,7 +189,7 @@ void CommandBufferImpl::flushDrawcall(CommandBuffer& cmdb)
 	//
 	// Fire commands to change some state
 	//
-	class Cmd final : public GlCommand
+	class StencilCmd final : public GlCommand
 	{
 	public:
 		GLenum m_face;
@@ -197,7 +197,7 @@ void CommandBufferImpl::flushDrawcall(CommandBuffer& cmdb)
 		GLint m_ref;
 		GLuint m_compareMask;
 
-		Cmd(GLenum face, GLenum func, GLint ref, GLuint mask)
+		StencilCmd(GLenum face, GLenum func, GLint ref, GLuint mask)
 			: m_face(face)
 			, m_func(func)
 			, m_ref(ref)
@@ -212,12 +212,11 @@ void CommandBufferImpl::flushDrawcall(CommandBuffer& cmdb)
 		}
 	};
 
-	const Array<GLenum, 2> FACE = {{GL_FRONT, GL_BACK}};
 	for(U i = 0; i < 2; ++i)
 	{
 		if(m_state.m_glStencilFuncSeparateDirty[i])
 		{
-			pushBackNewCommand<Cmd>(FACE[i],
+			pushBackNewCommand<StencilCmd>(GL_FRONT + i,
 				convertCompareOperation(m_state.m_stencilCompare[i]),
 				m_state.m_stencilRef[i],
 				m_state.m_stencilCompareMask[i]);
@@ -283,6 +282,35 @@ void CommandBufferImpl::flushDrawcall(CommandBuffer& cmdb)
 	{
 		pushBackNewCommand<StencilTestCmd>(m_state.m_stencilTestEnabled);
 	}
+
+	class BlendCmd final : public GlCommand
+	{
+	public:
+		Bool8 m_enable;
+
+		BlendCmd(Bool enable)
+			: m_enable(enable)
+		{
+		}
+
+		Error operator()(GlState&)
+		{
+			if(m_enable)
+			{
+				glEnable(GL_BLEND);
+			}
+			else
+			{
+				glDisable(GL_BLEND);
+			}
+			return ErrorCode::NONE;
+		}
+	};
+
+	if(m_state.maybeEnableBlend())
+	{
+		pushBackNewCommand<BlendCmd>(m_state.m_enableBlend);
+	}
 }
 
 } // end namespace anki

+ 1 - 0
src/anki/gr/gl/GlState.cpp

@@ -129,6 +129,7 @@ void GlState::initRenderThread()
 	// Set some GL state
 	glEnable(GL_PROGRAM_POINT_SIZE);
 	glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
+	glEnable(GL_CULL_FACE);
 
 	// Create default VAO
 	glGenVertexArrays(1, &m_defaultVao);

+ 63 - 29
src/anki/gr/gl/StateTracker.h

@@ -61,7 +61,7 @@ public:
 	class VertexBuffer
 	{
 	public:
-		BufferPtr m_buff;
+		BufferImpl* m_buff = nullptr;
 		PtrSize m_offset = 0;
 		PtrSize m_stride = 0;
 		TransientMemoryToken m_token;
@@ -72,7 +72,7 @@ public:
 	Bool bindVertexBuffer(U32 binding, BufferPtr buff, PtrSize offset, PtrSize stride)
 	{
 		VertexBuffer& b = m_vertBuffs[binding];
-		b.m_buff = buff;
+		b.m_buff = buff->m_impl.get();
 		b.m_offset = offset;
 		b.m_stride = stride;
 		b.m_token = {};
@@ -82,7 +82,7 @@ public:
 	Bool bindVertexBuffer(U32 binding, const TransientMemoryToken& token, PtrSize stride)
 	{
 		VertexBuffer& b = m_vertBuffs[binding];
-		b.m_buff = {};
+		b.m_buff = nullptr;
 		b.m_offset = 0;
 		b.m_stride = stride;
 		b.m_token = token;
@@ -92,14 +92,14 @@ public:
 	class Index
 	{
 	public:
-		BufferPtr m_buff;
+		BufferImpl* m_buff = nullptr;
 		PtrSize m_offset = MAX_PTR_SIZE;
 		GLenum m_indexType = 0;
 	} m_idx;
 
 	Bool bindIndexBuffer(BufferPtr buff, PtrSize offset, IndexType type)
 	{
-		m_idx.m_buff = buff;
+		m_idx.m_buff = buff->m_impl.get();
 		m_idx.m_offset = offset;
 		m_idx.m_indexType = convertIndexType(type);
 		return true;
@@ -108,7 +108,7 @@ public:
 
 	/// @name input_assembly
 	/// @{
-	U8 m_primitiveRestart = 2;
+	Bool8 m_primitiveRestart = 2;
 
 	Bool setPrimitiveRestart(Bool enable)
 	{
@@ -316,7 +316,7 @@ public:
 
 	Bool maybeEnableDepthTest()
 	{
-		ANKI_ASSERT(m_depthWrite != 2 && m_depthOp != CompareOperation::COUNT);
+		ANKI_ASSERT(m_depthWrite <= 1 && m_depthOp != CompareOperation::COUNT);
 		Bool enable = m_depthWrite || m_depthOp != CompareOperation::ALWAYS;
 
 		if(enable != m_depthTestEnabled)
@@ -369,17 +369,43 @@ public:
 		return false;
 	}
 
+	Bool8 m_enableBlend = 2;
+
+	Bool maybeEnableBlend()
+	{
+		Bool8 enable = 0;
+
+		for(U i = 0; i < m_fb->getColorBufferCount(); ++i)
+		{
+			if(!!(m_colorWriteMasks[i]) && (m_enableBlendMask & (1 << i)))
+			{
+				enable = enable || 1;
+			}
+		}
+
+		if(enable != m_enableBlend)
+		{
+			m_enableBlend = enable;
+			return true;
+		}
+		return false;
+	}
+
 	Array<BlendMethod, MAX_COLOR_ATTACHMENTS> m_blendSrcMethod = {
 		{BlendMethod::COUNT, BlendMethod::COUNT, BlendMethod::COUNT, BlendMethod::COUNT}};
 	Array<BlendMethod, MAX_COLOR_ATTACHMENTS> m_blendDstMethod = {
 		{BlendMethod::COUNT, BlendMethod::COUNT, BlendMethod::COUNT, BlendMethod::COUNT}};
 
+	U8 m_enableBlendMask = 0; ///< Per attachment
+
 	Bool setBlendMethods(U32 attachment, BlendMethod src, BlendMethod dst)
 	{
 		if(m_blendSrcMethod[attachment] != src || m_blendDstMethod[attachment] != dst)
 		{
 			m_blendSrcMethod[attachment] = src;
 			m_blendDstMethod[attachment] = dst;
+			Bool wantBlend = !(src == BlendMethod::ONE && dst == BlendMethod::ZERO);
+			m_enableBlendMask |= (wantBlend) ? (1 << attachment) : 0;
 			return true;
 		}
 		return false;
@@ -404,8 +430,8 @@ public:
 	class TextureBinding
 	{
 	public:
-		TexturePtr m_tex;
-		SamplerPtr m_sampler;
+		TextureImpl* m_tex = nullptr;
+		SamplerImpl* m_sampler = nullptr;
 		DepthStencilAspectMask m_aspect;
 	};
 
@@ -414,8 +440,8 @@ public:
 	Bool bindTexture(U32 set, U32 binding, TexturePtr tex, DepthStencilAspectMask aspect)
 	{
 		TextureBinding& b = m_textures[set][binding];
-		b.m_tex = tex;
-		b.m_sampler = {};
+		b.m_tex = tex->m_impl.get();
+		b.m_sampler = nullptr;
 		b.m_aspect = aspect;
 		return true;
 	}
@@ -423,8 +449,8 @@ public:
 	Bool bindTextureAndSampler(U32 set, U32 binding, TexturePtr tex, SamplerPtr sampler, DepthStencilAspectMask aspect)
 	{
 		TextureBinding& b = m_textures[set][binding];
-		b.m_tex = tex;
-		b.m_sampler = sampler;
+		b.m_tex = tex->m_impl.get();
+		b.m_sampler = sampler->m_impl.get();
 		b.m_aspect = aspect;
 		return true;
 	}
@@ -432,7 +458,7 @@ public:
 	class ShaderBufferBinding
 	{
 	public:
-		BufferPtr m_buff;
+		BufferImpl* m_buff = nullptr;
 		PtrSize m_offset;
 		TransientMemoryToken m_token;
 	};
@@ -442,7 +468,7 @@ public:
 	Bool bindUniformBuffer(U32 set, U32 binding, BufferPtr buff, PtrSize offset)
 	{
 		ShaderBufferBinding& b = m_ubos[set][binding];
-		b.m_buff = buff;
+		b.m_buff = buff->m_impl.get();
 		b.m_offset = offset;
 		b.m_token = {};
 		return true;
@@ -451,7 +477,7 @@ public:
 	Bool bindUniformBuffer(U32 set, U32 binding, const TransientMemoryToken& token)
 	{
 		ShaderBufferBinding& b = m_ubos[set][binding];
-		b.m_buff = {};
+		b.m_buff = nullptr;
 		b.m_offset = 0;
 		b.m_token = token;
 		return true;
@@ -462,7 +488,7 @@ public:
 	Bool bindStorageBuffer(U32 set, U32 binding, BufferPtr buff, PtrSize offset)
 	{
 		ShaderBufferBinding& b = m_ssbos[set][binding];
-		b.m_buff = buff;
+		b.m_buff = buff->m_impl.get();
 		b.m_offset = offset;
 		b.m_token = {};
 		return true;
@@ -471,7 +497,7 @@ public:
 	Bool bindStorageBuffer(U32 set, U32 binding, const TransientMemoryToken& token)
 	{
 		ShaderBufferBinding& b = m_ssbos[set][binding];
-		b.m_buff = {};
+		b.m_buff = nullptr;
 		b.m_offset = 0;
 		b.m_token = token;
 		return true;
@@ -480,7 +506,7 @@ public:
 	class ImageBinding
 	{
 	public:
-		TexturePtr m_tex;
+		TextureImpl* m_tex = nullptr;
 		U8 m_level;
 	};
 
@@ -489,18 +515,18 @@ public:
 	Bool bindImage(U32 set, U32 binding, TexturePtr img, U32 level)
 	{
 		ImageBinding& b = m_images[set][binding];
-		b.m_tex = img;
+		b.m_tex = img->m_impl.get();
 		b.m_level = level;
 		return true;
 	}
 
-	ShaderProgramPtr m_prog;
+	ShaderProgramImpl* m_prog = nullptr;
 
 	Bool bindShaderProgram(ShaderProgramPtr prog)
 	{
-		if(prog != m_prog)
+		if(prog->m_impl.get() != m_prog)
 		{
-			m_prog = prog;
+			m_prog = prog->m_impl.get();
 			return true;
 		}
 		return false;
@@ -509,12 +535,12 @@ public:
 
 	/// @name other
 	/// @{
-	FramebufferPtr m_fb;
+	FramebufferImpl* m_fb = nullptr;
 
 	Bool beginRenderPass(const FramebufferPtr& fb)
 	{
 		ANKI_ASSERT(!insideRenderPass() && "Already inside a renderpass");
-		m_fb = fb;
+		m_fb = fb->m_impl.get();
 		m_lastSecondLevelCmdb = nullptr;
 		return true;
 	}
@@ -522,12 +548,20 @@ public:
 	void endRenderPass()
 	{
 		ANKI_ASSERT(insideRenderPass() && "Not inside a renderpass");
-		m_fb = {};
+		if(m_lastSecondLevelCmdb)
+		{
+			// Renderpass had 2nd level cmdbs, need to restore the state back to default
+			::new(this) StateTracker();
+		}
+		else
+		{
+			m_fb = nullptr;
+		}
 	}
 
 	Bool insideRenderPass() const
 	{
-		return m_fb.isCreated();
+		return m_fb != nullptr;
 	}
 
 	CommandBufferImpl* m_lastSecondLevelCmdb = nullptr;
@@ -549,13 +583,13 @@ public:
 	void checkDrawcall() const
 	{
 		ANKI_ASSERT(m_viewport[1] != MAX_U16 && "Forgot to set the viewport");
-		ANKI_ASSERT(m_prog.isCreated() && "Forgot to bound a program");
+		ANKI_ASSERT(m_prog && "Forgot to bound a program");
 		ANKI_ASSERT((insideRenderPass() || m_secondLevel) && "Forgot to begin a render pass");
 	}
 
 	void checkDispatch() const
 	{
-		ANKI_ASSERT(m_prog.isCreated() && "Forgot to bound a program");
+		ANKI_ASSERT(m_prog && "Forgot to bound a program");
 		ANKI_ASSERT(!insideRenderPass() && "Forgot to end the render pass");
 	}
 	/// @}

+ 12 - 0
src/anki/renderer/Bloom.h

@@ -101,6 +101,18 @@ anki_internal:
 	}
 
 	ANKI_USE_RESULT Error init(const ConfigSet& cfg)
+	{
+		ANKI_LOGI("Initializing bloom passes");
+		Error err = initInternal(cfg);
+		if(err)
+		{
+			ANKI_LOGE("Failed to initialize bloom passes");
+		}
+		return err;
+	}
+
+private:
+	ANKI_USE_RESULT Error initInternal(const ConfigSet& cfg)
 	{
 		ANKI_CHECK(m_extractExposure.init(cfg));
 		ANKI_CHECK(m_upscale.init(cfg));

+ 6 - 2
src/anki/renderer/DepthDownscale.cpp

@@ -66,12 +66,14 @@ void HalfDepth::run(RenderingContext& ctx)
 	cmdb->bindTexture(0, 0, m_r->getMs().m_depthRt);
 
 	cmdb->setViewport(0, 0, m_r->getWidth() / 2, m_r->getHeight() / 2);
-	cmdb->setDepthWrite(true);
 	cmdb->setDepthCompareFunction(CompareOperation::ALWAYS);
 
 	m_r->drawQuad(cmdb);
 
 	cmdb->endRenderPass();
+
+	// Restore state
+	cmdb->setDepthCompareFunction(CompareOperation::LESS);
 }
 
 QuarterDepth::~QuarterDepth()
@@ -130,12 +132,14 @@ void QuarterDepth::run(RenderingContext& ctx)
 	cmdb->bindTexture(0, 0, m_parent->m_hd.m_depthRt);
 
 	cmdb->setViewport(0, 0, m_r->getWidth() / 4, m_r->getHeight() / 4);
-	cmdb->setDepthWrite(true);
 	cmdb->setDepthCompareFunction(CompareOperation::ALWAYS);
 
 	m_r->drawQuad(cmdb);
 
 	cmdb->endRenderPass();
+
+	// Restore state
+	cmdb->setDepthCompareFunction(CompareOperation::LESS);
 }
 
 DepthDownscale::~DepthDownscale()

+ 38 - 4
src/anki/renderer/Drawer.cpp

@@ -361,13 +361,47 @@ Error RenderableDrawer::flushDrawcall(DrawContext& ctx, CompleteRenderingBuildIn
 	setupUniforms(ctx, build);
 
 	// Finaly, touch the command buffer
-	ctx.m_cmdb->bindUniformBuffer(0, 0, ctx.m_uboToken);
-	ctx.m_cmdb->bindShaderProgram(build.m_out.m_program);
+	CommandBufferPtr& cmdb = ctx.m_cmdb;
+
+	cmdb->bindUniformBuffer(0, 0, ctx.m_uboToken);
+	cmdb->bindShaderProgram(build.m_out.m_program);
+
+	for(U i = 0; i < build.m_out.m_vertexBufferBindingCount; ++i)
+	{
+		const RenderingVertexBufferBinding& binding = build.m_out.m_vertexBufferBindings[i];
+		if(binding.m_buffer)
+		{
+			cmdb->bindVertexBuffer(i, binding.m_buffer, binding.m_offset, binding.m_stride);
+		}
+		else
+		{
+			ANKI_ASSERT(!!(binding.m_token));
+			cmdb->bindVertexBuffer(i, binding.m_token, binding.m_stride);
+		}
+	}
+
+	for(U i = 0; i < build.m_out.m_vertexAttributeCount; ++i)
+	{
+		const RenderingVertexAttributeInfo& attrib = build.m_out.m_vertexAttributes[i];
+
+		cmdb->setVertexAttribute(i, attrib.m_bufferBinding, attrib.m_format, attrib.m_relativeOffset);
+	}
+
 	if(!build.m_out.m_drawArrays)
 	{
 		const DrawElementsIndirectInfo& drawc = build.m_out.m_drawcall.m_elements;
 
-		ctx.m_cmdb->drawElements(build.m_out.m_topology,
+		if(build.m_out.m_indexBuffer)
+		{
+			cmdb->bindIndexBuffer(build.m_out.m_indexBuffer, 0, IndexType::U16);
+		}
+		else
+		{
+			ANKI_ASSERT(!!(build.m_out.m_indexBufferToken));
+			cmdb->bindIndexBuffer(build.m_out.m_indexBufferToken, IndexType::U16);
+		}
+
+		cmdb->drawElements(build.m_out.m_topology,
 			drawc.m_count,
 			drawc.m_instanceCount,
 			drawc.m_firstIndex,
@@ -378,7 +412,7 @@ Error RenderableDrawer::flushDrawcall(DrawContext& ctx, CompleteRenderingBuildIn
 	{
 		const DrawArraysIndirectInfo& drawc = build.m_out.m_drawcall.m_arrays;
 
-		ctx.m_cmdb->drawArrays(
+		cmdb->drawArrays(
 			build.m_out.m_topology, drawc.m_count, drawc.m_instanceCount, drawc.m_first, drawc.m_baseInstance);
 	}
 

+ 19 - 7
src/anki/renderer/Fs.cpp

@@ -20,7 +20,20 @@ Fs::~Fs()
 {
 }
 
-Error Fs::init(const ConfigSet&)
+Error Fs::init(const ConfigSet& cfg)
+{
+	ANKI_LOGI("Initializing forward shading");
+
+	Error err = initInternal(cfg);
+	if(err)
+	{
+		ANKI_LOGE("Failed to initialize forward shading");
+	}
+
+	return err;
+}
+
+Error Fs::initInternal(const ConfigSet&)
 {
 	m_width = m_r->getWidth() / FS_FRACTION;
 	m_height = m_r->getHeight() / FS_FRACTION;
@@ -75,8 +88,8 @@ void Fs::drawVolumetric(RenderingContext& ctx, CommandBufferPtr cmdb)
 
 	cmdb->bindShaderProgram(m_vol.m_prog);
 	cmdb->setBlendMethods(0, BlendMethod::ONE, BlendMethod::ONE);
-
-	cmdb->bindShaderProgram(m_vol.m_prog);
+	cmdb->setDepthWrite(false);
+	cmdb->setDepthCompareFunction(CompareOperation::ALWAYS);
 
 	TransientMemoryToken token;
 	Vec4* unis = static_cast<Vec4*>(
@@ -93,6 +106,8 @@ void Fs::drawVolumetric(RenderingContext& ctx, CommandBufferPtr cmdb)
 
 	// Restore state
 	cmdb->setBlendMethods(0, BlendMethod::ONE, BlendMethod::ZERO);
+	cmdb->setDepthWrite(true);
+	cmdb->setDepthCompareFunction(CompareOperation::LESS);
 }
 
 Error Fs::buildCommandBuffers(RenderingContext& ctx, U threadId, U threadCount) const
@@ -117,8 +132,6 @@ Error Fs::buildCommandBuffers(RenderingContext& ctx, U threadId, U threadCount)
 	CommandBufferPtr cmdb = m_r->getGrManager().newInstance<CommandBuffer>(cinf);
 	ctx.m_fs.m_commandBuffers[threadId] = cmdb;
 
-	cmdb->setViewport(0, 0, m_width, m_height);
-
 	cmdb->bindTexture(1, 0, m_r->getDepthDownscale().m_hd.m_depthRt);
 	cmdb->bindTexture(1, 1, m_r->getSm().m_spotTexArray);
 	cmdb->bindTexture(1, 2, m_r->getSm().m_omniTexArray);
@@ -128,9 +141,9 @@ Error Fs::buildCommandBuffers(RenderingContext& ctx, U threadId, U threadCount)
 	cmdb->bindStorageBuffer(1, 0, ctx.m_is.m_clustersToken);
 	cmdb->bindStorageBuffer(1, 1, ctx.m_is.m_lightIndicesToken);
 
+	cmdb->setViewport(0, 0, m_width, m_height);
 	cmdb->setBlendMethods(0, BlendMethod::SRC_ALPHA, BlendMethod::ONE_MINUS_SRC_ALPHA);
 	cmdb->setDepthWrite(false);
-	cmdb->setDepthCompareFunction(CompareOperation::LESS);
 
 	// Start drawing
 	Error err = m_r->getSceneDrawer().drawRange(Pass::MS_FS,
@@ -163,7 +176,6 @@ void Fs::run(RenderingContext& ctx)
 	CommandBufferPtr& cmdb = ctx.m_commandBuffer;
 	cmdb->beginRenderPass(m_fb);
 	cmdb->setViewport(0, 0, m_width, m_height);
-	cmdb->setPolygonOffset(0.0, 0.0);
 
 	for(U i = 0; i < m_r->getThreadPool().getThreadsCount(); ++i)
 	{

+ 1 - 0
src/anki/renderer/Fs.h

@@ -70,6 +70,7 @@ private:
 		SamplerPtr m_nearestSampler;
 	} m_vol;
 
+	ANKI_USE_RESULT Error initInternal(const ConfigSet& initializer);
 	ANKI_USE_RESULT Error initVol();
 };
 /// @}

+ 2 - 2
src/anki/renderer/FsUpscale.cpp

@@ -29,7 +29,7 @@ Error FsUpscale::init(const ConfigSet& config)
 
 Error FsUpscale::initInternal(const ConfigSet& config)
 {
-	ANKI_LOGE("Initializing forward shading upscale");
+	ANKI_LOGI("Initializing forward shading upscale");
 
 	GrManager& gr = getGrManager();
 
@@ -77,7 +77,7 @@ void FsUpscale::run(RenderingContext& ctx)
 
 	cmdb->bindUniformBuffer(0, 0, token);
 	cmdb->bindTexture(0, 0, m_r->getMs().m_depthRt);
-	cmdb->bindTextureAndSampler(0, 1, m_r->getMs().m_depthRt, m_nearestSampler);
+	cmdb->bindTextureAndSampler(0, 1, m_r->getDepthDownscale().m_hd.m_depthRt, m_nearestSampler);
 	cmdb->bindTexture(0, 2, m_r->getFs().getRt());
 	cmdb->bindTexture(0, 3, m_r->getSsao().getRt());
 

+ 17 - 4
src/anki/renderer/Ir.cpp

@@ -57,7 +57,19 @@ Ir::~Ir()
 
 Error Ir::init(const ConfigSet& config)
 {
-	ANKI_LOGI("Initializing IR (Image Reflections)");
+	ANKI_LOGI("Initializing image reflections");
+
+	Error err = initInternal(config);
+	if(err)
+	{
+		ANKI_LOGE("Failed to initialize image reflections");
+	}
+
+	return err;
+}
+
+Error Ir::initInternal(const ConfigSet& config)
+{
 	m_fbSize = config.getNumber("ir.rendererSize");
 
 	if(m_fbSize < TILE_SIZE)
@@ -420,6 +432,7 @@ void Ir::runIs(RenderingContext& rctx, FrustumComponent& frc, U layer, U faceIdx
 		TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE,
 		TextureSurfaceInfo(0, 0, faceIdx, layer));
 
+	// Set state
 	cmdb->beginRenderPass(face.m_isFb);
 
 	cmdb->bindTexture(0, 0, face.m_gbufferColorRts[0]);
@@ -429,8 +442,8 @@ void Ir::runIs(RenderingContext& rctx, FrustumComponent& frc, U layer, U faceIdx
 	cmdb->setVertexAttribute(0, 0, PixelFormat(ComponentFormat::R32G32B32, TransformFormat::FLOAT), 0);
 
 	cmdb->setBlendMethods(0, BlendMethod::ONE, BlendMethod::ONE);
-	cmdb->setDepthWrite(false);
 	cmdb->setDepthCompareFunction(CompareOperation::GREATER);
+	cmdb->setDepthWrite(false);
 
 	// Process all lights
 	const Mat4& vpMat = frc.getViewProjectionMatrix();
@@ -480,7 +493,7 @@ void Ir::runIs(RenderingContext& rctx, FrustumComponent& frc, U layer, U faceIdx
 	}
 
 	cmdb->bindShaderProgram(m_is.m_slightProg);
-	cmdb->bindVertexBuffer(0, m_is.m_slightPositions, 0, 0);
+	cmdb->bindVertexBuffer(0, m_is.m_slightPositions, 0, sizeof(F32) * 3);
 	cmdb->bindIndexBuffer(m_is.m_slightIndices, 0, IndexType::U16);
 
 	it = vis.getBegin(VisibilityGroupType::LIGHTS_SPOT);
@@ -556,8 +569,8 @@ void Ir::runIs(RenderingContext& rctx, FrustumComponent& frc, U layer, U faceIdx
 
 	// Restore state
 	cmdb->setBlendMethods(0, BlendMethod::ONE, BlendMethod::ZERO);
-	cmdb->setDepthWrite(true);
 	cmdb->setDepthCompareFunction(CompareOperation::LESS);
+	cmdb->setDepthWrite(true);
 }
 
 void Ir::computeIrradiance(RenderingContext& rctx, U layer, U faceIdx)

+ 2 - 1
src/anki/renderer/Ir.h

@@ -32,7 +32,7 @@ anki_internal:
 
 	~Ir();
 
-	ANKI_USE_RESULT Error init(const ConfigSet& initializer);
+	ANKI_USE_RESULT Error init(const ConfigSet& cfg);
 
 	ANKI_USE_RESULT Error run(RenderingContext& ctx);
 
@@ -137,6 +137,7 @@ private:
 	SamplerPtr m_integrationLutSampler;
 
 	// Init
+	ANKI_USE_RESULT Error initInternal(const ConfigSet& cfg);
 	ANKI_USE_RESULT Error initIs();
 	ANKI_USE_RESULT Error initIrradiance();
 	void initFaceInfo(U cacheEntryIdx, U faceIdx);

+ 4 - 3
src/anki/renderer/Is.cpp

@@ -53,7 +53,7 @@ Is::~Is()
 
 Error Is::init(const ConfigSet& config)
 {
-	ANKI_LOGE("Initializing light stage");
+	ANKI_LOGI("Initializing light stage");
 	Error err = initInternal(config);
 
 	if(err)
@@ -89,7 +89,7 @@ Error Is::initInternal(const ConfigSet& config)
 		&getGrManager());
 
 	//
-	// Load the programs
+	// Load shaders and programs
 	//
 	StringAuto pps(getAllocator());
 
@@ -112,10 +112,11 @@ Error Is::initInternal(const ConfigSet& config)
 		1,
 		m_r->getIr().getReflectionTextureMipmapCount());
 
-	// point light
 	ANKI_CHECK(m_r->createShader("shaders/Is.vert.glsl", m_lightVert, &pps[0]));
 	ANKI_CHECK(m_r->createShader("shaders/Is.frag.glsl", m_lightFrag, &pps[0]));
 
+	m_lightProg = getGrManager().newInstance<ShaderProgram>(m_lightVert->getGrShader(), m_lightFrag->getGrShader());
+
 	//
 	// Create framebuffer
 	//

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

@@ -34,7 +34,7 @@ Lf::~Lf()
 
 Error Lf::init(const ConfigSet& config)
 {
-	ANKI_LOGE("Initializing lens flare pass");
+	ANKI_LOGI("Initializing lens flare pass");
 
 	Error err = initInternal(config);
 	if(err)

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

@@ -148,7 +148,6 @@ void Ms::run(RenderingContext& ctx)
 
 	// Set some state anyway because other stages may depend on it
 	cmdb->setViewport(0, 0, m_r->getWidth(), m_r->getHeight());
-	cmdb->setPolygonOffset(0.0, 0.0);
 
 	for(U i = 0; i < m_r->getThreadPool().getThreadsCount(); ++i)
 	{

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

@@ -164,7 +164,7 @@ Error Renderer::initInternal(const ConfigSet& config)
 	ANKI_CHECK(m_fsUpscale->init(config));
 
 	m_tm.reset(getAllocator().newInstance<Tm>(this));
-	ANKI_CHECK(m_tm->create(config));
+	ANKI_CHECK(m_tm->init(config));
 
 	m_downscale.reset(getAllocator().newInstance<DownscaleBlur>(this));
 	ANKI_CHECK(m_downscale->init(config));
@@ -412,7 +412,6 @@ Error Renderer::buildCommandBuffersInternal(RenderingContext& ctx, U32 threadId,
 		init.m_framebuffer = m_fs->getFramebuffer();
 		CommandBufferPtr cmdb = getGrManager().newInstance<CommandBuffer>(init);
 		cmdb->setViewport(0, 0, m_fs->getWidth(), m_fs->getHeight());
-		cmdb->setPolygonOffset(0.0, 0.0);
 
 		m_lf->run(ctx, cmdb);
 		m_fs->drawVolumetric(ctx, cmdb);

+ 2 - 2
src/anki/renderer/Sm.cpp

@@ -268,7 +268,7 @@ Error Sm::doSpotLight(SceneNode& light, CommandBufferPtr& cmdb, FramebufferPtr&
 	}
 
 	CommandBufferInitInfo cinf;
-	cinf.m_flags = CommandBufferFlag::SECOND_LEVEL;
+	cinf.m_flags = CommandBufferFlag::SECOND_LEVEL | CommandBufferFlag::GRAPHICS_WORK;
 	cinf.m_framebuffer = fb;
 	cmdb = m_r->getGrManager().newInstance<CommandBuffer>(cinf);
 
@@ -301,7 +301,7 @@ Error Sm::doOmniLight(
 		if(start != end)
 		{
 			CommandBufferInitInfo cinf;
-			cinf.m_flags = CommandBufferFlag::SECOND_LEVEL;
+			cinf.m_flags = CommandBufferFlag::SECOND_LEVEL | CommandBufferFlag::GRAPHICS_WORK;
 			cinf.m_framebuffer = fbs[frCount];
 			cmdbs[frCount] = m_r->getGrManager().newInstance<CommandBuffer>(cinf);
 

+ 3 - 0
src/anki/renderer/Smaa.cpp

@@ -229,6 +229,9 @@ void SmaaWeights::run(RenderingContext& ctx)
 	cmdb->beginRenderPass(m_fb);
 	m_r->drawQuad(cmdb);
 	cmdb->endRenderPass();
+
+	// Restore state
+	cmdb->setStencilCompareFunction(FaceSelectionMask::FRONT, CompareOperation::ALWAYS);
 }
 
 Error Smaa::init(const ConfigSet& cfg)

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

@@ -50,6 +50,9 @@ void Sslf::run(RenderingContext& ctx)
 	cmdb->bindTexture(0, 1, m_lensDirtTex->getGrTexture());
 
 	m_r->drawQuad(cmdb);
+
+	// Retore state
+	cmdb->setBlendMethods(0, BlendMethod::ONE, BlendMethod::ZERO);
 }
 
 } // end namespace anki

+ 13 - 1
src/anki/renderer/Tm.cpp

@@ -10,7 +10,19 @@
 namespace anki
 {
 
-Error Tm::create(const ConfigSet& initializer)
+Error Tm::init(const ConfigSet& cfg)
+{
+	ANKI_LOGI("Initializing tonemapping");
+	Error err = initInternal(cfg);
+	if(err)
+	{
+		ANKI_LOGE("Failed to initialize tonemapping");
+	}
+
+	return err;
+}
+
+Error Tm::initInternal(const ConfigSet& initializer)
 {
 	// Create shader
 	ANKI_ASSERT(m_r->getIs().getRtMipmapCount() > 1);

+ 3 - 1
src/anki/renderer/Tm.h

@@ -24,13 +24,15 @@ anki_internal:
 	{
 	}
 
-	ANKI_USE_RESULT Error create(const ConfigSet& initializer);
+	ANKI_USE_RESULT Error init(const ConfigSet& cfg);
 
 	void run(RenderingContext& ctx);
 
 private:
 	ShaderResourcePtr m_luminanceShader;
 	ShaderProgramPtr m_prog;
+
+	ANKI_USE_RESULT Error initInternal(const ConfigSet& cfg);
 };
 /// @}
 

+ 3 - 0
src/anki/renderer/Volumetric.cpp

@@ -122,6 +122,9 @@ void Volumetric::run(RenderingContext& ctx)
 	cmdb->beginRenderPass(m_fb);
 	m_r->drawQuad(cmdb);
 	cmdb->endRenderPass();
+
+	// Restore state
+	cmdb->setBlendMethods(0, BlendMethod::ONE, BlendMethod::ZERO);
 }
 
 } // end namespace anki

+ 1 - 1
src/anki/scene/ModelNode.cpp

@@ -83,7 +83,7 @@ Error ModelPatchNode::buildRendering(const RenderingBuildInfoIn& in, RenderingBu
 	out.m_vertexAttributeCount = modelInf.m_vertexAttributeCount;
 	for(U i = 0; i < modelInf.m_vertexAttributeCount; ++i)
 	{
-		out.m_vertexAttributes[i] = out.m_vertexAttributes[i];
+		out.m_vertexAttributes[i] = modelInf.m_vertexAttributes[i];
 	}
 
 	out.m_indexBuffer = modelInf.m_indexBuffer;

+ 7 - 10
src/anki/scene/ParticleEmitter.cpp

@@ -284,13 +284,10 @@ Error ParticleEmitter::buildRendering(const RenderingBuildInfoIn& in, RenderingB
 		return ErrorCode::NONE;
 	}
 
-	U frame = (getGlobalTimestamp() % MAX_FRAMES_IN_FLIGHT);
-
 	m_particleEmitterResource->getRenderingInfo(in.m_key.m_lod, out.m_program);
 
 	out.m_vertexBufferBindingCount = 1;
-	out.m_vertexBufferBindings[0].m_buffer = m_vertBuffs[frame];
-	out.m_vertexBufferBindings[0].m_offset = 0;
+	out.m_vertexBufferBindings[0].m_token = m_vertBuffToken;
 	out.m_vertexBufferBindings[0].m_stride = VERTEX_SIZE;
 
 	out.m_vertexAttributeCount = 3;
@@ -309,8 +306,9 @@ Error ParticleEmitter::buildRendering(const RenderingBuildInfoIn& in, RenderingB
 	out.m_drawArrays = true;
 	out.m_drawcall.m_arrays.m_count = m_aliveParticlesCount;
 
-	// The particles are already in world position
-	out.m_hasTransform = false;
+	// The particles are already in world position but materials use the MVP
+	out.m_hasTransform = true;
+	out.m_transform = Mat4::getIdentity();
 
 	return ErrorCode::NONE;
 }
@@ -377,8 +375,9 @@ Error ParticleEmitter::frameUpdate(F32 prevUpdateTime, F32 crntTime)
 	Vec4 aabbmax(MIN_F32, MIN_F32, MIN_F32, 0.0);
 	m_aliveParticlesCount = 0;
 
-	U frame = getGlobalTimestamp() % 3;
-	F32* verts = static_cast<F32*>(m_vertBuffs[frame]->map(0, m_vertBuffSize, BufferMapAccessBit::WRITE));
+	F32* verts = static_cast<F32*>(getResourceManager().getGrManager().allocateFrameTransientMemory(
+		m_vertBuffSize, BufferUsageBit::VERTEX, m_vertBuffToken));
+
 	const F32* verts_base = verts;
 	(void)verts_base;
 
@@ -437,8 +436,6 @@ Error ParticleEmitter::frameUpdate(F32 prevUpdateTime, F32 crntTime)
 		}
 	}
 
-	m_vertBuffs[frame]->unmap();
-
 	if(m_aliveParticlesCount != 0)
 	{
 		Vec4 min = aabbmin - m_particle.m_size;

+ 1 - 1
src/anki/scene/ParticleEmitter.h

@@ -190,7 +190,7 @@ private:
 	/// @name Graphics
 	/// @{
 	U32 m_vertBuffSize = 0;
-	Array<BufferPtr, MAX_FRAMES_IN_FLIGHT> m_vertBuffs;
+	TransientMemoryToken m_vertBuffToken;
 	/// @}
 
 	SimulationType m_simulationType = SimulationType::UNDEFINED;