Explorar o código

GR interface: Some more work on the renderer

Panagiotis Christopoulos Charitos %!s(int64=9) %!d(string=hai) anos
pai
achega
229df151e2
Modificáronse 41 ficheiros con 572 adicións e 1109 borrados
  1. 10 0
      src/anki/gr/Common.h
  2. 1 1
      src/anki/gr/gl/BufferImpl.h
  3. 13 30
      src/anki/gr/gl/CommandBuffer.cpp
  4. 7 3
      src/anki/gr/gl/StateTracker.h
  5. 24 47
      src/anki/renderer/Bloom.cpp
  6. 2 4
      src/anki/renderer/Bloom.h
  7. 26 33
      src/anki/renderer/DepthDownscale.cpp
  8. 3 3
      src/anki/renderer/DepthDownscale.h
  9. 55 63
      src/anki/renderer/Drawer.cpp
  10. 2 7
      src/anki/renderer/Drawer.h
  11. 64 135
      src/anki/renderer/Is.cpp
  12. 4 15
      src/anki/renderer/Is.h
  13. 7 25
      src/anki/renderer/Ms.cpp
  14. 0 3
      src/anki/renderer/Ms.h
  15. 32 65
      src/anki/renderer/Pps.cpp
  16. 1 3
      src/anki/renderer/Pps.h
  17. 6 1
      src/anki/renderer/Renderer.cpp
  18. 15 5
      src/anki/renderer/Renderer.h
  19. 15 12
      src/anki/renderer/Sm.cpp
  20. 7 23
      src/anki/renderer/Sm.h
  21. 40 59
      src/anki/renderer/Smaa.cpp
  22. 5 4
      src/anki/renderer/Smaa.h
  23. 40 90
      src/anki/renderer/Ssao.cpp
  24. 3 8
      src/anki/renderer/Ssao.h
  25. 12 26
      src/anki/renderer/Sslf.cpp
  26. 1 2
      src/anki/renderer/Sslf.h
  27. 0 205
      src/anki/renderer/Tiler.cpp
  28. 0 57
      src/anki/renderer/Tiler.h
  29. 15 27
      src/anki/renderer/Tm.cpp
  30. 3 8
      src/anki/renderer/Tm.h
  31. 36 35
      src/anki/renderer/Volumetric.cpp
  32. 3 2
      src/anki/renderer/Volumetric.h
  33. 20 2
      src/anki/resource/Model.h
  34. 1 1
      src/anki/scene/CMakeLists.txt
  35. 0 8
      src/anki/scene/LensFlareComponent.cpp
  36. 0 7
      src/anki/scene/LensFlareComponent.h
  37. 16 5
      src/anki/scene/ModelNode.cpp
  38. 22 37
      src/anki/scene/ParticleEmitter.cpp
  39. 0 1
      src/anki/scene/ParticleEmitter.h
  40. 0 2
      src/anki/scene/RenderComponent.cpp
  41. 61 45
      src/anki/scene/RenderComponent.h

+ 10 - 0
src/anki/gr/Common.h

@@ -179,6 +179,16 @@ anki_internal:
 	TransientMemoryTokenLifetime m_lifetime = TransientMemoryTokenLifetime::PER_FRAME;
 	BufferUsageBit m_usage = BufferUsageBit::NONE;
 
+	operator Bool() const
+	{
+		return m_offset != 0;
+	}
+
+	Bool operator==(const TransientMemoryToken& b) const
+	{
+		return m_offset == b.m_offset && m_range == b.m_range && m_lifetime == b.m_lifetime && m_usage == b.m_usage;
+	}
+
 	void markUnused()
 	{
 		m_offset = m_range = MAX_U32;

+ 1 - 1
src/anki/gr/gl/BufferImpl.h

@@ -49,7 +49,7 @@ public:
 	void bind(GLenum target, U32 binding, PtrSize offset) const
 	{
 		ANKI_ASSERT(isCreated());
-		ANKI_ASSERT(offset + size <= m_size);
+		ANKI_ASSERT(offset < m_size);
 		glBindBufferRange(target, binding, m_glName, offset, m_size - offset);
 	}
 

+ 13 - 30
src/anki/gr/gl/CommandBuffer.cpp

@@ -42,25 +42,14 @@ void CommandBuffer::init(CommandBufferInitInfo& inf)
 {
 	m_impl.reset(getAllocator().newInstance<CommandBufferImpl>(&getManager()));
 	m_impl->init(inf);
-
-#if ANKI_ASSERTS_ENABLED
-	if((inf.m_flags & CommandBufferFlag::SECOND_LEVEL) == CommandBufferFlag::SECOND_LEVEL)
-	{
-		ANKI_ASSERT(inf.m_framebuffer.isCreated());
-		m_impl->m_dbg.m_insideRenderPass = true;
-		m_impl->m_dbg.m_secondLevel = true;
-	}
-#endif
 }
 
 void CommandBuffer::flush()
 {
-#if ANKI_ASSERTS_ENABLED
-	if(!m_impl->m_dbg.m_secondLevel)
+	if(!m_impl->isSecondLevel())
 	{
-		ANKI_ASSERT(!m_impl->m_dbg.m_insideRenderPass);
+		ANKI_ASSERT(!m_impl->m_state.insideRenderPass());
 	}
-#endif
 
 	if(!m_impl->isSecondLevel())
 	{
@@ -70,12 +59,11 @@ void CommandBuffer::flush()
 
 void CommandBuffer::finish()
 {
-#if ANKI_ASSERTS_ENABLED
-	if(!m_impl->m_dbg.m_secondLevel)
+	if(!m_impl->isSecondLevel())
 	{
-		ANKI_ASSERT(!m_impl->m_dbg.m_insideRenderPass);
+		ANKI_ASSERT(!m_impl->m_state.insideRenderPass());
 	}
-#endif
+
 	getManager().getImplementation().getRenderingThread().finishCommandBuffer(CommandBufferPtr(this));
 }
 
@@ -231,10 +219,6 @@ void CommandBuffer::setViewport(U16 minx, U16 miny, U16 maxx, U16 maxy)
 		}
 	};
 
-#if ANKI_ASSERTS_ENABLED
-	m_impl->m_dbg.m_viewport = true;
-#endif
-
 	m_impl->m_state.setViewport(
 		minx, miny, maxx, maxy, [=]() { m_impl->pushBackNewCommand<ViewportCommand>(minx, miny, maxx, maxy); });
 }
@@ -318,10 +302,6 @@ void CommandBuffer::setPolygonOffset(F32 factor, F32 units)
 		}
 	};
 
-#if ANKI_ASSERTS_ENABLED
-	m_impl->m_dbg.m_polygonOffset = true;
-#endif
-
 	m_impl->m_state.setPolygonOffset(factor, units, [=]() { m_impl->pushBackNewCommand<Cmd>(factor, units); });
 }
 
@@ -1080,7 +1060,7 @@ void CommandBuffer::uploadTextureSurface(
 
 	ANKI_ASSERT(tex);
 	ANKI_ASSERT(token.m_range > 0);
-	ANKI_ASSERT(!m_impl->m_dbg.m_insideRenderPass);
+	ANKI_ASSERT(!m_impl->m_state.insideRenderPass());
 
 	m_impl->pushBackNewCommand<TexSurfUploadCommand>(tex, surf, token);
 }
@@ -1117,7 +1097,7 @@ void CommandBuffer::uploadTextureVolume(TexturePtr tex, const TextureVolumeInfo&
 
 	ANKI_ASSERT(tex);
 	ANKI_ASSERT(token.m_range > 0);
-	ANKI_ASSERT(!m_impl->m_dbg.m_insideRenderPass);
+	ANKI_ASSERT(!m_impl->m_state.insideRenderPass());
 
 	m_impl->pushBackNewCommand<TexVolUploadCommand>(tex, vol, token);
 }
@@ -1154,7 +1134,7 @@ void CommandBuffer::uploadBuffer(BufferPtr buff, PtrSize offset, const Transient
 
 	ANKI_ASSERT(token.m_range > 0);
 	ANKI_ASSERT(buff);
-	ANKI_ASSERT(!m_impl->m_dbg.m_insideRenderPass);
+	ANKI_ASSERT(!m_impl->m_state.insideRenderPass());
 
 	m_impl->pushBackNewCommand<BuffWriteCommand>(buff, offset, token);
 }
@@ -1182,7 +1162,7 @@ void CommandBuffer::generateMipmaps2d(TexturePtr tex, U face, U layer)
 		}
 	};
 
-	ANKI_ASSERT(!m_impl->m_dbg.m_insideRenderPass);
+	ANKI_ASSERT(!m_impl->m_state.insideRenderPass());
 	m_impl->pushBackNewCommand<GenMipsCommand>(tex, face, layer);
 }
 
@@ -1252,7 +1232,7 @@ void CommandBuffer::copyTextureSurfaceToTextureSurface(
 		}
 	};
 
-	ANKI_ASSERT(!m_impl->m_dbg.m_insideRenderPass);
+	ANKI_ASSERT(!m_impl->m_state.insideRenderPass());
 	m_impl->pushBackNewCommand<CopyTexCommand>(src, srcSurf, dest, destSurf);
 }
 
@@ -1358,6 +1338,7 @@ void CommandBuffer::clearTextureSurface(
 		}
 	};
 
+	ANKI_ASSERT(!m_impl->m_state.insideRenderPass());
 	m_impl->pushBackNewCommand<ClearTextCommand>(tex, surf, clearValue, aspect);
 }
 
@@ -1386,6 +1367,7 @@ void CommandBuffer::fillBuffer(BufferPtr buff, PtrSize offset, PtrSize size, U32
 		}
 	};
 
+	ANKI_ASSERT(!m_impl->m_state.insideRenderPass());
 	m_impl->pushBackNewCommand<FillBufferCommand>(buff, offset, size, value);
 }
 
@@ -1419,6 +1401,7 @@ void CommandBuffer::writeOcclusionQueryResultToBuffer(OcclusionQueryPtr query, P
 		}
 	};
 
+	ANKI_ASSERT(!m_impl->m_state.insideRenderPass());
 	m_impl->pushBackNewCommand<WriteOcclResultToBuff>(query, offset, buff);
 }
 

+ 7 - 3
src/anki/gr/gl/StateTracker.h

@@ -76,8 +76,7 @@ public:
 	template<typename TFunc>
 	void setViewport(U16 minx, U16 miny, U16 maxx, U16 maxy, TFunc func)
 	{
-		ANKI_ASSERT(m_viewport[0] != MAX_U16 && m_viewport[1] != MAX_U16 && m_viewport[2] != MAX_U16
-			&& m_viewport[3] != MAX_U16);
+		ANKI_ASSERT(minx != MAX_U16 && miny != MAX_U16 && maxx != MAX_U16 && maxy != MAX_U16);
 		if(m_viewport[0] != minx || m_viewport[1] != miny || m_viewport[2] != maxx || m_viewport[3] != maxy)
 		{
 			m_viewport = {minx, miny, maxx, maxy};
@@ -274,7 +273,7 @@ public:
 	template<typename TFunc>
 	void maybeEnableDepthTest(TFunc func)
 	{
-		ANKI_ASSERT(m_depthWrite != 2 && m_depthOp = CompareOperation::COUNT);
+		ANKI_ASSERT(m_depthWrite != 2 && m_depthOp != CompareOperation::COUNT);
 		Bool enable = m_depthWrite || m_depthOp != CompareOperation::ALWAYS;
 
 		if(enable != m_depthTestEnabled)
@@ -395,6 +394,11 @@ public:
 		ANKI_ASSERT(m_fbUuid != MAX_U64 && "Not inside a renderpass");
 		m_fbUuid = MAX_U64;
 	}
+
+	Bool insideRenderPass() const
+	{
+		return m_fbUuid != MAX_U64;
+	}
 	/// @}
 
 	/// @name drawcalls

+ 24 - 47
src/anki/renderer/Bloom.cpp

@@ -45,32 +45,17 @@ Error BloomExposure::init(const ConfigSet& config)
 	m_fb = gr.newInstance<Framebuffer>(fbInit);
 
 	// init shaders
-	StringAuto pps(getAllocator());
-	pps.sprintf("#define WIDTH %u\n"
-				"#define HEIGHT %u\n"
-				"#define MIPMAP %u.0\n",
+	ANKI_CHECK(m_r->createShader("shaders/Bloom.frag.glsl",
+		m_frag,
+		"#define WIDTH %u\n"
+		"#define HEIGHT %u\n"
+		"#define MIPMAP %u.0\n",
 		m_r->getWidth() >> (m_r->getIs().getRtMipmapCount() - 1),
 		m_r->getHeight() >> (m_r->getIs().getRtMipmapCount() - 1),
-		m_r->getIs().getRtMipmapCount() - 1);
+		m_r->getIs().getRtMipmapCount() - 1));
 
-	ANKI_CHECK(getResourceManager().loadResourceToCache(m_frag, "shaders/Bloom.frag.glsl", pps.toCString(), "r_"));
-
-	// Init pplines
-	ColorStateInfo colorInf;
-	colorInf.m_attachmentCount = 1;
-	colorInf.m_attachments[0].m_format = BLOOM_RT_PIXEL_FORMAT;
-
-	m_r->createDrawQuadPipeline(m_frag->getGrShader(), colorInf, m_ppline);
-
-	// Set descriptors
-	ResourceGroupInitInfo descInit;
-	descInit.m_textures[0].m_texture = m_r->getIs().getRt();
-	descInit.m_uniformBuffers[0].m_uploadedMemory = true;
-	descInit.m_uniformBuffers[0].m_usage = BufferUsageBit::UNIFORM_FRAGMENT;
-	descInit.m_storageBuffers[0].m_buffer = m_r->getTm().getAverageLuminanceBuffer();
-	descInit.m_storageBuffers[0].m_usage = BufferUsageBit::STORAGE_FRAGMENT_READ;
-
-	m_rsrc = gr.newInstance<ResourceGroup>(descInit);
+	// Init prog
+	m_r->createDrawQuadShaderProgram(m_frag->getGrShader(), m_prog);
 
 	return ErrorCode::NONE;
 }
@@ -95,14 +80,16 @@ void BloomExposure::run(RenderingContext& ctx)
 
 	cmdb->beginRenderPass(m_fb);
 	cmdb->setViewport(0, 0, m_width, m_height);
-	cmdb->bindPipeline(m_ppline);
+	cmdb->bindShaderProgram(m_prog);
+	cmdb->bindTexture(0, 0, m_r->getIs().getRt());
 
-	TransientMemoryInfo dyn;
-	Vec4* uniforms = static_cast<Vec4*>(getGrManager().allocateFrameTransientMemory(
-		sizeof(Vec4), BufferUsageBit::UNIFORM_ALL, dyn.m_uniformBuffers[0]));
+	TransientMemoryToken token;
+	Vec4* uniforms = static_cast<Vec4*>(
+		getGrManager().allocateFrameTransientMemory(sizeof(Vec4), BufferUsageBit::UNIFORM_ALL, token));
 	*uniforms = Vec4(m_threshold, m_scale, 0.0, 0.0);
 
-	cmdb->bindResourceGroup(m_rsrc, 0, &dyn);
+	cmdb->bindUniformBuffer(0, 0, token);
+	cmdb->bindStorageBuffer(0, 0, m_r->getTm().getAverageLuminanceBuffer(), 0);
 
 	m_r->drawQuad(cmdb);
 	cmdb->endRenderPass();
@@ -137,25 +124,15 @@ Error BloomUpscale::init(const ConfigSet& config)
 	m_fb = gr.newInstance<Framebuffer>(fbInit);
 
 	// init shaders
-	StringAuto pps(getAllocator());
-	pps.sprintf("#define WIDTH %u\n"
-				"#define HEIGHT %u\n",
+	ANKI_CHECK(m_r->createShader("shaders/BloomUpscale.frag.glsl",
+		m_frag,
+		"#define WIDTH %u\n"
+		"#define HEIGHT %u\n",
 		m_width,
-		m_height);
-
-	ANKI_CHECK(
-		getResourceManager().loadResourceToCache(m_frag, "shaders/BloomUpscale.frag.glsl", pps.toCString(), "r_"));
-
-	// Init pplines
-	ColorStateInfo colorInf;
-	colorInf.m_attachmentCount = 1;
-	colorInf.m_attachments[0].m_format = BLOOM_RT_PIXEL_FORMAT;
-	m_r->createDrawQuadPipeline(m_frag->getGrShader(), colorInf, m_ppline);
+		m_height));
 
-	// Set descriptors
-	ResourceGroupInitInfo descInit;
-	descInit.m_textures[0].m_texture = m_r->getBloom().m_extractExposure.m_rt;
-	m_rsrc = gr.newInstance<ResourceGroup>(descInit);
+	// Init prog
+	m_r->createDrawQuadShaderProgram(m_frag->getGrShader(), m_prog);
 
 	return ErrorCode::NONE;
 }
@@ -182,8 +159,8 @@ void BloomUpscale::run(RenderingContext& ctx)
 
 	cmdb->setViewport(0, 0, m_width, m_height);
 	cmdb->beginRenderPass(m_fb);
-	cmdb->bindPipeline(m_ppline);
-	cmdb->bindResourceGroup(m_rsrc, 0, nullptr);
+	cmdb->bindShaderProgram(m_prog);
+	cmdb->bindTexture(0, 0, m_r->getBloom().m_extractExposure.m_rt);
 	m_r->drawQuad(cmdb);
 
 	m_r->getBloom().m_sslf.run(ctx);

+ 2 - 4
src/anki/renderer/Bloom.h

@@ -46,8 +46,7 @@ anki_internal:
 private:
 	FramebufferPtr m_fb;
 	ShaderResourcePtr m_frag;
-	PipelinePtr m_ppline;
-	ResourceGroupPtr m_rsrc;
+	ShaderProgramPtr m_prog;
 
 	F32 m_threshold = 10.0; ///< How bright it is
 	F32 m_scale = 1.0;
@@ -78,8 +77,7 @@ anki_internal:
 private:
 	FramebufferPtr m_fb;
 	ShaderResourcePtr m_frag;
-	PipelinePtr m_ppline;
-	ResourceGroupPtr m_rsrc;
+	ShaderProgramPtr m_prog;
 };
 
 /// Bloom pass.

+ 26 - 33
src/anki/renderer/DepthDownscale.cpp

@@ -38,13 +38,6 @@ Error HalfDepth::init(const ConfigSet&)
 
 	m_fb = gr.newInstance<Framebuffer>(fbInit);
 
-	// Create RC group
-	ResourceGroupInitInfo rcinit;
-	rcinit.m_textures[0].m_texture = m_r->getMs().m_depthRt;
-	rcinit.m_textures[0].m_usage = TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ;
-
-	m_rcgroup = gr.newInstance<ResourceGroup>(rcinit);
-
 	return ErrorCode::NONE;
 }
 
@@ -69,9 +62,12 @@ void HalfDepth::run(RenderingContext& ctx)
 	CommandBufferPtr& cmdb = ctx.m_commandBuffer;
 
 	cmdb->beginRenderPass(m_fb);
+	cmdb->bindShaderProgram(m_parent->m_prog);
+	cmdb->bindTexture(0, 0, m_r->getMs().m_depthRt);
+
 	cmdb->setViewport(0, 0, m_r->getWidth() / 2, m_r->getHeight() / 2);
-	cmdb->bindPipeline(m_parent->m_ppline);
-	cmdb->bindResourceGroup(m_rcgroup, 0, nullptr);
+	cmdb->enableDepthWrite(true);
+	cmdb->setDepthCompareFunction(CompareOperation::ALWAYS);
 
 	m_r->drawQuad(cmdb);
 
@@ -106,13 +102,6 @@ Error QuarterDepth::init(const ConfigSet&)
 
 	m_fb = gr.newInstance<Framebuffer>(fbInit);
 
-	// Create RC group
-	ResourceGroupInitInfo rcinit;
-	rcinit.m_textures[0].m_texture = m_parent->m_hd.m_depthRt;
-	rcinit.m_textures[0].m_usage = TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ;
-
-	m_rcgroup = gr.newInstance<ResourceGroup>(rcinit);
-
 	return ErrorCode::NONE;
 }
 
@@ -137,9 +126,12 @@ void QuarterDepth::run(RenderingContext& ctx)
 	CommandBufferPtr& cmdb = ctx.m_commandBuffer;
 
 	cmdb->beginRenderPass(m_fb);
+	cmdb->bindShaderProgram(m_parent->m_prog);
+	cmdb->bindTexture(0, 0, m_parent->m_hd.m_depthRt);
+
 	cmdb->setViewport(0, 0, m_r->getWidth() / 4, m_r->getHeight() / 4);
-	cmdb->bindPipeline(m_parent->m_ppline);
-	cmdb->bindResourceGroup(m_rcgroup, 0, nullptr);
+	cmdb->enableDepthWrite(true);
+	cmdb->setDepthCompareFunction(CompareOperation::ALWAYS);
 
 	m_r->drawQuad(cmdb);
 
@@ -150,29 +142,30 @@ DepthDownscale::~DepthDownscale()
 {
 }
 
-Error DepthDownscale::init(const ConfigSet& cfg)
+Error DepthDownscale::initInternal(const ConfigSet& cfg)
 {
-	GrManager& gr = getGrManager();
-
 	// Create shader
 	ANKI_CHECK(getResourceManager().loadResource("shaders/DepthDownscale.frag.glsl", m_frag));
 
-	// Create pipeline
-	PipelineInitInfo pinit;
-
-	pinit.m_inputAssembler.m_topology = PrimitiveTopology::TRIANGLE_STRIP;
-
-	pinit.m_depthStencil.m_depthWriteEnabled = true;
-	pinit.m_depthStencil.m_depthCompareFunction = CompareOperation::ALWAYS;
-	pinit.m_depthStencil.m_format = MS_DEPTH_ATTACHMENT_PIXEL_FORMAT;
-
-	pinit.m_shaders[ShaderType::VERTEX] = m_r->getDrawQuadVertexShader();
-	pinit.m_shaders[ShaderType::FRAGMENT] = m_frag->getGrShader();
-	m_ppline = gr.newInstance<Pipeline>(pinit);
+	// Create prog
+	m_r->createDrawQuadShaderProgram(m_frag->getGrShader(), m_prog);
 
 	ANKI_CHECK(m_hd.init(cfg));
 	ANKI_CHECK(m_qd.init(cfg));
 	return ErrorCode::NONE;
 }
 
+Error DepthDownscale::init(const ConfigSet& cfg)
+{
+	ANKI_LOGI("Initializing depth downscale passes");
+
+	Error err = initInternal(cfg);
+	if(err)
+	{
+		ANKI_LOGE("Failed to initialize depth downscale passes");
+	}
+
+	return err;
+}
+
 } // end namespace anki

+ 3 - 3
src/anki/renderer/DepthDownscale.h

@@ -42,7 +42,6 @@ anki_internal:
 private:
 	DepthDownscale* m_parent;
 
-	ResourceGroupPtr m_rcgroup;
 	FramebufferPtr m_fb;
 };
 
@@ -69,7 +68,6 @@ anki_internal:
 private:
 	DepthDownscale* m_parent;
 
-	ResourceGroupPtr m_rcgroup;
 	FramebufferPtr m_fb;
 };
 
@@ -95,7 +93,9 @@ anki_internal:
 
 private:
 	ShaderResourcePtr m_frag;
-	PipelinePtr m_ppline;
+	ShaderProgramPtr m_prog;
+
+	ANKI_USE_RESULT Error initInternal(const ConfigSet& cfg);
 };
 /// @}
 

+ 55 - 63
src/anki/renderer/Drawer.cpp

@@ -4,7 +4,6 @@
 // http://www.anki3d.org/LICENSE
 
 #include <anki/renderer/Drawer.h>
-#include <anki/renderer/Ms.h>
 #include <anki/resource/ShaderResource.h>
 #include <anki/scene/FrustumComponent.h>
 #include <anki/resource/Material.h>
@@ -30,43 +29,60 @@ static Bool canMergeBuildInfo(const RenderingBuildInfoOut& a, const RenderingBui
 
 	ANKI_ASSERT(a.m_hasTransform == b.m_hasTransform);
 
-	if(a.m_resourceGroup != b.m_resourceGroup)
+	if(a.m_program != b.m_program)
 	{
 		return false;
 	}
 
-	for(U i = 0; i < U(ShaderType::COUNT); ++i)
+	if(a.m_vertexBufferBindingCount != b.m_vertexBufferBindingCount
+		|| a.m_vertexAttributeCount != b.m_vertexAttributeCount)
 	{
-		if(a.m_state->m_shaders[i] != b.m_state->m_shaders[i])
+		return false;
+	}
+
+	for(U i = 0; i < a.m_vertexBufferBindingCount; ++i)
+	{
+		if(a.m_vertexBufferBindings[i] != b.m_vertexBufferBindings[i])
 		{
 			return false;
 		}
 	}
 
-	// Drawcall
-	if(a.m_drawArrays != b.m_drawArrays)
+	for(U i = 0; i < a.m_vertexAttributeCount; ++i)
+	{
+		if(a.m_vertexAttributes[i] != b.m_vertexAttributes[i])
+		{
+			return false;
+		}
+	}
+
+	if(a.m_indexBuffer != b.m_indexBuffer)
 	{
 		return false;
 	}
 
-	if(a.m_drawArrays && a.m_drawcall.m_arrays != b.m_drawcall.m_arrays)
+	if(a.m_indexBufferToken != b.m_indexBufferToken)
 	{
 		return false;
 	}
 
-	if(!a.m_drawArrays && a.m_drawcall.m_elements != b.m_drawcall.m_elements)
+	// Drawcall
+	if(a.m_drawArrays != b.m_drawArrays)
+	{
+		return false;
+	}
+
+	if(a.m_drawArrays && a.m_drawcall.m_arrays != b.m_drawcall.m_arrays)
 	{
 		return false;
 	}
 
-	// Vertex
-	if(a.m_state->m_vertex != b.m_state->m_vertex)
+	if(!a.m_drawArrays && a.m_drawcall.m_elements != b.m_drawcall.m_elements)
 	{
 		return false;
 	}
 
-	// IA
-	if(a.m_state->m_inputAssembler != b.m_state->m_inputAssembler)
+	if(a.m_topology != b.m_topology)
 	{
 		return false;
 	}
@@ -76,15 +92,18 @@ static Bool canMergeBuildInfo(const RenderingBuildInfoOut& a, const RenderingBui
 
 static void resetRenderingBuildInfoOut(RenderingBuildInfoOut& b)
 {
-	b.m_resourceGroup.reset(nullptr);
-	b.m_drawcall.m_elements = DrawElementsIndirectInfo();
-	b.m_drawArrays = false;
 	b.m_hasTransform = false;
-	b.m_stateMask = PipelineSubStateBit::NONE;
+	b.m_program = {};
+
+	b.m_vertexBufferBindingCount = 0;
+	b.m_vertexAttributeCount = 0;
 
-	b.m_state->m_inputAssembler = InputAssemblerStateInfo();
-	b.m_state->m_vertex = VertexStateInfo();
-	b.m_state->m_shaders = Array<ShaderPtr, U(ShaderType::COUNT)>();
+	b.m_indexBuffer = {};
+	b.m_indexBufferToken = {};
+
+	b.m_drawcall.m_elements = DrawElementsIndirectInfo();
+	b.m_drawArrays = false;
+	b.m_topology = PrimitiveTopology::TRIANGLES;
 }
 
 class CompleteRenderingBuildInfo
@@ -94,11 +113,6 @@ public:
 	RenderComponent* m_rc = nullptr;
 	RenderingBuildInfoIn m_in;
 	RenderingBuildInfoOut m_out;
-
-	CompleteRenderingBuildInfo(PipelineInitInfo* state)
-		: m_out(state)
-	{
-	}
 };
 
 /// Drawer's context
@@ -114,19 +128,12 @@ public:
 	Array<Mat4, MAX_INSTANCES> m_cachedTrfs;
 	U m_cachedTrfCount = 0;
 
-	TransientMemoryInfo m_dynBufferInfo;
-	U m_nodeProcessedCount = 0;
+	TransientMemoryToken m_uboToken;
 
-	GrObjectCache* m_pplineCache;
+	U m_nodeProcessedCount = 0;
 
 	Array<CompleteRenderingBuildInfo, 2> m_buildInfo;
-	Array<PipelineInitInfo, 2> m_state;
 	U m_crntBuildInfo = 0;
-
-	DrawContext()
-		: m_buildInfo{{&m_state[0], &m_state[1]}}
-	{
-	}
 };
 
 /// Visitor that sets a uniform
@@ -276,7 +283,8 @@ void SetupRenderableVariableVisitor::uniSet<TextureResourcePtr>(
 	const MaterialVariable& mtlvar, const TextureResourcePtr* values, U32 size)
 {
 	ANKI_ASSERT(size == 1);
-	// Do nothing
+	ANKI_ASSERT(values);
+	m_ctx->m_cmdb->bindTexture(0, mtlvar.getTextureUnit(), (*values)->getGrTexture());
 }
 
 RenderableDrawer::~RenderableDrawer()
@@ -290,7 +298,7 @@ void RenderableDrawer::setupUniforms(DrawContext& ctx, CompleteRenderingBuildInf
 
 	// Get some memory for uniforms
 	U8* uniforms = static_cast<U8*>(m_r->getGrManager().allocateFrameTransientMemory(
-		variant.getDefaultBlockSize(), BufferUsageBit::UNIFORM_ALL, ctx.m_dynBufferInfo.m_uniformBuffers[0]));
+		variant.getDefaultBlockSize(), BufferUsageBit::UNIFORM_ALL, ctx.m_uboToken));
 
 	// Call the visitor
 	SetupRenderableVariableVisitor visitor;
@@ -312,13 +320,8 @@ void RenderableDrawer::setupUniforms(DrawContext& ctx, CompleteRenderingBuildInf
 	}
 }
 
-Error RenderableDrawer::drawRange(Pass pass,
-	const FrustumComponent& frc,
-	CommandBufferPtr cmdb,
-	GrObjectCache& pplineCache,
-	const PipelineInitInfo& state,
-	VisibleNode* begin,
-	VisibleNode* end)
+Error RenderableDrawer::drawRange(
+	Pass pass, const FrustumComponent& frc, CommandBufferPtr cmdb, VisibleNode* begin, VisibleNode* end)
 {
 	ANKI_ASSERT(begin && end && begin < end);
 
@@ -326,9 +329,6 @@ Error RenderableDrawer::drawRange(Pass pass,
 	ctx.m_frc = &frc;
 	ctx.m_pass = pass;
 	ctx.m_cmdb = cmdb;
-	ctx.m_pplineCache = &pplineCache;
-	ctx.m_state[0] = state;
-	ctx.m_state[1] = state;
 
 	for(; begin != end; ++begin)
 	{
@@ -357,35 +357,29 @@ Error RenderableDrawer::flushDrawcall(DrawContext& ctx, CompleteRenderingBuildIn
 		ANKI_CHECK(rc.buildRendering(build.m_in, build.m_out));
 	}
 
-	// Create the pipeline
-	U64 pplineHash = build.m_out.m_state->computeHash();
-	PipelinePtr ppline;
-	Bool pplineFound = rc.tryGetPipeline(pplineHash, ppline);
-
-	if(ANKI_UNLIKELY(!pplineFound))
-	{
-		ppline = ctx.m_pplineCache->newInstance<Pipeline>(*build.m_out.m_state, pplineHash);
-		rc.storePipeline(pplineHash, ppline);
-	}
-
 	// Enqueue uniform state updates
 	setupUniforms(ctx, build);
 
 	// Finaly, touch the command buffer
-	ctx.m_cmdb->bindResourceGroup(build.m_out.m_resourceGroup, 0, &ctx.m_dynBufferInfo);
-	ctx.m_cmdb->bindPipeline(ppline);
+	ctx.m_cmdb->bindUniformBuffer(0, 0, ctx.m_uboToken);
+	ctx.m_cmdb->bindShaderProgram(build.m_out.m_program);
 	if(!build.m_out.m_drawArrays)
 	{
 		const DrawElementsIndirectInfo& drawc = build.m_out.m_drawcall.m_elements;
 
-		ctx.m_cmdb->drawElements(
-			drawc.m_count, drawc.m_instanceCount, drawc.m_firstIndex, drawc.m_baseVertex, drawc.m_baseInstance);
+		ctx.m_cmdb->drawElements(build.m_out.m_topology,
+			drawc.m_count,
+			drawc.m_instanceCount,
+			drawc.m_firstIndex,
+			drawc.m_baseVertex,
+			drawc.m_baseInstance);
 	}
 	else
 	{
 		const DrawArraysIndirectInfo& drawc = build.m_out.m_drawcall.m_arrays;
 
-		ctx.m_cmdb->drawArrays(drawc.m_count, drawc.m_instanceCount, drawc.m_first, drawc.m_baseInstance);
+		ctx.m_cmdb->drawArrays(
+			build.m_out.m_topology, drawc.m_count, drawc.m_instanceCount, drawc.m_first, drawc.m_baseInstance);
 	}
 
 	// Rendered something, reset the cached transforms
@@ -426,8 +420,6 @@ Error RenderableDrawer::drawSingle(DrawContext& ctx)
 
 	resetRenderingBuildInfoOut(crntBuild.m_out);
 	ANKI_CHECK(renderable.buildRendering(crntBuild.m_in, crntBuild.m_out));
-	ANKI_ASSERT(crntBuild.m_out.m_stateMask
-		== (PipelineSubStateBit::VERTEX | PipelineSubStateBit::INPUT_ASSEMBLER | PipelineSubStateBit::SHADERS));
 
 	if(ANKI_UNLIKELY(ctx.m_nodeProcessedCount == 0))
 	{

+ 2 - 7
src/anki/renderer/Drawer.h

@@ -34,13 +34,8 @@ public:
 
 	~RenderableDrawer();
 
-	ANKI_USE_RESULT Error drawRange(Pass pass,
-		const FrustumComponent& frc,
-		CommandBufferPtr cmdb,
-		GrObjectCache& pplineCache,
-		const PipelineInitInfo& state,
-		VisibleNode* begin,
-		VisibleNode* end);
+	ANKI_USE_RESULT Error drawRange(
+		Pass pass, const FrustumComponent& frc, CommandBufferPtr cmdb, VisibleNode* begin, VisibleNode* end);
 
 private:
 	Renderer* m_r;

+ 64 - 135
src/anki/renderer/Is.cpp

@@ -6,7 +6,6 @@
 #include <anki/renderer/Is.h>
 #include <anki/renderer/Renderer.h>
 #include <anki/renderer/Sm.h>
-#include <anki/renderer/Pps.h>
 #include <anki/renderer/Ir.h>
 #include <anki/renderer/Ms.h>
 #include <anki/renderer/LightBin.h>
@@ -54,11 +53,12 @@ Is::~Is()
 
 Error Is::init(const ConfigSet& config)
 {
+	ANKI_LOGE("Initializing light stage");
 	Error err = initInternal(config);
 
 	if(err)
 	{
-		ANKI_LOGE("Failed to init IS");
+		ANKI_LOGE("Failed to init light stage");
 	}
 
 	return err;
@@ -93,7 +93,7 @@ Error Is::initInternal(const ConfigSet& config)
 	//
 	StringAuto pps(getAllocator());
 
-	pps.sprintf("\n#define TILE_COUNT_X %u\n"
+	pps.sprintf("#define TILE_COUNT_X %u\n"
 				"#define TILE_COUNT_Y %u\n"
 				"#define CLUSTER_COUNT %u\n"
 				"#define RENDERER_WIDTH %u\n"
@@ -113,20 +113,8 @@ Error Is::initInternal(const ConfigSet& config)
 		m_r->getIr().getReflectionTextureMipmapCount());
 
 	// point light
-	ANKI_CHECK(getResourceManager().loadResourceToCache(m_lightVert, "shaders/Is.vert.glsl", pps.toCString(), "r_"));
-
-	ANKI_CHECK(getResourceManager().loadResourceToCache(m_lightFrag, "shaders/Is.frag.glsl", pps.toCString(), "r_"));
-
-	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_color.m_attachmentCount = 1;
-	init.m_color.m_attachments[0].m_format = IS_COLOR_ATTACHMENT_PIXEL_FORMAT;
-	init.m_shaders[U(ShaderType::VERTEX)] = m_lightVert->getGrShader();
-	init.m_shaders[U(ShaderType::FRAGMENT)] = m_lightFrag->getGrShader();
-	m_lightPpline = getGrManager().newInstance<Pipeline>(init);
+	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]));
 
 	//
 	// Create framebuffer
@@ -147,44 +135,6 @@ Error Is::initInternal(const ConfigSet& config)
 	fbInit.m_colorAttachments[0].m_usageInsideRenderPass = TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE;
 	m_fb = getGrManager().newInstance<Framebuffer>(fbInit);
 
-	//
-	// Create resource group
-	//
-	{
-		ResourceGroupInitInfo init;
-		init.m_textures[0].m_texture = m_r->getMs().m_rt0;
-		init.m_textures[1].m_texture = m_r->getMs().m_rt1;
-		init.m_textures[2].m_texture = m_r->getMs().m_rt2;
-		init.m_textures[3].m_texture = m_r->getMs().m_depthRt;
-		init.m_textures[3].m_usage = TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ;
-		init.m_textures[4].m_texture = m_r->getSm().getSpotTextureArray();
-		init.m_textures[5].m_texture = m_r->getSm().getOmniTextureArray();
-
-		init.m_textures[6].m_texture = m_r->getIr().getReflectionTexture();
-		init.m_textures[7].m_texture = m_r->getIr().getIrradianceTexture();
-
-		init.m_textures[8].m_texture = m_r->getIr().getIntegrationLut();
-		init.m_textures[8].m_sampler = m_r->getIr().getIntegrationLutSampler();
-
-		init.m_uniformBuffers[0].m_uploadedMemory = true;
-		init.m_uniformBuffers[0].m_usage = BufferUsageBit::UNIFORM_FRAGMENT | BufferUsageBit::UNIFORM_VERTEX;
-		init.m_uniformBuffers[1].m_uploadedMemory = true;
-		init.m_uniformBuffers[1].m_usage = BufferUsageBit::UNIFORM_FRAGMENT | BufferUsageBit::UNIFORM_VERTEX;
-		init.m_uniformBuffers[2].m_uploadedMemory = true;
-		init.m_uniformBuffers[2].m_usage = BufferUsageBit::UNIFORM_FRAGMENT | BufferUsageBit::UNIFORM_VERTEX;
-		init.m_uniformBuffers[3].m_uploadedMemory = true;
-		init.m_uniformBuffers[3].m_usage = BufferUsageBit::UNIFORM_FRAGMENT | BufferUsageBit::UNIFORM_VERTEX;
-		init.m_uniformBuffers[4].m_uploadedMemory = true;
-		init.m_uniformBuffers[4].m_usage = BufferUsageBit::UNIFORM_FRAGMENT | BufferUsageBit::UNIFORM_VERTEX;
-
-		init.m_storageBuffers[0].m_uploadedMemory = true;
-		init.m_storageBuffers[0].m_usage = BufferUsageBit::STORAGE_FRAGMENT_READ | BufferUsageBit::STORAGE_VERTEX_READ;
-		init.m_storageBuffers[1].m_uploadedMemory = true;
-		init.m_storageBuffers[1].m_usage = BufferUsageBit::STORAGE_FRAGMENT_READ | BufferUsageBit::STORAGE_VERTEX_READ;
-
-		m_rcGroup = getGrManager().newInstance<ResourceGroup>(init);
-	}
-
 	TextureInitInfo texinit;
 	texinit.m_width = texinit.m_height = 4;
 	texinit.m_usage = TextureUsageBit::SAMPLED_FRAGMENT;
@@ -198,48 +148,18 @@ Error Is::binLights(RenderingContext& ctx)
 {
 	updateCommonBlock(ctx);
 
-	TexturePtr diffDecalTex, normRoughnessDecalTex;
-
 	ANKI_CHECK(m_lightBin->bin(*ctx.m_frustumComponent,
 		getFrameAllocator(),
 		m_maxLightIds,
 		true,
-		ctx.m_is.m_dynBufferInfo.m_uniformBuffers[P_LIGHTS_LOCATION],
-		ctx.m_is.m_dynBufferInfo.m_uniformBuffers[S_LIGHTS_LOCATION],
-		&ctx.m_is.m_dynBufferInfo.m_uniformBuffers[PROBES_LOCATION],
-		ctx.m_is.m_dynBufferInfo.m_uniformBuffers[DECALS_LOCATION],
-		ctx.m_is.m_dynBufferInfo.m_storageBuffers[CLUSTERS_LOCATION],
-		ctx.m_is.m_dynBufferInfo.m_storageBuffers[LIGHT_IDS_LOCATION],
-		diffDecalTex,
-		normRoughnessDecalTex));
-
-	ResourceGroupInitInfo rcinit;
-	if(diffDecalTex)
-	{
-		rcinit.m_textures[0].m_texture = diffDecalTex;
-	}
-	else
-	{
-		// Bind something because validation layers will complain
-		rcinit.m_textures[0].m_texture = m_dummyTex;
-	}
-
-	if(normRoughnessDecalTex)
-	{
-		rcinit.m_textures[1].m_texture = normRoughnessDecalTex;
-	}
-	else
-	{
-		rcinit.m_textures[1].m_texture = m_dummyTex;
-	}
-
-	U64 hash = rcinit.computeHash();
-	if(hash != m_rcGroup1Hash)
-	{
-		m_rcGroup1Hash = hash;
-
-		m_rcGroup1 = getGrManager().newInstance<ResourceGroup>(rcinit);
-	}
+		ctx.m_is.m_pointLightsToken,
+		ctx.m_is.m_spotLightsToken,
+		&ctx.m_is.m_probesToken,
+		ctx.m_is.m_decalsToken,
+		ctx.m_is.m_clustersToken,
+		ctx.m_is.m_lightIndicesToken,
+		ctx.m_is.m_diffDecalTex,
+		ctx.m_is.m_normRoughnessDecalTex));
 
 	return ErrorCode::NONE;
 }
@@ -250,20 +170,39 @@ void Is::run(RenderingContext& ctx)
 
 	cmdb->beginRenderPass(m_fb);
 	cmdb->setViewport(0, 0, m_r->getWidth(), m_r->getHeight());
-	cmdb->bindPipeline(m_lightPpline);
-	cmdb->bindResourceGroup(m_rcGroup, 0, &ctx.m_is.m_dynBufferInfo);
-	cmdb->bindResourceGroup(m_rcGroup1, 1, nullptr);
-	cmdb->drawArrays(4, m_r->getTileCount());
+	cmdb->bindShaderProgram(m_lightProg);
+
+	cmdb->bindTexture(0, 0, m_r->getMs().m_rt0);
+	cmdb->bindTexture(0, 1, m_r->getMs().m_rt1);
+	cmdb->bindTexture(0, 2, m_r->getMs().m_rt2);
+	cmdb->bindTexture(0, 3, m_r->getMs().m_depthRt, DepthStencilAspectMask::DEPTH);
+	cmdb->bindTexture(0, 4, m_r->getSm().getSpotTextureArray());
+	cmdb->bindTexture(0, 5, m_r->getSm().getOmniTextureArray());
+	cmdb->bindTexture(0, 6, m_r->getIr().getReflectionTexture());
+	cmdb->bindTexture(0, 7, m_r->getIr().getIrradianceTexture());
+	cmdb->bindTextureAndSampler(0, 8, m_r->getIr().getIntegrationLut(), m_r->getIr().getIntegrationLutSampler());
+
+	cmdb->bindTexture(1, 0, (ctx.m_is.m_diffDecalTex) ? ctx.m_is.m_diffDecalTex : m_dummyTex);
+	cmdb->bindTexture(1, 1, (ctx.m_is.m_normRoughnessDecalTex) ? ctx.m_is.m_normRoughnessDecalTex : m_dummyTex);
+
+	cmdb->bindUniformBuffer(0, 0, ctx.m_is.m_commonToken);
+	cmdb->bindUniformBuffer(0, 1, ctx.m_is.m_pointLightsToken);
+	cmdb->bindUniformBuffer(0, 2, ctx.m_is.m_spotLightsToken);
+	cmdb->bindUniformBuffer(0, 3, ctx.m_is.m_probesToken);
+	cmdb->bindUniformBuffer(0, 4, ctx.m_is.m_decalsToken);
+
+	cmdb->bindStorageBuffer(0, 0, ctx.m_is.m_clustersToken);
+	cmdb->bindStorageBuffer(0, 1, ctx.m_is.m_lightIndicesToken);
+
+	cmdb->drawArrays(PrimitiveTopology::TRIANGLE_STRIP, 4, m_r->getTileCount());
 	cmdb->endRenderPass();
 }
 
 void Is::updateCommonBlock(RenderingContext& ctx)
 {
 	const FrustumComponent& fr = *ctx.m_frustumComponent;
-	ShaderCommonUniforms* blk =
-		static_cast<ShaderCommonUniforms*>(getGrManager().allocateFrameTransientMemory(sizeof(ShaderCommonUniforms),
-			BufferUsageBit::UNIFORM_ALL,
-			ctx.m_is.m_dynBufferInfo.m_uniformBuffers[COMMON_VARS_LOCATION]));
+	ShaderCommonUniforms* blk = static_cast<ShaderCommonUniforms*>(getGrManager().allocateFrameTransientMemory(
+		sizeof(ShaderCommonUniforms), BufferUsageBit::UNIFORM_ALL, ctx.m_is.m_commonToken));
 
 	// Start writing
 	blk->m_projectionParams = fr.getProjectionParameters();
@@ -286,31 +225,33 @@ void Is::setPreRunBarriers(RenderingContext& ctx)
 		TextureSurfaceInfo(0, 0, 0, 0));
 }
 
-Error Is::getOrCreatePipeline(ShaderVariantBit variantMask, RenderingContext& ctx, PipelinePtr& ppline)
+Error Is::getOrCreateProgram(ShaderVariantBit variantMask, RenderingContext& ctx, ShaderProgramPtr& prog)
 {
 	auto it = m_shaderVariantMap.find(variantMask);
 	if(it != m_shaderVariantMap.getEnd())
 	{
-		ppline = it->m_lightPpline;
+		prog = it->m_lightProg;
 	}
 	else
 	{
-		StringAuto pps(ctx.m_tempAllocator);
-
-		pps.sprintf("#define TILE_COUNT_X %u\n"
-					"#define TILE_COUNT_Y %u\n"
-					"#define CLUSTER_COUNT %u\n"
-					"#define RENDERER_WIDTH %u\n"
-					"#define RENDERER_HEIGHT %u\n"
-					"#define MAX_LIGHT_INDICES %u\n"
-					"#define POISSON %u\n"
-					"#define INDIRECT_ENABLED %u\n"
-					"#define IR_MIPMAP_COUNT %u\n"
-					"#define POINT_LIGHTS_ENABLED %u\n"
-					"#define SPOT_LIGHTS_ENABLED %u\n"
-					"#define DECALS_ENABLED %u\n"
-					"#define POINT_LIGHTS_SHADOWS_ENABLED %u\n"
-					"#define SPOT_LIGHTS_SHADOWS_ENABLED %u\n",
+		ShaderVariant variant;
+
+		ANKI_CHECK(m_r->createShader("shaders/Is.frag.glsl",
+			variant.m_lightFrag,
+			"#define TILE_COUNT_X %u\n"
+			"#define TILE_COUNT_Y %u\n"
+			"#define CLUSTER_COUNT %u\n"
+			"#define RENDERER_WIDTH %u\n"
+			"#define RENDERER_HEIGHT %u\n"
+			"#define MAX_LIGHT_INDICES %u\n"
+			"#define POISSON %u\n"
+			"#define INDIRECT_ENABLED %u\n"
+			"#define IR_MIPMAP_COUNT %u\n"
+			"#define POINT_LIGHTS_ENABLED %u\n"
+			"#define SPOT_LIGHTS_ENABLED %u\n"
+			"#define DECALS_ENABLED %u\n"
+			"#define POINT_LIGHTS_SHADOWS_ENABLED %u\n"
+			"#define SPOT_LIGHTS_SHADOWS_ENABLED %u\n",
 			m_r->getTileCountXY().x(),
 			m_r->getTileCountXY().y(),
 			m_clusterCount,
@@ -324,24 +265,12 @@ Error Is::getOrCreatePipeline(ShaderVariantBit variantMask, RenderingContext& ct
 			!!(variantMask & ShaderVariantBit::S_LIGHTS),
 			!!(variantMask & ShaderVariantBit::DECALS),
 			!!(variantMask & ShaderVariantBit::P_LIGHTS_SHADOWS),
-			!!(variantMask & ShaderVariantBit::S_LIGHTS_SHADOWS));
-
-		ShaderVariant variant;
-		ANKI_CHECK(getResourceManager().loadResourceToCache(
-			variant.m_lightFrag, "shaders/Is.frag.glsl", pps.toCString(), "r_"));
-
-		PipelineInitInfo init;
+			!!(variantMask & ShaderVariantBit::S_LIGHTS_SHADOWS)));
 
-		init.m_inputAssembler.m_topology = PrimitiveTopology::TRIANGLE_STRIP;
-		init.m_depthStencil.m_depthWriteEnabled = false;
-		init.m_depthStencil.m_depthCompareFunction = CompareOperation::ALWAYS;
-		init.m_color.m_attachmentCount = 1;
-		init.m_color.m_attachments[0].m_format = IS_COLOR_ATTACHMENT_PIXEL_FORMAT;
-		init.m_shaders[U(ShaderType::VERTEX)] = m_lightVert->getGrShader();
-		init.m_shaders[U(ShaderType::FRAGMENT)] = m_lightFrag->getGrShader();
-		variant.m_lightPpline = getGrManager().newInstance<Pipeline>(init);
+		variant.m_lightProg =
+			getGrManager().newInstance<ShaderProgram>(m_lightVert->getGrShader(), variant.m_lightFrag->getGrShader());
 
-		ppline = variant.m_lightPpline;
+		prog = variant.m_lightProg;
 
 		m_shaderVariantMap.pushBack(getAllocator(), variantMask, variant);
 	}

+ 4 - 15
src/anki/renderer/Is.h

@@ -53,14 +53,6 @@ anki_internal:
 	}
 
 private:
-	static const U COMMON_VARS_LOCATION = 0;
-	static const U P_LIGHTS_LOCATION = 1;
-	static const U S_LIGHTS_LOCATION = 2;
-	static const U PROBES_LOCATION = 3;
-	static const U DECALS_LOCATION = 4;
-	static const U CLUSTERS_LOCATION = 0;
-	static const U LIGHT_IDS_LOCATION = 1;
-
 	/// The IS render target
 	TexturePtr m_rt;
 	U8 m_rtMipCount = 0;
@@ -69,22 +61,18 @@ private:
 	/// The IS FBO
 	FramebufferPtr m_fb;
 
-	ResourceGroupPtr m_rcGroup;
-	U64 m_rcGroup1Hash = 0;
-	ResourceGroupPtr m_rcGroup1;
-
 	TexturePtr m_dummyTex;
 
 	// Light shaders
 	ShaderResourcePtr m_lightVert;
 	ShaderResourcePtr m_lightFrag;
-	PipelinePtr m_lightPpline;
+	ShaderProgramPtr m_lightProg;
 
 	class ShaderVariant
 	{
 	public:
 		ShaderResourcePtr m_lightFrag;
-		PipelinePtr m_lightPpline;
+		ShaderProgramPtr m_lightProg;
 	};
 
 	using Key = ShaderVariantBit;
@@ -113,7 +101,8 @@ private:
 
 	void updateCommonBlock(RenderingContext& ctx);
 
-	ANKI_USE_RESULT Error getOrCreatePipeline(ShaderVariantBit variantMask, RenderingContext& ctx, PipelinePtr& ppline);
+	ANKI_USE_RESULT Error getOrCreateProgram(
+		ShaderVariantBit variantMask, RenderingContext& ctx, ShaderProgramPtr& prog);
 };
 /// @}
 

+ 7 - 25
src/anki/renderer/Ms.cpp

@@ -17,10 +17,6 @@ namespace anki
 
 Ms::~Ms()
 {
-	if(m_pplineCache)
-	{
-		getAllocator().deleteInstance(m_pplineCache);
-	}
 }
 
 Error Ms::createRt(U32 samples)
@@ -91,10 +87,12 @@ Error Ms::createRt(U32 samples)
 
 Error Ms::init(const ConfigSet& initializer)
 {
+	ANKI_LOGI("Initializing g-buffer pass");
+
 	Error err = initInternal(initializer);
 	if(err)
 	{
-		ANKI_LOGE("Failed to initialize material stage");
+		ANKI_LOGE("Failed to initialize g-buffer pass");
 	}
 
 	return err;
@@ -103,21 +101,6 @@ Error Ms::init(const ConfigSet& initializer)
 Error Ms::initInternal(const ConfigSet& initializer)
 {
 	ANKI_CHECK(createRt(initializer.getNumber("samples")));
-
-	getGrManager().finish();
-
-	{
-		ColorStateInfo& color = m_state.m_color;
-		color.m_attachmentCount = MS_COLOR_ATTACHMENT_COUNT;
-		color.m_attachments[0].m_format = MS_COLOR_ATTACHMENT_PIXEL_FORMATS[0];
-		color.m_attachments[1].m_format = MS_COLOR_ATTACHMENT_PIXEL_FORMATS[1];
-		color.m_attachments[2].m_format = MS_COLOR_ATTACHMENT_PIXEL_FORMATS[2];
-
-		m_state.m_depthStencil.m_format = MS_DEPTH_ATTACHMENT_PIXEL_FORMAT;
-	}
-
-	m_pplineCache = getAllocator().newInstance<GrObjectCache>(&getGrManager());
-
 	return ErrorCode::NONE;
 }
 
@@ -134,21 +117,20 @@ Error Ms::buildCommandBuffers(RenderingContext& ctx, U threadId, U threadCount)
 
 	if(start != end)
 	{
-		// Create the command buffer and set some state
+		// Create the command buffer
 		CommandBufferInitInfo cinf;
-		cinf.m_flags = CommandBufferFlag::SECOND_LEVEL;
+		cinf.m_flags = CommandBufferFlag::SECOND_LEVEL | CommandBufferFlag::GRAPHICS_WORK;
 		cinf.m_framebuffer = m_fb;
 		CommandBufferPtr cmdb = m_r->getGrManager().newInstance<CommandBuffer>(cinf);
 		ctx.m_ms.m_commandBuffers[threadId] = cmdb;
+
+		// Set some state, leave the rest to default
 		cmdb->setViewport(0, 0, m_r->getWidth(), m_r->getHeight());
-		cmdb->setPolygonOffset(0.0, 0.0);
 
 		// Start drawing
 		ANKI_CHECK(m_r->getSceneDrawer().drawRange(Pass::MS_FS,
 			*ctx.m_frustumComponent,
 			cmdb,
-			*m_pplineCache,
-			m_state,
 			vis.getBegin(VisibilityGroupType::RENDERABLES_MS) + start,
 			vis.getBegin(VisibilityGroupType::RENDERABLES_MS) + end));
 	}

+ 0 - 3
src/anki/renderer/Ms.h

@@ -23,9 +23,6 @@ anki_internal:
 	TexturePtr m_rt2;
 	TexturePtr m_depthRt;
 
-	PipelineInitInfo m_state;
-	GrObjectCache* m_pplineCache = nullptr;
-
 	Ms(Renderer* r)
 		: RenderingPass(r)
 	{

+ 32 - 65
src/anki/renderer/Pps.cpp

@@ -78,7 +78,6 @@ Error Pps::loadColorGradingTexture(CString filename)
 	ANKI_ASSERT(m_lut->getHeight() == LUT_SIZE);
 	ANKI_ASSERT(m_lut->getDepth() == LUT_SIZE);
 
-	m_lutDirty = true;
 	return ErrorCode::NONE;
 }
 
@@ -91,27 +90,27 @@ Error Pps::run(RenderingContext& ctx)
 	Bool dbgEnabled = m_r->getDbg().getEnabled();
 
 	// Get or create the ppline
-	PipelinePtr& ppline = m_ppline[drawToDefaultFb][dbgEnabled];
+	ShaderProgramPtr& prog = m_prog[drawToDefaultFb][dbgEnabled];
 
-	if(!ppline)
+	if(!prog)
 	{
 		// Need to create it
 
 		ShaderResourcePtr& frag = m_frag[drawToDefaultFb][dbgEnabled];
 		if(!frag)
 		{
-			StringAuto pps(ctx.m_tempAllocator);
-
-			pps.sprintf("#define BLOOM_ENABLED %u\n"
-						"#define SHARPEN_ENABLED %u\n"
-						"#define FBO_WIDTH %u\n"
-						"#define FBO_HEIGHT %u\n"
-						"#define LUT_SIZE %u.0\n"
-						"#define DBG_ENABLED %u\n"
-						"#define DRAW_TO_DEFAULT %u\n"
-						"#define SMAA_ENABLED 1\n"
-						"#define SMAA_RT_METRICS vec4(%f, %f, %f, %f)\n"
-						"#define SMAA_PRESET_%s\n",
+			ANKI_CHECK(m_r->createShaderf("shaders/Pps.frag.glsl",
+				frag,
+				"#define BLOOM_ENABLED %u\n"
+				"#define SHARPEN_ENABLED %u\n"
+				"#define FBO_WIDTH %u\n"
+				"#define FBO_HEIGHT %u\n"
+				"#define LUT_SIZE %u.0\n"
+				"#define DBG_ENABLED %u\n"
+				"#define DRAW_TO_DEFAULT %u\n"
+				"#define SMAA_ENABLED 1\n"
+				"#define SMAA_RT_METRICS vec4(%f, %f, %f, %f)\n"
+				"#define SMAA_PRESET_%s\n",
 				true,
 				m_sharpenEnabled,
 				m_r->getWidth(),
@@ -123,69 +122,38 @@ Error Pps::run(RenderingContext& ctx)
 				1.0 / m_r->getHeight(),
 				F32(m_r->getWidth()),
 				F32(m_r->getHeight()),
-				&m_r->getSmaa().m_qualityPerset[0]);
-
-			ANKI_CHECK(getResourceManager().loadResourceToCache(frag, "shaders/Pps.frag.glsl", pps.toCString(), "r_"));
+				&m_r->getSmaa().m_qualityPerset[0]));
 		}
 
 		if(!m_vert)
 		{
-			StringAuto pps(ctx.m_tempAllocator);
-
-			pps.sprintf("#define SMAA_ENABLED 1\n"
-						"#define SMAA_RT_METRICS vec4(%f, %f, %f, %f)\n"
-						"#define SMAA_PRESET_%s\n",
+			ANKI_CHECK(m_r->createShaderf("shaders/Pps.vert.glsl",
+				m_vert,
+				"#define SMAA_ENABLED 1\n"
+				"#define SMAA_RT_METRICS vec4(%f, %f, %f, %f)\n"
+				"#define SMAA_PRESET_%s\n",
 				1.0 / m_r->getWidth(),
 				1.0 / m_r->getHeight(),
 				F32(m_r->getWidth()),
 				F32(m_r->getHeight()),
-				&m_r->getSmaa().m_qualityPerset[0]);
-
-			ANKI_CHECK(
-				getResourceManager().loadResourceToCache(m_vert, "shaders/Pps.vert.glsl", pps.toCString(), "r_"));
+				&m_r->getSmaa().m_qualityPerset[0]));
 		}
 
-		PixelFormat pfs = (drawToDefaultFb) ? PixelFormat(ComponentFormat::DEFAULT_FRAMEBUFFER, TransformFormat::NONE)
-											: RT_PIXEL_FORMAT;
-
-		PipelineInitInfo ppinit;
-
-		ppinit.m_inputAssembler.m_topology = PrimitiveTopology::TRIANGLE_STRIP;
-
-		ppinit.m_depthStencil.m_depthWriteEnabled = false;
-		ppinit.m_depthStencil.m_depthCompareFunction = CompareOperation::ALWAYS;
-
-		ppinit.m_color.m_attachmentCount = 1;
-		ppinit.m_color.m_attachments[0].m_format = pfs;
-
-		ppinit.m_shaders[ShaderType::VERTEX] = m_vert->getGrShader();
-		ppinit.m_shaders[ShaderType::FRAGMENT] = frag->getGrShader();
-
-		ppline = m_r->getGrManager().newInstance<Pipeline>(ppinit);
+		prog = getGrManager().newInstance<ShaderProgram>(m_vert->getGrShader(), frag->getGrShader());
 	}
 
-	// Get or create the resource group
-	ResourceGroupPtr& rsrc = m_rcGroup[dbgEnabled];
-	if(!rsrc || m_lutDirty)
+	// Bind stuff
+	cmdb->bindTexture(0, 0, m_r->getIs().getRt());
+	cmdb->bindTexture(0, 1, m_r->getBloom().m_upscale.m_rt);
+	cmdb->bindTexture(0, 2, m_lut->getGrTexture());
+	cmdb->bindTexture(0, 3, m_r->getSmaa().m_weights.m_rt);
+	if(dbgEnabled)
 	{
-		ResourceGroupInitInfo rcInit;
-		rcInit.m_textures[0].m_texture = m_r->getIs().getRt();
-		rcInit.m_textures[1].m_texture = m_r->getBloom().m_upscale.m_rt;
-		rcInit.m_textures[2].m_texture = m_lut->getGrTexture();
-		rcInit.m_textures[3].m_texture = m_r->getSmaa().m_weights.m_rt;
-		if(dbgEnabled)
-		{
-			rcInit.m_textures[4].m_texture = m_r->getDbg().getRt();
-		}
-
-		rcInit.m_storageBuffers[0].m_buffer = m_r->getTm().getAverageLuminanceBuffer();
-		rcInit.m_storageBuffers[0].m_usage = BufferUsageBit::STORAGE_FRAGMENT_READ;
-
-		rsrc = getGrManager().newInstance<ResourceGroup>(rcInit);
-
-		m_lutDirty = false;
+		cmdb->bindTexture(0, 4, m_r->getDbg().getRt());
 	}
 
+	cmdb->bindStorageBuffer(0, 0, m_r->getTm().m_luminanceBuff, 0);
+
 	// Get or create FB
 	FramebufferPtr* fb = nullptr;
 	U width, height;
@@ -204,8 +172,7 @@ Error Pps::run(RenderingContext& ctx)
 
 	cmdb->beginRenderPass(*fb);
 	cmdb->setViewport(0, 0, width, height);
-	cmdb->bindPipeline(ppline);
-	cmdb->bindResourceGroup(rsrc, 0, nullptr);
+	cmdb->bindShaderProgram(prog);
 	m_r->drawQuad(cmdb);
 	cmdb->endRenderPass();
 

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

@@ -46,12 +46,10 @@ private:
 	FramebufferPtr m_fb;
 	Array2d<ShaderResourcePtr, 2, 2> m_frag; ///< One with Dbg and one without
 	ShaderResourcePtr m_vert;
-	Array2d<PipelinePtr, 2, 2> m_ppline; ///< With Dbg, Default FB or not
+	Array2d<ShaderProgramPtr, 2, 2> m_prog; ///< With Dbg, Default FB or not
 	TexturePtr m_rt;
-	Array<ResourceGroupPtr, 2> m_rcGroup; ///< One with Dbg and one without
 
 	TextureResourcePtr m_lut; ///< Color grading lookup texture.
-	Bool8 m_lutDirty = true;
 
 	Bool8 m_sharpenEnabled = false;
 

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

@@ -503,7 +503,12 @@ Error Renderer::buildCommandBuffers(RenderingContext& ctx)
 	return err;
 }
 
-Error Renderer::createShader(CString fname, ShaderResourcePtr& shader, CString fmt, ...)
+Error Renderer::createShader(CString fname, ShaderResourcePtr& shader, CString extra)
+{
+	return m_resources->loadResourceToCache(shader, fname, &extra[0], "r_");
+}
+
+Error Renderer::createShaderf(CString fname, ShaderResourcePtr& shader, CString fmt, ...)
 {
 	Array<char, 512> buffer;
 	va_list args;

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

@@ -66,7 +66,16 @@ public:
 	class Is
 	{
 	public:
-		TransientMemoryInfo m_dynBufferInfo;
+		TransientMemoryToken m_commonToken;
+		TransientMemoryToken m_pointLightsToken;
+		TransientMemoryToken m_spotLightsToken;
+		TransientMemoryToken m_probesToken;
+		TransientMemoryToken m_decalsToken;
+		TransientMemoryToken m_clustersToken;
+		TransientMemoryToken m_lightIndicesToken;
+
+		TexturePtr m_diffDecalTex;
+		TexturePtr m_normRoughnessDecalTex;
 	} m_is;
 	/// @}
 
@@ -285,7 +294,7 @@ anki_internal:
 
 	void drawQuadInstanced(CommandBufferPtr& cmdb, U32 primitiveCount)
 	{
-		cmdb->drawArrays(3, primitiveCount);
+		cmdb->drawArrays(PrimitiveTopology::TRIANGLES, 3, primitiveCount);
 	}
 
 	/// Get the LOD given the distance of an object from the camera
@@ -294,8 +303,8 @@ anki_internal:
 		return distance / m_lodDistance;
 	}
 
-	/// Create a pipeline object that has as a vertex shader the m_drawQuadVert and the given fragment progam
-	void createDrawQuadPipeline(ShaderPtr frag, const ColorStateInfo& colorState, PipelinePtr& ppline);
+	/// Create a shader program that has as a vertex shader the m_drawQuadVert and the given fragment progam
+	void createDrawQuadShaderProgram(ShaderPtr frag, ShaderProgramPtr& prog);
 
 	/// Create a framebuffer attachment texture
 	void createRenderTarget(U32 w,
@@ -308,7 +317,8 @@ anki_internal:
 
 	void clearRenderTarget(TexturePtr rt, const ClearValue& clear, TextureUsageBit transferTo);
 
-	ANKI_USE_RESULT Error createShader(CString fname, ShaderResourcePtr& shader, CString fmt, ...);
+	ANKI_USE_RESULT Error createShader(CString fname, ShaderResourcePtr& shader, CString extra);
+	ANKI_USE_RESULT Error createShaderf(CString fname, ShaderResourcePtr& shader, CString fmt, ...);
 
 	GrManager& getGrManager()
 	{

+ 15 - 12
src/anki/renderer/Sm.cpp

@@ -23,14 +23,22 @@ Sm::~Sm()
 {
 	m_spots.destroy(getAllocator());
 	m_omnis.destroy(getAllocator());
+}
+
+Error Sm::init(const ConfigSet& config)
+{
+	ANKI_LOGI("Initializing shadowmapping");
 
-	if(m_pplineCache)
+	Error err = initInternal(config);
+	if(err)
 	{
-		getAllocator().deleteInstance(m_pplineCache);
+		ANKI_LOGE("Failed to initialize shadowmapping");
 	}
+
+	return err;
 }
 
-Error Sm::init(const ConfigSet& config)
+Error Sm::initInternal(const ConfigSet& config)
 {
 	m_poissonEnabled = config.getNumber("sm.poissonEnabled");
 	m_bilinearEnabled = config.getNumber("sm.bilinearEnabled");
@@ -98,11 +106,6 @@ Error Sm::init(const ConfigSet& config)
 		++layer;
 	}
 
-	// Init state
-	m_state.m_depthStencil.m_format = Sm::DEPTH_RT_PIXEL_FORMAT;
-
-	m_pplineCache = getAllocator().newInstance<GrObjectCache>(&getGrManager());
-
 	return ErrorCode::NONE;
 }
 
@@ -268,14 +271,14 @@ Error Sm::doSpotLight(SceneNode& light, CommandBufferPtr& cmdb, FramebufferPtr&
 	cinf.m_flags = CommandBufferFlag::SECOND_LEVEL;
 	cinf.m_framebuffer = fb;
 	cmdb = m_r->getGrManager().newInstance<CommandBuffer>(cinf);
+
+	// Set state
 	cmdb->setViewport(0, 0, m_resolution, m_resolution);
 	cmdb->setPolygonOffset(1.0, 2.0);
 
 	Error err = m_r->getSceneDrawer().drawRange(Pass::SM,
 		frc,
 		cmdb,
-		*m_pplineCache,
-		m_state,
 		vis.getBegin(VisibilityGroupType::RENDERABLES_MS) + start,
 		vis.getBegin(VisibilityGroupType::RENDERABLES_MS) + end);
 
@@ -301,14 +304,14 @@ Error Sm::doOmniLight(
 			cinf.m_flags = CommandBufferFlag::SECOND_LEVEL;
 			cinf.m_framebuffer = fbs[frCount];
 			cmdbs[frCount] = m_r->getGrManager().newInstance<CommandBuffer>(cinf);
+
+			// Set state
 			cmdbs[frCount]->setViewport(0, 0, m_resolution, m_resolution);
 			cmdbs[frCount]->setPolygonOffset(1.0, 2.0);
 
 			ANKI_CHECK(m_r->getSceneDrawer().drawRange(Pass::SM,
 				frc,
 				cmdbs[frCount],
-				*m_pplineCache,
-				m_state,
 				vis.getBegin(VisibilityGroupType::RENDERABLES_MS) + start,
 				vis.getBegin(VisibilityGroupType::RENDERABLES_MS) + end));
 

+ 7 - 23
src/anki/renderer/Sm.h

@@ -25,6 +25,12 @@ class Sm : public RenderingPass
 anki_internal:
 	static const PixelFormat DEPTH_RT_PIXEL_FORMAT;
 
+	/// Enable Poisson for all the levels
+	Bool8 m_poissonEnabled = false;
+
+	TexturePtr m_spotTexArray;
+	TexturePtr m_omniTexArray;
+
 	Sm(Renderer* r)
 		: RenderingPass(r)
 	{
@@ -44,25 +50,7 @@ anki_internal:
 
 	void setPostRunBarriers(RenderingContext& ctx);
 
-	Bool getPoissonEnabled() const
-	{
-		return m_poissonEnabled;
-	}
-
-	TexturePtr getSpotTextureArray() const
-	{
-		return m_spotTexArray;
-	}
-
-	TexturePtr getOmniTextureArray() const
-	{
-		return m_omniTexArray;
-	}
-
 private:
-	TexturePtr m_spotTexArray;
-	TexturePtr m_omniTexArray;
-
 	class ShadowmapBase
 	{
 	public:
@@ -86,17 +74,13 @@ private:
 	DynamicArray<ShadowmapSpot> m_spots;
 	DynamicArray<ShadowmapOmni> m_omnis;
 
-	/// Enable Poisson for all the levels
-	Bool8 m_poissonEnabled = false;
-
 	/// Shadowmap bilinear filtering for the first level. Better quality
 	Bool8 m_bilinearEnabled;
 
 	/// Shadowmap resolution
 	U32 m_resolution;
 
-	GrObjectCache* m_pplineCache = nullptr;
-	PipelineInitInfo m_state;
+	ANKI_USE_RESULT Error initInternal(const ConfigSet& initializer);
 
 	/// Find the best shadowmap for that light
 	template<typename TShadowmap, typename TContainer>

+ 40 - 59
src/anki/renderer/Smaa.cpp

@@ -34,26 +34,11 @@ Error SmaaEdge::init(const ConfigSet& initializer)
 		F32(m_r->getHeight()),
 		&m_r->getSmaa().m_qualityPerset[0]);
 
-	ANKI_CHECK(getResourceManager().loadResourceToCache(m_vert, "shaders/SmaaEdge.vert.glsl", pps.toCString(), "r_"));
-	ANKI_CHECK(getResourceManager().loadResourceToCache(m_frag, "shaders/SmaaEdge.frag.glsl", pps.toCString(), "r_"));
+	ANKI_CHECK(m_r->createShader("shaders/SmaaEdge.vert.glsl", m_vert, pps.toCString()));
+	ANKI_CHECK(m_r->createShader("shaders/SmaaEdge.frag.glsl", m_frag, pps.toCString()));
 
-	// Create ppline
-	PipelineInitInfo ppinit;
-
-	ppinit.m_inputAssembler.m_topology = PrimitiveTopology::TRIANGLE_STRIP;
-
-	ppinit.m_depthStencil.m_depthWriteEnabled = false;
-	ppinit.m_depthStencil.m_depthCompareFunction = CompareOperation::ALWAYS;
-	ppinit.m_depthStencil.m_stencilFront.m_stencilPassDepthPassOperation = StencilOperation::REPLACE;
-	ppinit.m_depthStencil.m_format = STENCIL_PIXEL_FORMAT;
-
-	ppinit.m_color.m_attachmentCount = 1;
-	ppinit.m_color.m_attachments[0].m_format = EDGE_PIXEL_FORMAT;
-
-	ppinit.m_shaders[ShaderType::VERTEX] = m_vert->getGrShader();
-	ppinit.m_shaders[ShaderType::FRAGMENT] = m_frag->getGrShader();
-
-	m_ppline = gr.newInstance<Pipeline>(ppinit);
+	// Create prog
+	m_prog = getGrManager().newInstance<ShaderProgram>(m_vert->getGrShader(), m_frag->getGrShader());
 
 	// Create RT
 	m_r->createRenderTarget(m_r->getWidth(),
@@ -75,11 +60,6 @@ Error SmaaEdge::init(const ConfigSet& initializer)
 	fbInit.m_depthStencilAttachment.m_usageInsideRenderPass = TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE;
 	m_fb = gr.newInstance<Framebuffer>(fbInit);
 
-	// Create RC group
-	ResourceGroupInitInfo rcinit;
-	rcinit.m_textures[0].m_texture = m_r->getIs().getRt();
-	m_rcgroup = gr.newInstance<ResourceGroup>(rcinit);
-
 	return ErrorCode::NONE;
 }
 
@@ -112,15 +92,22 @@ void SmaaEdge::run(RenderingContext& ctx)
 	CommandBufferPtr& cmdb = ctx.m_commandBuffer;
 
 	cmdb->setViewport(0, 0, m_r->getWidth(), m_r->getHeight());
-	cmdb->bindResourceGroup(m_rcgroup, 0, nullptr);
-	cmdb->bindPipeline(m_ppline);
+	cmdb->bindShaderProgram(m_prog);
+	cmdb->bindTexture(0, 0, m_r->getIs().getRt());
+
+	cmdb->setStencilOperations(
+		FaceSelectionMask::FRONT, StencilOperation::KEEP, StencilOperation::KEEP, StencilOperation::REPLACE);
 	cmdb->setStencilCompareMask(FaceSelectionMask::FRONT, 0xF);
 	cmdb->setStencilWriteMask(FaceSelectionMask::FRONT, 0xF);
 	cmdb->setStencilReference(FaceSelectionMask::FRONT, 0xF);
 
 	cmdb->beginRenderPass(m_fb);
-	cmdb->drawArrays(3);
+	m_r->drawQuad(cmdb);
 	cmdb->endRenderPass();
+
+	// Restore state
+	cmdb->setStencilOperations(
+		FaceSelectionMask::FRONT, StencilOperation::KEEP, StencilOperation::KEEP, StencilOperation::KEEP);
 }
 
 SmaaWeights::~SmaaWeights()
@@ -141,28 +128,11 @@ Error SmaaWeights::init(const ConfigSet& initializer)
 		F32(m_r->getHeight()),
 		&m_r->getSmaa().m_qualityPerset[0]);
 
-	ANKI_CHECK(
-		getResourceManager().loadResourceToCache(m_vert, "shaders/SmaaWeights.vert.glsl", pps.toCString(), "r_"));
-	ANKI_CHECK(
-		getResourceManager().loadResourceToCache(m_frag, "shaders/SmaaWeights.frag.glsl", pps.toCString(), "r_"));
-
-	// Create ppline
-	PipelineInitInfo ppinit;
-
-	ppinit.m_inputAssembler.m_topology = PrimitiveTopology::TRIANGLE_STRIP;
-
-	ppinit.m_depthStencil.m_depthWriteEnabled = false;
-	ppinit.m_depthStencil.m_depthCompareFunction = CompareOperation::ALWAYS;
-	ppinit.m_depthStencil.m_stencilFront.m_compareFunction = CompareOperation::EQUAL;
-	ppinit.m_depthStencil.m_format = STENCIL_PIXEL_FORMAT;
-
-	ppinit.m_color.m_attachmentCount = 1;
-	ppinit.m_color.m_attachments[0].m_format = WEIGHTS_PIXEL_FORMAT;
-
-	ppinit.m_shaders[ShaderType::VERTEX] = m_vert->getGrShader();
-	ppinit.m_shaders[ShaderType::FRAGMENT] = m_frag->getGrShader();
+	ANKI_CHECK(m_r->createShader("shaders/SmaaWeights.vert.glsl", m_vert, pps.toCString()));
+	ANKI_CHECK(m_r->createShader("shaders/SmaaWeights.frag.glsl", m_frag, pps.toCString()));
 
-	m_ppline = gr.newInstance<Pipeline>(ppinit);
+	// Create prog
+	m_prog = getGrManager().newInstance<ShaderProgram>(m_vert->getGrShader(), m_frag->getGrShader());
 
 	// Create RT
 	m_r->createRenderTarget(m_r->getWidth(),
@@ -224,13 +194,6 @@ Error SmaaWeights::init(const ConfigSet& initializer)
 	}
 	cmdb->flush();
 
-	// Create RC group
-	ResourceGroupInitInfo rcinit;
-	rcinit.m_textures[0].m_texture = m_r->getSmaa().m_edge.m_rt;
-	rcinit.m_textures[1].m_texture = m_areaTex;
-	rcinit.m_textures[2].m_texture = m_searchTex;
-	m_rcgroup = gr.newInstance<ResourceGroup>(rcinit);
-
 	return ErrorCode::NONE;
 }
 
@@ -253,19 +216,38 @@ void SmaaWeights::run(RenderingContext& ctx)
 	CommandBufferPtr& cmdb = ctx.m_commandBuffer;
 
 	cmdb->setViewport(0, 0, m_r->getWidth(), m_r->getHeight());
-	cmdb->bindResourceGroup(m_rcgroup, 0, nullptr);
-	cmdb->bindPipeline(m_ppline);
+	cmdb->bindTexture(0, 0, m_r->getSmaa().m_edge.m_rt);
+	cmdb->bindTexture(0, 1, m_areaTex);
+	cmdb->bindTexture(0, 2, m_searchTex);
+	cmdb->bindShaderProgram(m_prog);
+
+	cmdb->setStencilCompareFunction(FaceSelectionMask::FRONT, CompareOperation::EQUAL);
 	cmdb->setStencilCompareMask(FaceSelectionMask::FRONT, 0xF);
 	cmdb->setStencilWriteMask(FaceSelectionMask::FRONT, 0x0);
 	cmdb->setStencilReference(FaceSelectionMask::FRONT, 0xF);
 
 	cmdb->beginRenderPass(m_fb);
-	cmdb->drawArrays(3);
+	m_r->drawQuad(cmdb);
 	cmdb->endRenderPass();
 }
 
 Error Smaa::init(const ConfigSet& cfg)
 {
+	Error err = initInternal(cfg);
+	if(err)
+	{
+		ANKI_LOGE("Failed to initialize SMAA");
+	}
+
+	return err;
+}
+
+Error Smaa::initInternal(const ConfigSet& cfg)
+{
+	m_qualityPerset = "ULTRA";
+
+	ANKI_LOGI("Initializing SMAA in %s perset", &m_qualityPerset[0]);
+
 	TextureInitInfo texinit;
 	texinit.m_format = STENCIL_PIXEL_FORMAT;
 	texinit.m_width = m_r->getWidth();
@@ -273,7 +255,6 @@ Error Smaa::init(const ConfigSet& cfg)
 	texinit.m_usage = TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ_WRITE;
 	m_stencilTex = getGrManager().newInstance<Texture>(texinit);
 
-	m_qualityPerset = "ULTRA";
 	ANKI_CHECK(m_edge.init(cfg));
 	ANKI_CHECK(m_weights.init(cfg));
 	return ErrorCode::NONE;

+ 5 - 4
src/anki/renderer/Smaa.h

@@ -35,8 +35,7 @@ private:
 	FramebufferPtr m_fb;
 	ShaderResourcePtr m_vert;
 	ShaderResourcePtr m_frag;
-	PipelinePtr m_ppline;
-	ResourceGroupPtr m_rcgroup;
+	ShaderProgramPtr m_prog;
 };
 
 class SmaaWeights : public RenderingPass
@@ -61,10 +60,9 @@ private:
 	FramebufferPtr m_fb;
 	ShaderResourcePtr m_vert;
 	ShaderResourcePtr m_frag;
-	PipelinePtr m_ppline;
+	ShaderProgramPtr m_prog;
 	TexturePtr m_areaTex;
 	TexturePtr m_searchTex;
-	ResourceGroupPtr m_rcgroup;
 };
 
 class Smaa : public RenderingPass
@@ -87,6 +85,9 @@ anki_internal:
 	}
 
 	ANKI_USE_RESULT Error init(const ConfigSet& cfg);
+
+private:
+	ANKI_USE_RESULT Error initInternal(const ConfigSet& cfg);
 };
 /// @}
 

+ 40 - 90
src/anki/renderer/Ssao.cpp

@@ -119,16 +119,14 @@ Error Ssao::initInternal(const ConfigSet& config)
 	genNoise(&noise[0], &noise[0] + noise.getSize());
 
 	CommandBufferInitInfo cmdbInit;
-	cmdbInit.m_flags = CommandBufferFlag::SMALL_BATCH;
+	cmdbInit.m_flags = CommandBufferFlag::SMALL_BATCH | CommandBufferFlag::TRANSFER_WORK;
 
 	CommandBufferPtr cmdb = gr.newInstance<CommandBuffer>(cmdbInit);
 
 	TextureSurfaceInfo surf(0, 0, 0, 0);
 
 	cmdb->setTextureSurfaceBarrier(m_noiseTex, TextureUsageBit::NONE, TextureUsageBit::UPLOAD, surf);
-
 	cmdb->uploadTextureSurfaceCopyData(m_noiseTex, surf, &noise[0], sizeof(noise));
-
 	cmdb->setTextureSurfaceBarrier(m_noiseTex, TextureUsageBit::UPLOAD, TextureUsageBit::SAMPLED_FRAGMENT, surf);
 
 	cmdb->flush();
@@ -154,103 +152,51 @@ Error Ssao::initInternal(const ConfigSet& config)
 	//
 	// Shaders
 	//
-	PipelineInitInfo ppinit;
-	ppinit.m_color.m_attachmentCount = 1;
-	ppinit.m_color.m_attachments[0].m_format = RT_PIXEL_FORMAT;
-	ppinit.m_depthStencil.m_depthWriteEnabled = false;
-	ppinit.m_depthStencil.m_depthCompareFunction = CompareOperation::ALWAYS;
-
-	StringAuto pps(getAllocator());
-
-	// vert shader
-	ANKI_CHECK(getResourceManager().loadResource("shaders/Quad.vert.glsl", m_quadVert));
-
-	ppinit.m_shaders[ShaderType::VERTEX] = m_quadVert->getGrShader();
 
 	// main pass prog
-	pps.destroy();
-	pps.sprintf("#define NOISE_MAP_SIZE %u\n"
-				"#define WIDTH %u\n"
-				"#define HEIGHT %u\n"
-				"#define KERNEL_SIZE %u\n"
-				"#define KERNEL_ARRAY %s\n"
-				"#define RADIUS float(%f)\n",
+	ANKI_CHECK(m_r->createShaderf("shaders/Ssao.frag.glsl",
+		m_ssaoFrag,
+		"#define NOISE_MAP_SIZE %u\n"
+		"#define WIDTH %u\n"
+		"#define HEIGHT %u\n"
+		"#define KERNEL_SIZE %u\n"
+		"#define KERNEL_ARRAY %s\n"
+		"#define RADIUS float(%f)\n",
 		NOISE_TEX_SIZE,
 		m_width,
 		m_height,
 		KERNEL_SIZE,
 		&kernelStr[0],
-		HEMISPHERE_RADIUS);
-
-	ANKI_CHECK(getResourceManager().loadResourceToCache(m_ssaoFrag, "shaders/Ssao.frag.glsl", pps.toCString(), "r_"));
+		HEMISPHERE_RADIUS));
 
-	ppinit.m_shaders[ShaderType::FRAGMENT] = m_ssaoFrag->getGrShader();
-
-	m_ssaoPpline = getGrManager().newInstance<Pipeline>(ppinit);
+	m_r->createDrawQuadShaderProgram(m_ssaoFrag->getGrShader(), m_ssaoProg);
 
 	// h blur
 	const char* SHADER_FILENAME = "shaders/GaussianBlurGeneric.frag.glsl";
 
-	pps.destroy();
-	pps.sprintf("#define HPASS\n"
-				"#define COL_R\n"
-				"#define TEXTURE_SIZE vec2(%f, %f)\n"
-				"#define KERNEL_SIZE 13\n",
+	ANKI_CHECK(m_r->createShaderf(SHADER_FILENAME,
+		m_hblurFrag,
+		"#define HPASS\n"
+		"#define COL_R\n"
+		"#define TEXTURE_SIZE vec2(%f, %f)\n"
+		"#define KERNEL_SIZE 13\n",
 		F32(m_width),
-		F32(m_height));
-
-	ANKI_CHECK(getResourceManager().loadResourceToCache(m_hblurFrag, SHADER_FILENAME, pps.toCString(), "r_"));
-
-	ppinit.m_shaders[ShaderType::FRAGMENT] = m_hblurFrag->getGrShader();
+		F32(m_height)));
 
-	m_hblurPpline = getGrManager().newInstance<Pipeline>(ppinit);
+	m_r->createDrawQuadShaderProgram(m_hblurFrag->getGrShader(), m_hblurProg);
 
 	// v blur
-	pps.destroy();
-	pps.sprintf("#define VPASS\n"
-				"#define COL_R\n"
-				"#define TEXTURE_SIZE vec2(%f, %f)\n"
-				"#define KERNEL_SIZE 11\n",
+	ANKI_CHECK(m_r->createShaderf(SHADER_FILENAME,
+		m_vblurFrag,
+		"#define VPASS\n"
+		"#define COL_R\n"
+		"#define TEXTURE_SIZE vec2(%f, %f)\n"
+		"#define KERNEL_SIZE 11\n",
 		F32(m_width),
-		F32(m_height));
-
-	ANKI_CHECK(getResourceManager().loadResourceToCache(m_vblurFrag, SHADER_FILENAME, pps.toCString(), "r_"));
-
-	ppinit.m_shaders[ShaderType::FRAGMENT] = m_vblurFrag->getGrShader();
+		F32(m_height)));
 
-	m_vblurPpline = getGrManager().newInstance<Pipeline>(ppinit);
+	m_r->createDrawQuadShaderProgram(m_vblurFrag->getGrShader(), m_vblurProg);
 
-	//
-	// Resource groups
-	//
-	ResourceGroupInitInfo rcinit;
-	SamplerInitInfo sinit;
-	sinit.m_minMagFilter = SamplingFilter::LINEAR;
-	sinit.m_mipmapFilter = SamplingFilter::NEAREST;
-	sinit.m_repeat = false;
-
-	rcinit.m_textures[0].m_texture = m_r->getDepthDownscale().m_qd.m_depthRt;
-	rcinit.m_textures[0].m_sampler = gr.newInstance<Sampler>(sinit);
-	rcinit.m_textures[0].m_usage = TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ;
-
-	rcinit.m_textures[1].m_texture = m_r->getMs().m_rt2;
-	rcinit.m_textures[1].m_sampler = rcinit.m_textures[0].m_sampler;
-
-	rcinit.m_textures[2].m_texture = m_noiseTex;
-
-	rcinit.m_uniformBuffers[0].m_uploadedMemory = true;
-	rcinit.m_uniformBuffers[0].m_usage = BufferUsageBit::UNIFORM_FRAGMENT;
-	m_rcFirst = gr.newInstance<ResourceGroup>(rcinit);
-
-	rcinit = ResourceGroupInitInfo();
-	rcinit.m_textures[0].m_texture = m_vblurRt;
-	m_hblurRc = gr.newInstance<ResourceGroup>(rcinit);
-
-	rcinit = ResourceGroupInitInfo();
-	rcinit.m_textures[0].m_texture = m_hblurRt;
-	m_vblurRc = gr.newInstance<ResourceGroup>(rcinit);
-
-	gr.finish();
 	return ErrorCode::NONE;
 }
 
@@ -290,11 +236,15 @@ void Ssao::run(RenderingContext& ctx)
 	//
 	cmdb->beginRenderPass(m_vblurFb);
 	cmdb->setViewport(0, 0, m_width, m_height);
-	cmdb->bindPipeline(m_ssaoPpline);
+	cmdb->bindShaderProgram(m_ssaoProg);
+
+	cmdb->bindTexture(0, 0, m_r->getDepthDownscale().m_qd.m_depthRt);
+	cmdb->bindTexture(0, 1, m_r->getMs().m_rt2);
+	cmdb->bindTexture(0, 2, m_noiseTex);
 
-	TransientMemoryInfo inf;
-	Vec4* unis = static_cast<Vec4*>(getGrManager().allocateFrameTransientMemory(
-		sizeof(Vec4) * 2, BufferUsageBit::UNIFORM_ALL, inf.m_uniformBuffers[0]));
+	TransientMemoryToken token;
+	Vec4* unis = static_cast<Vec4*>(
+		getGrManager().allocateFrameTransientMemory(sizeof(Vec4) * 2, BufferUsageBit::UNIFORM_ALL, token));
 
 	const FrustumComponent& frc = *ctx.m_frustumComponent;
 	const Mat4& pmat = frc.getProjectionMatrix();
@@ -302,7 +252,7 @@ void Ssao::run(RenderingContext& ctx)
 	++unis;
 	*unis = Vec4(pmat(0, 0), pmat(1, 1), pmat(2, 2), pmat(2, 3));
 
-	cmdb->bindResourceGroup(m_rcFirst, 0, &inf);
+	cmdb->bindUniformBuffer(0, 0, token);
 
 	// Draw
 	m_r->drawQuad(cmdb);
@@ -322,8 +272,8 @@ void Ssao::run(RenderingContext& ctx)
 			TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE,
 			TextureSurfaceInfo(0, 0, 0, 0));
 		cmdb->beginRenderPass(m_hblurFb);
-		cmdb->bindPipeline(m_hblurPpline);
-		cmdb->bindResourceGroup(m_hblurRc, 0, nullptr);
+		cmdb->bindShaderProgram(m_hblurProg);
+		cmdb->bindTexture(0, 0, m_vblurRt);
 		m_r->drawQuad(cmdb);
 		cmdb->endRenderPass();
 
@@ -337,8 +287,8 @@ void Ssao::run(RenderingContext& ctx)
 			TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE,
 			TextureSurfaceInfo(0, 0, 0, 0));
 		cmdb->beginRenderPass(m_vblurFb);
-		cmdb->bindPipeline(m_vblurPpline);
-		cmdb->bindResourceGroup(m_vblurRc, 0, nullptr);
+		cmdb->bindShaderProgram(m_vblurProg);
+		cmdb->bindTexture(0, 0, m_hblurRt);
 		m_r->drawQuad(cmdb);
 		cmdb->endRenderPass();
 	}

+ 3 - 8
src/anki/renderer/Ssao.h

@@ -48,20 +48,15 @@ private:
 	FramebufferPtr m_vblurFb;
 	FramebufferPtr m_hblurFb;
 
-	ShaderResourcePtr m_quadVert;
 	ShaderResourcePtr m_ssaoFrag;
 	ShaderResourcePtr m_hblurFrag;
 	ShaderResourcePtr m_vblurFrag;
-	PipelinePtr m_ssaoPpline;
-	PipelinePtr m_hblurPpline;
-	PipelinePtr m_vblurPpline;
+	ShaderProgramPtr m_ssaoProg;
+	ShaderProgramPtr m_hblurProg;
+	ShaderProgramPtr m_vblurProg;
 
 	TexturePtr m_noiseTex;
 
-	ResourceGroupPtr m_rcFirst;
-	ResourceGroupPtr m_hblurRc;
-	ResourceGroupPtr m_vblurRc;
-
 	ANKI_USE_RESULT Error createFb(FramebufferPtr& fb, TexturePtr& rt);
 	ANKI_USE_RESULT Error initInternal(const ConfigSet& initializer);
 };

+ 12 - 26
src/anki/renderer/Sslf.cpp

@@ -13,10 +13,12 @@ namespace anki
 
 Error Sslf::init(const ConfigSet& config)
 {
+	ANKI_LOGI("Initializing screen space lens flare");
+
 	Error err = initInternal(config);
 	if(err)
 	{
-		ANKI_LOGE("Failed to init screen space lens flare pass");
+		ANKI_LOGE("Failed to init screen space lens flare");
 	}
 
 	return err;
@@ -24,34 +26,16 @@ Error Sslf::init(const ConfigSet& config)
 
 Error Sslf::initInternal(const ConfigSet& config)
 {
-	// Load program 1
-	StringAuto pps(getAllocator());
-
-	pps.sprintf("#define TEX_DIMENSIONS vec2(%u.0, %u.0)\n",
+	ANKI_CHECK(m_r->createShaderf("shaders/Sslf.frag.glsl",
+		m_frag,
+		"#define TEX_DIMENSIONS vec2(%u.0, %u.0)\n",
 		m_r->getBloom().m_extractExposure.m_width,
-		m_r->getBloom().m_extractExposure.m_height);
-
-	ANKI_CHECK(getResourceManager().loadResourceToCache(m_frag, "shaders/Sslf.frag.glsl", pps.toCString(), "r_"));
+		m_r->getBloom().m_extractExposure.m_height));
 
-	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;
+	m_r->createDrawQuadShaderProgram(m_frag->getGrShader(), m_prog);
 
-	m_r->createDrawQuadPipeline(m_frag->getGrShader(), colorState, m_ppline);
-
-	// Textures
 	ANKI_CHECK(getResourceManager().loadResource("engine_data/LensDirt.ankitex", m_lensDirtTex));
 
-	// Create the resource group
-	ResourceGroupInitInfo rcInit;
-	rcInit.m_textures[0].m_texture = m_r->getBloom().m_extractExposure.m_rt;
-	rcInit.m_textures[1].m_texture = m_lensDirtTex->getGrTexture();
-
-	m_rcGroup = getGrManager().newInstance<ResourceGroup>(rcInit);
-
-	getGrManager().finish();
 	return ErrorCode::NONE;
 }
 
@@ -60,8 +44,10 @@ void Sslf::run(RenderingContext& ctx)
 	CommandBufferPtr& cmdb = ctx.m_commandBuffer;
 
 	// Draw to the SSLF FB
-	cmdb->bindPipeline(m_ppline);
-	cmdb->bindResourceGroup(m_rcGroup, 0, nullptr);
+	cmdb->bindShaderProgram(m_prog);
+	cmdb->setBlendMethods(0, BlendMethod::ONE, BlendMethod::ONE);
+	cmdb->bindTexture(0, 0, m_r->getBloom().m_extractExposure.m_rt);
+	cmdb->bindTexture(0, 1, m_lensDirtTex->getGrTexture());
 
 	m_r->drawQuad(cmdb);
 }

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

@@ -27,9 +27,8 @@ anki_internal:
 
 private:
 	ShaderResourcePtr m_frag;
-	PipelinePtr m_ppline;
+	ShaderProgramPtr m_prog;
 	TextureResourcePtr m_lensDirtTex;
-	ResourceGroupPtr m_rcGroup;
 
 	ANKI_USE_RESULT Error initInternal(const ConfigSet& config);
 };

+ 0 - 205
src/anki/renderer/Tiler.cpp

@@ -1,205 +0,0 @@
-// 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/renderer/Tiler.h>
-#include <anki/renderer/Renderer.h>
-#include <anki/renderer/Ms.h>
-#include <anki/resource/ShaderResource.h>
-#include <anki/scene/FrustumComponent.h>
-#include <anki/scene/MoveComponent.h>
-#include <anki/scene/SceneNode.h>
-
-namespace anki
-{
-
-Tiler::Tiler(Renderer* r)
-	: RenderingPass(r)
-{
-}
-
-Tiler::~Tiler()
-{
-	m_currentMinMax.destroy(getAllocator());
-}
-
-Error Tiler::init()
-{
-	Error err = initInternal();
-
-	if(err)
-	{
-		ANKI_LOGE("Failed to init tiler");
-	}
-
-	return err;
-}
-
-Error Tiler::initInternal()
-{
-	// Load the program
-	StringAuto pps(getAllocator());
-
-	pps.sprintf("#define TILE_SIZE_X %u\n"
-				"#define TILE_SIZE_Y %u\n"
-				"#define TILES_COUNT_X %u\n"
-				"#define TILES_COUNT_Y %u\n",
-		TILE_SIZE,
-		TILE_SIZE,
-		m_r->getTileCountXY().x(),
-		m_r->getTileCountXY().y());
-
-	ANKI_CHECK(
-		getResourceManager().loadResourceToCache(m_shader, "shaders/TilerMinMax.comp.glsl", pps.toCString(), "r_"));
-
-	PipelineInitInfo pplineInit;
-	pplineInit.m_shaders[U(ShaderType::COMPUTE)] = m_shader->getGrShader();
-	m_ppline = getGrManager().newInstance<Pipeline>(pplineInit);
-
-	// Allocate the buffers
-	U pboSize = m_r->getTileCount() * sizeof(Vec2); // The pixel size
-
-	for(U i = 0; i < m_outBuffers.getSize(); ++i)
-	{
-		// Create the buffer
-		m_outBuffers[i] =
-			getGrManager().newInstance<Buffer>(pboSize, BufferUsageBit::STORAGE_ALL, BufferMapAccessBit::READ);
-
-		// Create graphics resources
-		ResourceGroupInitInfo rcinit;
-		rcinit.m_storageBuffers[0].m_buffer = m_outBuffers[i];
-		rcinit.m_textures[0].m_texture = m_r->getMs().m_depthRt;
-
-		m_rcGroups[i] = getGrManager().newInstance<ResourceGroup>(rcinit);
-	}
-
-	m_currentMinMax.create(getAllocator(), m_r->getTileCount());
-
-	return ErrorCode::NONE;
-}
-
-void Tiler::run(CommandBufferPtr& cmd)
-{
-	// Issue the min/max job
-	U pboIdx = m_r->getFrameCount() % m_outBuffers.getSize();
-
-	cmd->bindPipeline(m_ppline);
-	cmd->bindResourceGroup(m_rcGroups[pboIdx], 0, nullptr);
-
-	cmd->dispatchCompute(m_r->getTileCountXY().x(), m_r->getTileCountXY().y(), 1);
-}
-
-void Tiler::prepareForVisibilityTests(const SceneNode& node)
-{
-	// Get the min max
-	U size = m_r->getTileCount() * sizeof(Vec2);
-
-	U buffIdx = max<U>(m_r->getFrameCount() % m_outBuffers.getSize(), 2u) - 2;
-	BufferPtr& buff = m_outBuffers[buffIdx];
-	void* mappedMem = buff->map(0, size, BufferMapAccessBit::READ);
-
-	ANKI_ASSERT(mappedMem);
-	memcpy(&m_currentMinMax[0], mappedMem, size);
-
-	buff->unmap();
-
-	// Convert the min max to view space
-	const FrustumComponent& frc = node.getComponent<FrustumComponent>();
-	const Vec4& projParams = frc.getProjectionParameters();
-
-	for(Vec2& v : m_currentMinMax)
-	{
-		// Unproject
-		v = projParams.z() / (projParams.w() + v);
-	};
-
-	// Other
-	const MoveComponent& movec = node.getComponent<MoveComponent>();
-	m_nearPlaneWspace = Plane(Vec4(0.0, 0.0, -1.0, 0.0), frc.getFrustum().getNear());
-	m_nearPlaneWspace.transform(movec.getWorldTransform());
-
-	m_viewProjMat = frc.getViewProjectionMatrix();
-	m_near = frc.getFrustum().getNear();
-}
-
-Bool Tiler::test(const CollisionShape& cs, const Aabb& aabb) const
-{
-	// Compute the distance from the near plane
-	F32 dist = aabb.testPlane(m_nearPlaneWspace);
-	if(dist <= 0.0)
-	{
-		// Collides with the near plane. The following tests will fail
-		return true;
-	}
-
-	dist += m_near;
-	dist = -dist; // Because m_nearPlaneWspace has negatives
-
-	// Find the tiles that affect it
-	const Vec4& minv = aabb.getMin();
-	const Vec4& maxv = aabb.getMax();
-	Array<Vec4, 8> points;
-	points[0] = minv.xyz1();
-	points[1] = Vec4(minv.x(), maxv.y(), minv.z(), 1.0);
-	points[2] = Vec4(minv.x(), maxv.y(), maxv.z(), 1.0);
-	points[3] = Vec4(minv.x(), minv.y(), maxv.z(), 1.0);
-	points[4] = maxv.xyz1();
-	points[5] = Vec4(maxv.x(), minv.y(), maxv.z(), 1.0);
-	points[6] = Vec4(maxv.x(), minv.y(), minv.z(), 1.0);
-	points[7] = Vec4(maxv.x(), maxv.y(), minv.z(), 1.0);
-	Vec2 min2(MAX_F32), max2(MIN_F32);
-	for(Vec4& p : points)
-	{
-		p = m_viewProjMat * p;
-		ANKI_ASSERT(p.w() > 0.0);
-		p = p.perspectiveDivide();
-
-		for(U i = 0; i < 2; ++i)
-		{
-			min2[i] = min(min2[i], p[i]);
-			max2[i] = max(max2[i], p[i]);
-		}
-	}
-
-	min2 = min2 * 0.5 + 0.5;
-	max2 = max2 * 0.5 + 0.5;
-
-	F32 tcountX = m_r->getTileCountXY().x();
-	F32 tcountY = m_r->getTileCountXY().y();
-
-	I xBegin = floor(tcountX * min2.x());
-	xBegin = clamp<I>(xBegin, 0, tcountX);
-
-	I xEnd = ceil(tcountX * max2.x());
-	xEnd = min<U>(xEnd, tcountX);
-
-	I yBegin = floor(tcountY * min2.y());
-	yBegin = clamp<I>(yBegin, 0, tcountY);
-
-	I yEnd = ceil(tcountY * max2.y());
-	yEnd = min<I>(yEnd, tcountY);
-
-	ANKI_ASSERT(xBegin >= 0 && xBegin <= tcountX && xEnd >= 0 && xEnd <= tcountX);
-	ANKI_ASSERT(yBegin >= 0 && yBegin <= tcountX && yEnd >= 0 && yBegin <= tcountY);
-
-	// Check every tile
-	U visibleCount = (yEnd - yBegin) * (xEnd - xBegin);
-	for(I y = yBegin; y < yEnd; y++)
-	{
-		for(I x = xBegin; x < xEnd; x++)
-		{
-			U tileIdx = y * tcountX + x;
-			F32 tileMaxDist = m_currentMinMax[tileIdx].y();
-
-			if(dist < tileMaxDist)
-			{
-				--visibleCount;
-			}
-		}
-	}
-
-	return visibleCount > 0;
-}
-
-} // end namespace anki

+ 0 - 57
src/anki/renderer/Tiler.h

@@ -1,57 +0,0 @@
-// 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/Collision.h>
-#include <anki/renderer/RenderingPass.h>
-#include <anki/core/Timestamp.h>
-
-namespace anki
-{
-
-class SceneNode;
-
-/// @addtogroup renderer
-/// @{
-
-/// Tiler used for visibility tests
-class Tiler : public RenderingPass
-{
-	friend class UpdatePlanesPerspectiveCameraTask;
-
-anki_internal:
-	Tiler(Renderer* r);
-	~Tiler();
-
-	ANKI_USE_RESULT Error init();
-
-	/// Test against all tiles.
-	Bool test(const CollisionShape& cs, const Aabb& aabb) const;
-
-	/// Issue the GPU job
-	void run(CommandBufferPtr& cmd);
-
-	/// Prepare for visibility tests
-	void prepareForVisibilityTests(const SceneNode& node);
-
-private:
-	// GPU objects
-	Array<BufferPtr, MAX_FRAMES_IN_FLIGHT> m_outBuffers;
-	Array<ResourceGroupPtr, MAX_FRAMES_IN_FLIGHT> m_rcGroups;
-	ShaderResourcePtr m_shader;
-	PipelinePtr m_ppline;
-
-	// Other
-	DynamicArray<Vec2> m_currentMinMax;
-	Mat4 m_viewProjMat;
-	F32 m_near;
-	Plane m_nearPlaneWspace;
-
-	ANKI_USE_RESULT Error initInternal();
-};
-/// @}
-
-} // end namespace anki

+ 15 - 27
src/anki/renderer/Tm.cpp

@@ -13,55 +13,43 @@ namespace anki
 Error Tm::create(const ConfigSet& initializer)
 {
 	// Create shader
-	StringAuto pps(getAllocator());
-
 	ANKI_ASSERT(m_r->getIs().getRtMipmapCount() > 1);
-	pps.sprintf("#define IS_RT_MIPMAP %u\n"
-				"#define ANKI_RENDERER_WIDTH %u\n"
-				"#define ANKI_RENDERER_HEIGHT %u\n",
+
+	ANKI_CHECK(m_r->createShaderf("shaders/TmAverageLuminance.comp.glsl",
+		m_luminanceShader,
+		"#define IS_RT_MIPMAP %u\n"
+		"#define ANKI_RENDERER_WIDTH %u\n"
+		"#define ANKI_RENDERER_HEIGHT %u\n",
 		m_r->getIs().getRtMipmapCount() - 1,
 		m_r->getWidth(),
-		m_r->getHeight());
-
-	ANKI_CHECK(getResourceManager().loadResourceToCache(
-		m_luminanceShader, "shaders/TmAverageLuminance.comp.glsl", pps.toCString(), "r_"));
+		m_r->getHeight()));
 
-	// Create ppline
-	PipelineInitInfo pplineInit;
-	pplineInit.m_shaders[U(ShaderType::COMPUTE)] = m_luminanceShader->getGrShader();
-	m_luminancePpline = getGrManager().newInstance<Pipeline>(pplineInit);
+	// Create prog
+	m_prog = getGrManager().newInstance<ShaderProgram>(m_luminanceShader->getGrShader());
 
 	// Create buffer
 	m_luminanceBuff = getGrManager().newInstance<Buffer>(sizeof(Vec4),
 		BufferUsageBit::STORAGE_ALL | BufferUsageBit::UNIFORM_ALL | BufferUsageBit::BUFFER_UPLOAD_DESTINATION,
 		BufferMapAccessBit::NONE);
 
-	CommandBufferPtr cmdb = getGrManager().newInstance<CommandBuffer>(CommandBufferInitInfo());
+	CommandBufferInitInfo cmdbinit;
+	cmdbinit.m_flags = CommandBufferFlag::SMALL_BATCH | CommandBufferFlag::TRANSFER_WORK;
+	CommandBufferPtr cmdb = getGrManager().newInstance<CommandBuffer>(cmdbinit);
 	TransientMemoryToken token;
 	void* data = getGrManager().allocateFrameTransientMemory(sizeof(Vec4), BufferUsageBit::BUFFER_UPLOAD_SOURCE, token);
 	*static_cast<Vec4*>(data) = Vec4(0.5);
 	cmdb->uploadBuffer(m_luminanceBuff, 0, token);
 	cmdb->flush();
 
-	// Create descriptors
-	ResourceGroupInitInfo rcinit;
-	rcinit.m_storageBuffers[0].m_buffer = m_luminanceBuff;
-	rcinit.m_storageBuffers[0].m_range = sizeof(Vec4);
-	rcinit.m_storageBuffers[0].m_usage = BufferUsageBit::STORAGE_COMPUTE_READ_WRITE;
-	rcinit.m_textures[0].m_texture = m_r->getIs().getRt();
-	rcinit.m_textures[0].m_usage = TextureUsageBit::SAMPLED_COMPUTE;
-
-	m_rcGroup = getGrManager().newInstance<ResourceGroup>(rcinit);
-
-	getGrManager().finish();
 	return ErrorCode::NONE;
 }
 
 void Tm::run(RenderingContext& ctx)
 {
 	CommandBufferPtr& cmdb = ctx.m_commandBuffer;
-	cmdb->bindPipeline(m_luminancePpline);
-	cmdb->bindResourceGroup(m_rcGroup, 0, nullptr);
+	cmdb->bindShaderProgram(m_prog);
+	cmdb->bindStorageBuffer(0, 0, m_luminanceBuff, 0);
+	cmdb->bindTexture(0, 0, m_r->getIs().getRt());
 
 	cmdb->dispatchCompute(1, 1, 1);
 }

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

@@ -17,25 +17,20 @@ namespace anki
 class Tm : public RenderingPass
 {
 anki_internal:
+	BufferPtr m_luminanceBuff;
+
 	Tm(Renderer* r)
 		: RenderingPass(r)
 	{
 	}
 
-	BufferPtr& getAverageLuminanceBuffer()
-	{
-		return m_luminanceBuff;
-	}
-
 	ANKI_USE_RESULT Error create(const ConfigSet& initializer);
 
 	void run(RenderingContext& ctx);
 
 private:
 	ShaderResourcePtr m_luminanceShader;
-	PipelinePtr m_luminancePpline;
-	BufferPtr m_luminanceBuff;
-	ResourceGroupPtr m_rcGroup;
+	ShaderProgramPtr m_prog;
 };
 /// @}
 

+ 36 - 35
src/anki/renderer/Volumetric.cpp

@@ -19,6 +19,19 @@ Volumetric::~Volumetric()
 }
 
 Error Volumetric::init(const ConfigSet& config)
+{
+	ANKI_LOGI("Initializing volumetric pass");
+
+	Error err = initInternal(config);
+	if(err)
+	{
+		ANKI_LOGE("Failed to initialize volumetric pass");
+	}
+
+	return err;
+}
+
+Error Volumetric::initInternal(const ConfigSet& config)
 {
 	U width = m_r->getWidth() / VOLUMETRIC_FRACTION;
 	U height = m_r->getHeight() / VOLUMETRIC_FRACTION;
@@ -35,7 +48,7 @@ Error Volumetric::init(const ConfigSet& config)
 	m_r->clearRenderTarget(m_rt, ClearValue(), TextureUsageBit::SAMPLED_FRAGMENT);
 
 	// Create shaders
-	ANKI_CHECK(m_r->createShader("shaders/Volumetric.frag.glsl",
+	ANKI_CHECK(m_r->createShaderf("shaders/Volumetric.frag.glsl",
 		m_frag,
 		"#define RPASS_SIZE uvec2(%uu, %uu)\n"
 		"#define CLUSTER_COUNT uvec3(%uu, %uu, %uu)\n",
@@ -45,34 +58,8 @@ Error Volumetric::init(const ConfigSet& config)
 		m_r->getIs().getLightBin().getClusterer().getClusterCountY(),
 		m_r->getIs().getLightBin().getClusterer().getClusterCountZ()));
 
-	// Create pplines
-	ColorStateInfo state;
-	state.m_attachmentCount = 1;
-	state.m_attachments[0].m_format = IS_COLOR_ATTACHMENT_PIXEL_FORMAT;
-	state.m_attachments[0].m_srcBlendMethod = BlendMethod::SRC_ALPHA;
-	state.m_attachments[0].m_dstBlendMethod = BlendMethod::ONE_MINUS_SRC_ALPHA;
-
-	m_r->createDrawQuadPipeline(m_frag->getGrShader(), state, m_ppline);
-
-	// Create the resource groups
-	ResourceGroupInitInfo rcInit;
-	rcInit.m_textures[0].m_texture = m_r->getDepthDownscale().m_qd.m_depthRt;
-	rcInit.m_textures[0].m_usage = TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ;
-	rcInit.m_textures[1].m_texture = m_r->getSm().getSpotTextureArray();
-	rcInit.m_textures[2].m_texture = m_r->getSm().getOmniTextureArray();
-	rcInit.m_uniformBuffers[0].m_uploadedMemory = true;
-	rcInit.m_uniformBuffers[0].m_usage = BufferUsageBit::UNIFORM_FRAGMENT;
-	rcInit.m_uniformBuffers[1].m_uploadedMemory = true;
-	rcInit.m_uniformBuffers[1].m_usage = BufferUsageBit::UNIFORM_FRAGMENT;
-	rcInit.m_uniformBuffers[2].m_uploadedMemory = true;
-	rcInit.m_uniformBuffers[2].m_usage = BufferUsageBit::UNIFORM_FRAGMENT;
-	rcInit.m_uniformBuffers[3].m_uploadedMemory = true;
-	rcInit.m_uniformBuffers[3].m_usage = BufferUsageBit::UNIFORM_FRAGMENT;
-	rcInit.m_storageBuffers[0].m_uploadedMemory = true;
-	rcInit.m_storageBuffers[0].m_usage = BufferUsageBit::STORAGE_FRAGMENT_READ;
-	rcInit.m_storageBuffers[1].m_uploadedMemory = true;
-	rcInit.m_storageBuffers[1].m_usage = BufferUsageBit::STORAGE_FRAGMENT_READ;
-	m_rc = getGrManager().newInstance<ResourceGroup>(rcInit);
+	// Create prog
+	m_r->createDrawQuadShaderProgram(m_frag->getGrShader(), m_prog);
 
 	// Create FBs
 	FramebufferInitInfo fbInit;
@@ -107,18 +94,32 @@ void Volumetric::run(RenderingContext& ctx)
 	const Frustum& frc = ctx.m_frustumComponent->getFrustum();
 
 	// Update uniforms
-	TransientMemoryInfo dyn = ctx.m_is.m_dynBufferInfo;
-	Vec4* uniforms = static_cast<Vec4*>(getGrManager().allocateFrameTransientMemory(
-		sizeof(Vec4) * 2, BufferUsageBit::UNIFORM_ALL, dyn.m_uniformBuffers[3]));
+	TransientMemoryToken token;
+	Vec4* uniforms = static_cast<Vec4*>(
+		getGrManager().allocateFrameTransientMemory(sizeof(Vec4) * 2, BufferUsageBit::UNIFORM_ALL, token));
 	computeLinearizeDepthOptimal(frc.getNear(), frc.getFar(), uniforms[0].x(), uniforms[0].y());
 
 	uniforms[1] = Vec4(m_fogColor, m_fogFactor);
 
-	// pass 0
+	// pass
 	cmdb->setViewport(0, 0, m_r->getWidth() / VOLUMETRIC_FRACTION, m_r->getHeight() / VOLUMETRIC_FRACTION);
+	cmdb->setBlendMethods(0, BlendMethod::SRC_ALPHA, BlendMethod::ONE_MINUS_SRC_ALPHA);
+
+	cmdb->bindTexture(0, 0, m_r->getDepthDownscale().m_qd.m_depthRt);
+	cmdb->bindTexture(0, 1, m_r->getSm().m_spotTexArray);
+	cmdb->bindTexture(0, 2, m_r->getSm().m_omniTexArray);
+
+	cmdb->bindUniformBuffer(0, 0, ctx.m_is.m_commonToken);
+	cmdb->bindUniformBuffer(0, 1, ctx.m_is.m_pointLightsToken);
+	cmdb->bindUniformBuffer(0, 2, ctx.m_is.m_spotLightsToken);
+	cmdb->bindUniformBuffer(0, 3, token);
+
+	cmdb->bindStorageBuffer(0, 0, ctx.m_is.m_clustersToken);
+	cmdb->bindStorageBuffer(0, 1, ctx.m_is.m_lightIndicesToken);
+
+	cmdb->bindShaderProgram(m_prog);
+
 	cmdb->beginRenderPass(m_fb);
-	cmdb->bindPipeline(m_ppline);
-	cmdb->bindResourceGroup(m_rc, 0, &dyn);
 	m_r->drawQuad(cmdb);
 	cmdb->endRenderPass();
 }

+ 3 - 2
src/anki/renderer/Volumetric.h

@@ -40,13 +40,14 @@ anki_internal:
 	void setPostRunBarriers(RenderingContext& ctx);
 
 private:
-	ResourceGroupPtr m_rc;
 	ShaderResourcePtr m_frag;
-	PipelinePtr m_ppline;
+	ShaderProgramPtr m_prog;
 	FramebufferPtr m_fb;
 
 	Vec3 m_fogColor = Vec3(1.0);
 	F32 m_fogFactor = 1.0;
+
+	ANKI_USE_RESULT Error initInternal(const ConfigSet& config);
 };
 /// @}
 

+ 20 - 2
src/anki/resource/Model.h

@@ -27,18 +27,36 @@ class VertexBufferBinding
 {
 public:
 	BufferPtr m_buffer;
-	U32 m_binding;
 	PtrSize m_offset;
 	PtrSize m_stride;
+
+	Bool operator==(const VertexBufferBinding& b) const
+	{
+		return m_buffer == b.m_buffer && m_offset == b.m_offset && m_stride == b.m_stride;
+	}
+
+	Bool operator!=(const VertexBufferBinding& b) const
+	{
+		return !(*this == b);
+	}
 };
 
 class VertexAttributeInfo
 {
 public:
-	U32 m_location;
 	U32 m_bufferBinding;
 	PixelFormat m_format;
 	PtrSize m_relativeOffset;
+
+	Bool operator==(const VertexAttributeInfo& b) const
+	{
+		return m_bufferBinding == b.m_bufferBinding && m_format == b.m_format && m_relativeOffset == b.m_relativeOffset;
+	}
+
+	Bool operator!=(const VertexAttributeInfo& b) const
+	{
+		return !(*this == b);
+	}
 };
 
 class ModelRenderingInfo

+ 1 - 1
src/anki/scene/CMakeLists.txt

@@ -3,4 +3,4 @@ file(GLOB_RECURSE ANKI_SCENE_HEADERS *.h)
 
 add_library(ankiscene ${ANKI_SCENE_SOURCES} ${ANKI_SCENE_HEADERS})
 
-target_link_libraries(ankiscene ankicore ankievent)
+target_link_libraries(ankiscene ankievent)

+ 0 - 8
src/anki/scene/LensFlareComponent.cpp

@@ -25,14 +25,6 @@ Error LensFlareComponent::init(const CString& textureFilename)
 	// Texture
 	ANKI_CHECK(getSceneGraph().getResourceManager().loadResource(textureFilename, m_tex));
 
-	// Resource group
-	ResourceGroupInitInfo rcInit;
-	rcInit.m_textures[0].m_texture = m_tex->getGrTexture();
-	rcInit.m_textures[0].m_usage = TextureUsageBit::SAMPLED_FRAGMENT;
-	rcInit.m_uniformBuffers[0].m_uploadedMemory = true;
-	rcInit.m_uniformBuffers[0].m_usage = BufferUsageBit::UNIFORM_FRAGMENT | BufferUsageBit::UNIFORM_VERTEX;
-	m_rcGroup = getSceneGraph().getGrManager().newInstance<ResourceGroup>(rcInit);
-
 	return ErrorCode::NONE;
 }
 

+ 0 - 7
src/anki/scene/LensFlareComponent.h

@@ -72,11 +72,6 @@ public:
 		return m_tex->getGrTexture();
 	}
 
-	const ResourceGroupPtr& getResourceGroup() const
-	{
-		return m_rcGroup;
-	}
-
 	/// @name SceneComponent virtuals
 	/// @{
 	Error update(SceneNode& node, F32 prevTime, F32 crntTime, Bool& updated) override
@@ -95,8 +90,6 @@ private:
 	Vec2 m_otherFlareSize = Vec2(1.0);
 
 	Vec4 m_worldPosition = Vec4(0.0);
-
-	ResourceGroupPtr m_rcGroup;
 };
 /// @}
 

+ 16 - 5
src/anki/scene/ModelNode.cpp

@@ -71,16 +71,27 @@ Error ModelPatchNode::buildRendering(const RenderingBuildInfoIn& in, RenderingBu
 	ANKI_ASSERT(m_modelPatch->getSubMeshesCount() == 0);
 
 	// State
-	ModelRenderingInfo modelInf(*out.m_state);
+	ModelRenderingInfo modelInf;
 	m_modelPatch->getRenderingDataSub(in.m_key, WeakArray<U8>(), modelInf);
-	ANKI_ASSERT(modelInf.m_stateMask
-		== (PipelineSubStateBit::VERTEX | PipelineSubStateBit::SHADERS | PipelineSubStateBit::INPUT_ASSEMBLER));
 
-	out.m_stateMask = modelInf.m_stateMask;
+	out.m_vertexBufferBindingCount = modelInf.m_vertexBufferBindingCount;
+	for(U i = 0; i < modelInf.m_vertexBufferBindingCount; ++i)
+	{
+		static_cast<VertexBufferBinding&>(out.m_vertexBufferBindings[i]) = modelInf.m_vertexBufferBindings[i];
+	}
+
+	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_indexBuffer = modelInf.m_indexBuffer;
+
+	out.m_program = modelInf.m_program;
 
 	// Other
 	ANKI_ASSERT(modelInf.m_drawcallCount == 1 && "Cannot accept multi-draw");
-	out.m_resourceGroup = modelInf.m_resourceGroup;
 	out.m_drawcall.m_elements.m_count = modelInf.m_indicesCountArray[0];
 	out.m_drawcall.m_elements.m_instanceCount = in.m_key.m_instanceCount;
 	out.m_drawcall.m_elements.m_firstIndex = modelInf.m_indicesOffsetArray[0] / sizeof(U16);

+ 22 - 37
src/anki/scene/ParticleEmitter.cpp

@@ -272,20 +272,6 @@ Error ParticleEmitter::init(const CString& filename)
 	// Create the vertex buffer and object
 	m_vertBuffSize = m_maxNumOfParticles * VERTEX_SIZE;
 
-	GrManager& gr = getSceneGraph().getGrManager();
-
-	ResourceGroupInitInfo rcinit;
-	m_particleEmitterResource->getMaterial().fillResourceGroupInitInfo(rcinit);
-
-	for(U i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i)
-	{
-		m_vertBuffs[i] = gr.newInstance<Buffer>(m_vertBuffSize, BufferUsageBit::VERTEX, BufferMapAccessBit::WRITE);
-
-		rcinit.m_vertexBuffers[0].m_buffer = m_vertBuffs[i];
-
-		m_grGroups[i] = gr.newInstance<ResourceGroup>(rcinit);
-	}
-
 	return ErrorCode::NONE;
 }
 
@@ -298,38 +284,37 @@ Error ParticleEmitter::buildRendering(const RenderingBuildInfoIn& in, RenderingB
 		return ErrorCode::NONE;
 	}
 
-	U frame = (getGlobalTimestamp() % 3);
+	U frame = (getGlobalTimestamp() % MAX_FRAMES_IN_FLIGHT);
 
-	PipelineSubStateBit stateMask;
-	m_particleEmitterResource->getRenderingInfo(in.m_key.m_lod, *out.m_state, stateMask);
-	ANKI_ASSERT(stateMask == PipelineSubStateBit::SHADERS);
+	m_particleEmitterResource->getRenderingInfo(in.m_key.m_lod, out.m_program);
 
-	VertexStateInfo& vertState = out.m_state->m_vertex;
-	vertState.m_bindingCount = 1;
-	vertState.m_bindings[0].m_stride = VERTEX_SIZE;
-	vertState.m_attributeCount = 3;
-	vertState.m_attributes[0].m_format = PixelFormat(ComponentFormat::R32G32B32, TransformFormat::FLOAT);
-	vertState.m_attributes[0].m_offset = 0;
-	vertState.m_attributes[0].m_binding = 0;
-	vertState.m_attributes[1].m_format = PixelFormat(ComponentFormat::R32, TransformFormat::FLOAT);
-	vertState.m_attributes[1].m_offset = sizeof(Vec3);
-	vertState.m_attributes[1].m_binding = 0;
-	vertState.m_attributes[2].m_format = PixelFormat(ComponentFormat::R32, TransformFormat::FLOAT);
-	vertState.m_attributes[2].m_offset = sizeof(Vec3) + sizeof(F32);
-	vertState.m_attributes[2].m_binding = 0;
+	out.m_vertexBufferBindingCount = 1;
+	out.m_vertexBufferBindings[0].m_buffer = m_vertBuffs[frame];
+	out.m_vertexBufferBindings[0].m_binding = 0;
+	out.m_vertexBufferBindings[0].m_offset = 0;
+	out.m_vertexBufferBindings[0].m_stride = VERTEX_SIZE;
 
-	out.m_state->m_inputAssembler.m_topology = PrimitiveTopology::POINTS;
+	out.m_vertexAttributeCount = 3;
+	out.m_vertexAttributes[0].m_location = 0;
+	out.m_vertexAttributes[0].m_bufferBinding = 0;
+	out.m_vertexAttributes[0].m_format = PixelFormat(ComponentFormat::R32G32B32, TransformFormat::FLOAT);
+	out.m_vertexAttributes[0].m_relativeOffset = 0;
+	out.m_vertexAttributes[1].m_location = 1;
+	out.m_vertexAttributes[1].m_bufferBinding = 0;
+	out.m_vertexAttributes[1].m_format = PixelFormat(ComponentFormat::R32, TransformFormat::FLOAT);
+	out.m_vertexAttributes[1].m_relativeOffset = sizeof(Vec3);
+	out.m_vertexAttributes[2].m_location = 2;
+	out.m_vertexAttributes[2].m_bufferBinding = 0;
+	out.m_vertexAttributes[2].m_format = PixelFormat(ComponentFormat::R32, TransformFormat::FLOAT);
+	out.m_vertexAttributes[2].m_relativeOffset = sizeof(Vec3) + sizeof(F32);
 
-	out.m_stateMask = stateMask | PipelineSubStateBit::VERTEX | PipelineSubStateBit::INPUT_ASSEMBLER;
+	out.m_topology = PrimitiveTopology::POINTS;
 
 	out.m_drawArrays = true;
 	out.m_drawcall.m_arrays.m_count = m_aliveParticlesCount;
 
-	out.m_resourceGroup = m_grGroups[frame];
-
 	// The particles are already in world position
-	out.m_hasTransform = true;
-	out.m_transform = Mat4::getIdentity();
+	out.m_hasTransform = false;
 
 	return ErrorCode::NONE;
 }

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

@@ -191,7 +191,6 @@ private:
 	/// @{
 	U32 m_vertBuffSize = 0;
 	Array<BufferPtr, MAX_FRAMES_IN_FLIGHT> m_vertBuffs;
-	Array<ResourceGroupPtr, MAX_FRAMES_IN_FLIGHT> m_grGroups;
 	/// @}
 
 	SimulationType m_simulationType = SimulationType::UNDEFINED;

+ 0 - 2
src/anki/scene/RenderComponent.cpp

@@ -63,8 +63,6 @@ RenderComponent::~RenderComponent()
 	}
 
 	m_vars.destroy(alloc);
-
-	m_localPplineCache.destroy(getAllocator());
 }
 
 Error RenderComponent::init()

+ 61 - 45
src/anki/scene/RenderComponent.h

@@ -8,6 +8,7 @@
 #include <anki/scene/Common.h>
 #include <anki/scene/SceneComponent.h>
 #include <anki/resource/Material.h>
+#include <anki/resource/Model.h>
 #include <anki/util/HashMap.h>
 
 namespace anki
@@ -110,12 +111,49 @@ public:
 	U32 m_subMeshIndicesCount;
 };
 
+/// Info on the vertex buffer binding.
+class RenderingVertexBufferBinding : public VertexBufferBinding
+{
+public:
+	TransientMemoryToken m_token;
+
+	Bool operator==(const RenderingVertexBufferBinding& b) const
+	{
+		if(m_token)
+		{
+			return m_token == b.m_token;
+		}
+		else
+		{
+			return static_cast<const VertexBufferBinding&>(*this) == static_cast<const VertexBufferBinding&>(b);
+		}
+	}
+
+	Bool operator!=(const RenderingVertexBufferBinding& b) const
+	{
+		return !(*this == b);
+	}
+};
+
+using RenderingVertexAttributeInfo = VertexAttributeInfo;
+
 /// Rendering data output.
 class RenderingBuildInfoOut
 {
 public:
-	ResourceGroupPtr m_resourceGroup;
 	Mat4 m_transform;
+	Bool8 m_hasTransform = false;
+
+	ShaderProgramPtr m_program;
+
+	Array<RenderingVertexBufferBinding, MAX_VERTEX_ATTRIBUTES> m_vertexBufferBindings;
+	U32 m_vertexBufferBindingCount;
+	Array<RenderingVertexAttributeInfo, MAX_VERTEX_ATTRIBUTES> m_vertexAttributes;
+	U32 m_vertexAttributeCount;
+
+	BufferPtr m_indexBuffer;
+	TransientMemoryToken m_indexBufferToken;
+
 	union A
 	{
 		DrawArraysIndirectInfo m_arrays;
@@ -126,17 +164,11 @@ public:
 		{
 		}
 	} m_drawcall;
-	Bool8 m_drawArrays = false;
-	Bool8 m_hasTransform = false;
+	Bool m_drawArrays = false;
 
-	PipelineInitInfo* m_state = nullptr;
-	PipelineSubStateBit m_stateMask = PipelineSubStateBit::NONE;
+	PrimitiveTopology m_topology = PrimitiveTopology::TRIANGLES;
 
-	RenderingBuildInfoOut(PipelineInitInfo* state)
-		: m_state(state)
-	{
-		ANKI_ASSERT(state);
-	}
+	RenderingBuildInfoOut() = default;
 
 	RenderingBuildInfoOut(const RenderingBuildInfoOut& b)
 	{
@@ -145,13 +177,27 @@ public:
 
 	RenderingBuildInfoOut& operator=(const RenderingBuildInfoOut& b)
 	{
-		m_resourceGroup = b.m_resourceGroup;
 		m_transform = b.m_transform;
-		m_drawcall.m_elements = b.m_drawcall.m_elements;
-		m_drawArrays = b.m_drawArrays;
 		m_hasTransform = b.m_hasTransform;
-		m_state = b.m_state;
-		m_stateMask = b.m_stateMask;
+
+		m_vertexBufferBindingCount = b.m_vertexBufferBindingCount;
+		for(U i = 0; i < m_vertexBufferBindingCount; ++i)
+		{
+			m_vertexBufferBindings[i] = b.m_vertexBufferBindings[i];
+		}
+
+		m_vertexAttributeCount = b.m_vertexAttributeCount;
+		for(U i = 0; i < m_vertexAttributeCount; ++i)
+		{
+			m_vertexAttributes[i] = b.m_vertexAttributes[i];
+		}
+
+		m_indexBuffer = b.m_indexBuffer;
+		m_indexBufferToken = b.m_indexBufferToken;
+
+		m_drawArrays = b.m_drawArrays;
+
+		m_topology = b.m_topology;
 
 		return *this;
 	}
@@ -221,32 +267,6 @@ public:
 		return err;
 	}
 
-	Bool tryGetPipeline(U64 hash, PipelinePtr& ppline)
-	{
-		LockGuard<SpinLock> lock(m_localPplineCacheMtx);
-
-		auto it = m_localPplineCache.find(hash);
-		if(it != m_localPplineCache.getEnd())
-		{
-			ppline = *it;
-			return true;
-		}
-		else
-		{
-			return false;
-		}
-	}
-
-	void storePipeline(U64 hash, PipelinePtr ppline)
-	{
-		LockGuard<SpinLock> lock(m_localPplineCacheMtx);
-
-		if(m_localPplineCache.find(hash) == m_localPplineCache.getEnd())
-		{
-			m_localPplineCache.pushBack(getAllocator(), hash, ppline);
-		}
-	}
-
 private:
 	using Key = U64;
 
@@ -272,10 +292,6 @@ private:
 
 	Variables m_vars;
 	const Material* m_mtl;
-
-	/// This is an optimization, a local hash of pipelines.
-	HashMap<U64, PipelinePtr, Hasher, Compare> m_localPplineCache;
-	SpinLock m_localPplineCacheMtx;
 };
 /// @}