Browse Source

GR interface: Fix the tests

Panagiotis Christopoulos Charitos 9 years ago
parent
commit
a1bbb2f70f

+ 118 - 46
src/anki/gr/gl/CommandBuffer.cpp

@@ -42,6 +42,10 @@ void CommandBuffer::init(CommandBufferInitInfo& inf)
 {
 	m_impl.reset(getAllocator().newInstance<CommandBufferImpl>(&getManager()));
 	m_impl->init(inf);
+
+#if ANKI_ASSERTIONS
+	m_impl->m_state.m_secondLevel = !!(inf.m_flags & CommandBufferFlag::SECOND_LEVEL);
+#endif
 }
 
 void CommandBuffer::flush()
@@ -77,7 +81,7 @@ void CommandBuffer::bindVertexBuffer(U32 binding, BufferPtr buff, PtrSize offset
 		PtrSize m_offset;
 		PtrSize m_stride;
 
-		Cmd(BufferPtr buff, U32 binding, PtrSize offset, PtrSize stride)
+		Cmd(U32 binding, BufferPtr buff, PtrSize offset, PtrSize stride)
 			: m_buff(buff)
 			, m_binding(binding)
 			, m_offset(offset)
@@ -92,7 +96,10 @@ void CommandBuffer::bindVertexBuffer(U32 binding, BufferPtr buff, PtrSize offset
 		}
 	};
 
-	m_impl->pushBackNewCommand<Cmd>(buff, binding, offset, stride);
+	if(m_impl->m_state.bindVertexBuffer(binding, buff, offset, stride))
+	{
+		m_impl->pushBackNewCommand<Cmd>(binding, buff, offset, stride);
+	}
 }
 
 void CommandBuffer::bindVertexBuffer(U32 binding, const TransientMemoryToken& token, PtrSize stride)
@@ -120,8 +127,13 @@ void CommandBuffer::bindVertexBuffer(U32 binding, const TransientMemoryToken& to
 		}
 	};
 
+	ANKI_ASSERT(token.m_usage == BufferUsageBit::VERTEX);
 	GLuint name = getManager().getImplementation().getTransientMemoryManager().getGlName(token);
-	m_impl->pushBackNewCommand<Cmd>(binding, token, stride, name);
+
+	if(m_impl->m_state.bindVertexBuffer(binding, token, stride))
+	{
+		m_impl->pushBackNewCommand<Cmd>(binding, token, stride, name);
+	}
 }
 
 void CommandBuffer::setVertexAttribute(U32 location, U32 buffBinding, const PixelFormat& fmt, PtrSize relativeOffset)
@@ -154,7 +166,8 @@ void CommandBuffer::setVertexAttribute(U32 location, U32 buffBinding, const Pixe
 		}
 	};
 
-	m_impl->m_state.setVertexAttribute(location, buffBinding, fmt, relativeOffset, [=]() {
+	if(m_impl->m_state.setVertexAttribute(location, buffBinding, fmt, relativeOffset))
+	{
 		U compCount;
 		GLenum type;
 		Bool normalized;
@@ -162,7 +175,7 @@ void CommandBuffer::setVertexAttribute(U32 location, U32 buffBinding, const Pixe
 		convertVertexFormat(fmt, compCount, type, normalized);
 
 		m_impl->pushBackNewCommand<Cmd>(location, buffBinding, compCount, type, normalized, relativeOffset);
-	});
+	}
 }
 
 void CommandBuffer::bindIndexBuffer(BufferPtr buff, PtrSize offset, IndexType type)
@@ -184,9 +197,10 @@ void CommandBuffer::bindIndexBuffer(BufferPtr buff, PtrSize offset, IndexType ty
 		}
 	};
 
-	m_impl->pushBackNewCommand<Cmd>(buff);
-	m_impl->m_state.m_indexBuffOffset = offset;
-	m_impl->m_state.m_indexType = convertIndexType(type);
+	if(m_impl->m_state.bindIndexBuffer(buff, offset, type))
+	{
+		m_impl->pushBackNewCommand<Cmd>(buff);
+	}
 }
 
 void CommandBuffer::bindIndexBuffer(const TransientMemoryToken& token, IndexType type)
@@ -221,7 +235,10 @@ void CommandBuffer::setPrimitiveRestart(Bool enable)
 		}
 	};
 
-	m_impl->m_state.setPrimitiveRestart(enable, [=]() { m_impl->pushBackNewCommand<Cmd>(enable); });
+	if(m_impl->m_state.setPrimitiveRestart(enable))
+	{
+		m_impl->pushBackNewCommand<Cmd>(enable);
+	}
 }
 
 void CommandBuffer::setViewport(U16 minx, U16 miny, U16 maxx, U16 maxy)
@@ -243,8 +260,10 @@ void CommandBuffer::setViewport(U16 minx, U16 miny, U16 maxx, U16 maxy)
 		}
 	};
 
-	m_impl->m_state.setViewport(
-		minx, miny, maxx, maxy, [=]() { m_impl->pushBackNewCommand<ViewportCommand>(minx, miny, maxx, maxy); });
+	if(m_impl->m_state.setViewport(minx, miny, maxx, maxy))
+	{
+		m_impl->pushBackNewCommand<ViewportCommand>(minx, miny, maxx, maxy);
+	}
 }
 
 void CommandBuffer::setScissorRect(U16 minx, U16 miny, U16 maxx, U16 maxy)
@@ -271,7 +290,10 @@ void CommandBuffer::setFillMode(FillMode mode)
 		}
 	};
 
-	m_impl->m_state.setFillMode(mode, [=]() { m_impl->pushBackNewCommand<Cmd>(convertFillMode(mode)); });
+	if(m_impl->m_state.setFillMode(mode))
+	{
+		m_impl->pushBackNewCommand<Cmd>(convertFillMode(mode));
+	}
 }
 
 void CommandBuffer::setCullMode(FaceSelectionMask mode)
@@ -293,7 +315,10 @@ void CommandBuffer::setCullMode(FaceSelectionMask mode)
 		}
 	};
 
-	m_impl->m_state.setCullMode(mode, [=]() { m_impl->pushBackNewCommand<Cmd>(convertFaceMode(mode)); });
+	if(m_impl->m_state.setCullMode(mode))
+	{
+		m_impl->pushBackNewCommand<Cmd>(convertFaceMode(mode));
+	}
 }
 
 void CommandBuffer::setPolygonOffset(F32 factor, F32 units)
@@ -326,7 +351,10 @@ void CommandBuffer::setPolygonOffset(F32 factor, F32 units)
 		}
 	};
 
-	m_impl->m_state.setPolygonOffset(factor, units, [=]() { m_impl->pushBackNewCommand<Cmd>(factor, units); });
+	if(m_impl->m_state.setPolygonOffset(factor, units))
+	{
+		m_impl->pushBackNewCommand<Cmd>(factor, units);
+	}
 }
 
 void CommandBuffer::setStencilOperations(FaceSelectionMask face,
@@ -357,13 +385,13 @@ void CommandBuffer::setStencilOperations(FaceSelectionMask face,
 		}
 	};
 
-	m_impl->m_state.setStencilOperations(face, stencilFail, stencilPassDepthFail, stencilPassDepthPass, [=]() {
-
+	if(m_impl->m_state.setStencilOperations(face, stencilFail, stencilPassDepthFail, stencilPassDepthPass))
+	{
 		m_impl->pushBackNewCommand<Cmd>(convertFaceMode(face),
 			convertStencilOperation(stencilFail),
 			convertStencilOperation(stencilPassDepthFail),
 			convertStencilOperation(stencilPassDepthPass));
-	});
+	}
 }
 
 void CommandBuffer::setStencilCompareFunction(FaceSelectionMask face, CompareOperation comp)
@@ -412,8 +440,10 @@ void CommandBuffer::setStencilWriteMask(FaceSelectionMask face, U32 mask)
 		}
 	};
 
-	m_impl->m_state.setStencilWriteMask(
-		face, mask, [=]() { m_impl->pushBackNewCommand<Cmd>(convertFaceMode(face), mask); });
+	if(m_impl->m_state.setStencilWriteMask(face, mask))
+	{
+		m_impl->pushBackNewCommand<Cmd>(convertFaceMode(face), mask);
+	}
 }
 
 void CommandBuffer::setStencilReference(FaceSelectionMask face, U32 ref)
@@ -441,7 +471,10 @@ void CommandBuffer::setDepthWrite(Bool enable)
 		}
 	};
 
-	m_impl->m_state.setDepthWrite(enable, [=]() { m_impl->pushBackNewCommand<Cmd>(enable); });
+	if(m_impl->m_state.setDepthWrite(enable))
+	{
+		m_impl->pushBackNewCommand<Cmd>(enable);
+	}
 }
 
 void CommandBuffer::setDepthCompareFunction(CompareOperation op)
@@ -463,8 +496,10 @@ void CommandBuffer::setDepthCompareFunction(CompareOperation op)
 		}
 	};
 
-	m_impl->m_state.setDepthCompareFunction(
-		op, [=]() { m_impl->pushBackNewCommand<Cmd>(convertCompareOperation(op)); });
+	if(m_impl->m_state.setDepthCompareFunction(op))
+	{
+		m_impl->pushBackNewCommand<Cmd>(convertCompareOperation(op));
+	}
 }
 
 void CommandBuffer::setAlphaToCoverage(Bool enable)
@@ -501,8 +536,10 @@ void CommandBuffer::setColorChannelWriteMask(U32 attachment, ColorBit mask)
 		}
 	};
 
-	m_impl->m_state.setColorChannelWriteMask(
-		attachment, mask, [=]() { m_impl->pushBackNewCommand<Cmd>(attachment, mask); });
+	if(m_impl->m_state.setColorChannelWriteMask(attachment, mask))
+	{
+		m_impl->pushBackNewCommand<Cmd>(attachment, mask);
+	}
 }
 
 void CommandBuffer::setBlendMethods(U32 attachment, BlendMethod src, BlendMethod dst)
@@ -528,9 +565,10 @@ void CommandBuffer::setBlendMethods(U32 attachment, BlendMethod src, BlendMethod
 		}
 	};
 
-	m_impl->m_state.setBlendMethods(attachment, src, dst, [=]() {
+	if(m_impl->m_state.setBlendMethods(attachment, src, dst))
+	{
 		m_impl->pushBackNewCommand<Cmd>(attachment, convertBlendMethod(src), convertBlendMethod(dst));
-	});
+	}
 }
 
 void CommandBuffer::setBlendFunction(U32 attachment, BlendFunction func)
@@ -554,8 +592,10 @@ void CommandBuffer::setBlendFunction(U32 attachment, BlendFunction func)
 		}
 	};
 
-	m_impl->m_state.setBlendFunction(
-		attachment, func, [=]() { m_impl->pushBackNewCommand<Cmd>(attachment, convertBlendFunction(func)); });
+	if(m_impl->m_state.setBlendFunction(attachment, func))
+	{
+		m_impl->pushBackNewCommand<Cmd>(attachment, convertBlendFunction(func));
+	}
 }
 
 void CommandBuffer::bindTexture(U32 set, U32 binding, TexturePtr tex, DepthStencilAspectMask aspect)
@@ -580,8 +620,11 @@ void CommandBuffer::bindTexture(U32 set, U32 binding, TexturePtr tex, DepthStenc
 		}
 	};
 
-	U unit = binding + MAX_TEXTURE_BINDINGS * set;
-	m_impl->pushBackNewCommand<Cmd>(unit, tex);
+	if(m_impl->m_state.bindTexture(set, binding, tex, aspect))
+	{
+		U unit = binding + MAX_TEXTURE_BINDINGS * set;
+		m_impl->pushBackNewCommand<Cmd>(unit, tex);
+	}
 }
 
 void CommandBuffer::bindTextureAndSampler(
@@ -609,8 +652,11 @@ void CommandBuffer::bindTextureAndSampler(
 		}
 	};
 
-	U unit = binding + MAX_TEXTURE_BINDINGS * set;
-	m_impl->pushBackNewCommand<Cmd>(unit, tex, sampler);
+	if(m_impl->m_state.bindTextureAndSampler(set, binding, tex, sampler, aspect))
+	{
+		U unit = binding + MAX_TEXTURE_BINDINGS * set;
+		m_impl->pushBackNewCommand<Cmd>(unit, tex, sampler);
+	}
 }
 
 void CommandBuffer::bindUniformBuffer(U32 set, U32 binding, BufferPtr buff, PtrSize offset)
@@ -636,8 +682,11 @@ void CommandBuffer::bindUniformBuffer(U32 set, U32 binding, BufferPtr buff, PtrS
 		}
 	};
 
-	binding = binding + MAX_UNIFORM_BUFFER_BINDINGS * set;
-	m_impl->pushBackNewCommand<Cmd>(binding, buff, offset);
+	if(m_impl->m_state.bindUniformBuffer(set, binding, buff, offset))
+	{
+		binding = binding + MAX_UNIFORM_BUFFER_BINDINGS * set;
+		m_impl->pushBackNewCommand<Cmd>(binding, buff, offset);
+	}
 }
 
 void CommandBuffer::bindUniformBuffer(U32 set, U32 binding, const TransientMemoryToken& token)
@@ -663,9 +712,14 @@ void CommandBuffer::bindUniformBuffer(U32 set, U32 binding, const TransientMemor
 		}
 	};
 
-	binding = binding + MAX_UNIFORM_BUFFER_BINDINGS * set;
-	GLuint name = getManager().getImplementation().getTransientMemoryManager().getGlName(token);
-	m_impl->pushBackNewCommand<Cmd>(binding, token, name);
+	ANKI_ASSERT(!!(token.m_usage & BufferUsageBit::UNIFORM_ALL));
+
+	if(m_impl->m_state.bindUniformBuffer(set, binding, token))
+	{
+		binding = binding + MAX_UNIFORM_BUFFER_BINDINGS * set;
+		GLuint name = getManager().getImplementation().getTransientMemoryManager().getGlName(token);
+		m_impl->pushBackNewCommand<Cmd>(binding, token, name);
+	}
 }
 
 void CommandBuffer::bindStorageBuffer(U32 set, U32 binding, BufferPtr buff, PtrSize offset)
@@ -691,8 +745,11 @@ void CommandBuffer::bindStorageBuffer(U32 set, U32 binding, BufferPtr buff, PtrS
 		}
 	};
 
-	binding = binding + MAX_STORAGE_BUFFER_BINDINGS * set;
-	m_impl->pushBackNewCommand<Cmd>(binding, buff, offset);
+	if(m_impl->m_state.bindStorageBuffer(set, binding, buff, offset))
+	{
+		binding = binding + MAX_STORAGE_BUFFER_BINDINGS * set;
+		m_impl->pushBackNewCommand<Cmd>(binding, buff, offset);
+	}
 }
 
 void CommandBuffer::bindStorageBuffer(U32 set, U32 binding, const TransientMemoryToken& token)
@@ -718,9 +775,14 @@ void CommandBuffer::bindStorageBuffer(U32 set, U32 binding, const TransientMemor
 		}
 	};
 
-	binding = binding + MAX_STORAGE_BUFFER_BINDINGS * set;
-	GLuint name = getManager().getImplementation().getTransientMemoryManager().getGlName(token);
-	m_impl->pushBackNewCommand<Cmd>(binding, token, name);
+	ANKI_ASSERT(!!(token.m_usage & BufferUsageBit::STORAGE_ALL));
+
+	if(m_impl->m_state.bindStorageBuffer(set, binding, token))
+	{
+		binding = binding + MAX_STORAGE_BUFFER_BINDINGS * set;
+		GLuint name = getManager().getImplementation().getTransientMemoryManager().getGlName(token);
+		m_impl->pushBackNewCommand<Cmd>(binding, token, name);
+	}
 }
 
 void CommandBuffer::bindImage(U32 set, U32 binding, TexturePtr img, U32 level)
@@ -752,8 +814,11 @@ void CommandBuffer::bindImage(U32 set, U32 binding, TexturePtr img, U32 level)
 		}
 	};
 
-	binding = binding + set * MAX_IMAGE_BINDINGS;
-	m_impl->pushBackNewCommand<Cmd>(binding, img, level);
+	if(m_impl->m_state.bindImage(set, binding, img, level))
+	{
+		binding = binding + set * MAX_IMAGE_BINDINGS;
+		m_impl->pushBackNewCommand<Cmd>(binding, img, level);
+	}
 }
 
 void CommandBuffer::bindShaderProgram(ShaderProgramPtr prog)
@@ -775,7 +840,10 @@ void CommandBuffer::bindShaderProgram(ShaderProgramPtr prog)
 		}
 	};
 
-	m_impl->m_state.bindShaderProgram(prog, [=]() { m_impl->pushBackNewCommand<Cmd>(prog); });
+	if(m_impl->m_state.bindShaderProgram(prog))
+	{
+		m_impl->pushBackNewCommand<Cmd>(prog);
+	}
 }
 
 void CommandBuffer::beginRenderPass(FramebufferPtr fb)
@@ -797,7 +865,10 @@ void CommandBuffer::beginRenderPass(FramebufferPtr fb)
 		}
 	};
 
-	m_impl->m_state.beginRenderPass(fb, [=]() { m_impl->pushBackNewCommand<BindFramebufferCommand>(fb); });
+	if(m_impl->m_state.beginRenderPass(fb))
+	{
+		m_impl->pushBackNewCommand<BindFramebufferCommand>(fb);
+	}
 }
 
 void CommandBuffer::endRenderPass()
@@ -998,6 +1069,7 @@ void CommandBuffer::dispatchCompute(U32 groupCountX, U32 groupCountY, U32 groupC
 		}
 	};
 
+	ANKI_ASSERT(!!(m_impl->m_flags & CommandBufferFlag::COMPUTE_WORK));
 	m_impl->m_state.checkDispatch();
 	m_impl->pushBackNewCommand<DispatchCommand>(groupCountX, groupCountY, groupCountZ);
 }

+ 2 - 0
src/anki/gr/gl/ShaderProgramImpl.cpp

@@ -42,6 +42,8 @@ Error ShaderProgramImpl::initCompute(ShaderPtr comp)
 	m_glName = glCreateProgram();
 	ANKI_ASSERT(m_glName != 0);
 
+	glAttachShader(m_glName, comp->m_impl->getGlName());
+
 	return link(0, 0);
 }
 

+ 198 - 74
src/anki/gr/gl/StateTracker.h

@@ -9,6 +9,10 @@
 #include <anki/gr/ShaderProgram.h>
 #include <anki/gr/Framebuffer.h>
 #include <anki/gr/gl/FramebufferImpl.h>
+#include <anki/gr/Buffer.h>
+#include <anki/gr/gl/BufferImpl.h>
+#include <anki/gr/Sampler.h>
+#include <anki/gr/gl/SamplerImpl.h>
 #include <anki/gr/common/Misc.h>
 
 namespace anki
@@ -24,6 +28,10 @@ public:
 	/// If it's false then there might be unset state.
 	Bool8 m_mayContainUnsetState = true;
 
+#if ANKI_ASSERTIONS
+	Bool8 m_secondLevel = false;
+#endif
+
 	/// @name vert_state
 	/// @{
 	class VertexAttribute
@@ -36,36 +44,77 @@ public:
 
 	Array<VertexAttribute, MAX_VERTEX_ATTRIBUTES> m_attribs;
 
-	template<typename TFunc>
-	void setVertexAttribute(U32 location, U32 buffBinding, const PixelFormat& fmt, PtrSize relativeOffset, TFunc func)
+	Bool setVertexAttribute(U32 location, U32 buffBinding, const PixelFormat& fmt, PtrSize relativeOffset)
 	{
 		VertexAttribute& attrib = m_attribs[location];
 		if(attrib.m_buffBinding != buffBinding || attrib.m_fmt != fmt || attrib.m_relativeOffset != relativeOffset)
 		{
-			func();
 			attrib.m_buffBinding = buffBinding;
 			attrib.m_fmt = fmt;
 			attrib.m_relativeOffset = relativeOffset;
+			return true;
 		}
+
+		return false;
 	}
 
+	class VertexBuffer
+	{
+	public:
+		BufferPtr m_buff;
+		PtrSize m_offset = 0;
+		PtrSize m_stride = 0;
+		TransientMemoryToken m_token;
+	};
+
+	Array<VertexBuffer, MAX_VERTEX_ATTRIBUTES> m_vertBuffs;
+
+	Bool bindVertexBuffer(U32 binding, BufferPtr buff, PtrSize offset, PtrSize stride)
+	{
+		VertexBuffer& b = m_vertBuffs[binding];
+		b.m_buff = buff;
+		b.m_offset = offset;
+		b.m_stride = stride;
+		b.m_token = {};
+		return true;
+	}
+
+	Bool bindVertexBuffer(U32 binding, const TransientMemoryToken& token, PtrSize stride)
+	{
+		VertexBuffer& b = m_vertBuffs[binding];
+		b.m_buff = {};
+		b.m_offset = 0;
+		b.m_stride = stride;
+		b.m_token = token;
+		return true;
+	}
+
+	BufferPtr m_indexBuff;
 	PtrSize m_indexBuffOffset = MAX_PTR_SIZE;
 	GLenum m_indexType = 0;
+
+	Bool bindIndexBuffer(BufferPtr buff, PtrSize offset, IndexType type)
+	{
+		m_indexBuff = buff;
+		m_indexBuffOffset = offset;
+		m_indexType = convertIndexType(type);
+		return true;
+	}
 	/// @}
 
 	/// @name input_assembly
 	/// @{
 	U8 m_primitiveRestart = 2;
 
-	template<typename TFunc>
-	void setPrimitiveRestart(Bool enable, TFunc func)
+	Bool setPrimitiveRestart(Bool enable)
 	{
 		U enablei = enable ? 1 : 0;
 		if(enablei != m_primitiveRestart)
 		{
 			m_primitiveRestart = enablei;
-			func();
+			return true;
 		}
+		return false;
 	}
 	/// @}
 
@@ -73,15 +122,15 @@ public:
 	/// @{
 	Array<U16, 4> m_viewport = {{MAX_U16, MAX_U16, MAX_U16, MAX_U16}};
 
-	template<typename TFunc>
-	void setViewport(U16 minx, U16 miny, U16 maxx, U16 maxy, TFunc func)
+	Bool setViewport(U16 minx, U16 miny, U16 maxx, U16 maxy)
 	{
 		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};
-			func();
+			return true;
 		}
+		return false;
 	}
 	/// @}
 
@@ -89,40 +138,40 @@ public:
 	/// @{
 	FillMode m_fillMode = FillMode::COUNT;
 
-	template<typename TFunc>
-	void setFillMode(FillMode mode, TFunc func)
+	Bool setFillMode(FillMode mode)
 	{
 		if(m_fillMode != mode)
 		{
 			m_fillMode = mode;
-			func();
+			return true;
 		}
+		return false;
 	}
 
 	FaceSelectionMask m_cullMode = static_cast<FaceSelectionMask>(0);
 
-	template<typename TFunc>
-	void setCullMode(FaceSelectionMask mode, TFunc func)
+	Bool setCullMode(FaceSelectionMask mode)
 	{
 		if(m_cullMode != mode)
 		{
 			m_cullMode = mode;
-			func();
+			return true;
 		}
+		return false;
 	}
 
 	F32 m_polyOffsetFactor = -1.0;
 	F32 m_polyOffsetUnits = -1.0;
 
-	template<typename TFunc>
-	void setPolygonOffset(F32 factor, F32 units, TFunc func)
+	Bool setPolygonOffset(F32 factor, F32 units)
 	{
 		if(factor != m_polyOffsetFactor || units != m_polyOffsetUnits)
 		{
 			m_polyOffsetFactor = factor;
 			m_polyOffsetUnits = units;
-			func();
+			return true;
 		}
+		return false;
 	}
 	/// @}
 
@@ -150,12 +199,10 @@ public:
 	Array<StencilOperation, 2> m_stencilPassDepthFail = {{StencilOperation::COUNT, StencilOperation::COUNT}};
 	Array<StencilOperation, 2> m_stencilPassDepthPass = {{StencilOperation::COUNT, StencilOperation::COUNT}};
 
-	template<typename TFunc>
-	void setStencilOperations(FaceSelectionMask face,
+	Bool setStencilOperations(FaceSelectionMask face,
 		StencilOperation stencilFail,
 		StencilOperation stencilPassDepthFail,
-		StencilOperation stencilPassDepthPass,
-		TFunc func)
+		StencilOperation stencilPassDepthPass)
 	{
 		Bool changed = false;
 		if(!!(face & FaceSelectionMask::FRONT)
@@ -178,10 +225,7 @@ public:
 			changed = true;
 		}
 
-		if(changed)
-		{
-			func();
-		}
+		return changed;
 	}
 
 	Array<Bool8, 2> m_glStencilFuncSeparateDirty = {{false, false}};
@@ -225,8 +269,7 @@ public:
 
 	Array<U32, 2> m_stencilWriteMask = {{DUMMY_STENCIL_MASK, DUMMY_STENCIL_MASK}};
 
-	template<typename TFunc>
-	void setStencilWriteMask(FaceSelectionMask face, U32 mask, TFunc func)
+	Bool setStencilWriteMask(FaceSelectionMask face, U32 mask)
 	{
 		ANKI_ASSERT(mask != DUMMY_STENCIL_MASK && "Oops");
 
@@ -243,10 +286,7 @@ public:
 			changed = true;
 		}
 
-		if(changed)
-		{
-			func();
-		}
+		return changed;
 	}
 
 	Array<U32, 2> m_stencilRef = {{DUMMY_STENCIL_MASK, DUMMY_STENCIL_MASK}};
@@ -285,26 +325,26 @@ public:
 
 	Bool8 m_depthWrite = 2;
 
-	template<typename TFunc>
-	void setDepthWrite(Bool enable, TFunc func)
+	Bool setDepthWrite(Bool enable)
 	{
 		if(m_depthWrite != enable)
 		{
 			m_depthWrite = enable;
-			func();
+			return true;
 		}
+		return false;
 	}
 
 	CompareOperation m_depthOp = CompareOperation::COUNT;
 
-	template<typename TFunc>
-	void setDepthCompareFunction(CompareOperation op, TFunc func)
+	Bool setDepthCompareFunction(CompareOperation op)
 	{
 		if(op != m_depthOp)
 		{
 			m_depthOp = op;
-			func();
+			return true;
 		}
+		return false;
 	}
 	/// @}
 
@@ -314,14 +354,14 @@ public:
 	Array<ColorBit, MAX_COLOR_ATTACHMENTS> m_colorWriteMasks = {
 		{INVALID_COLOR_MASK, INVALID_COLOR_MASK, INVALID_COLOR_MASK, INVALID_COLOR_MASK}};
 
-	template<typename TFunc>
-	void setColorChannelWriteMask(U32 attachment, ColorBit mask, TFunc func)
+	Bool setColorChannelWriteMask(U32 attachment, ColorBit mask)
 	{
 		if(m_colorWriteMasks[attachment] != mask)
 		{
 			m_colorWriteMasks[attachment] = mask;
-			func();
+			return true;
 		}
+		return false;
 	}
 
 	Array<BlendMethod, MAX_COLOR_ATTACHMENTS> m_blendSrcMethod = {
@@ -329,75 +369,159 @@ public:
 	Array<BlendMethod, MAX_COLOR_ATTACHMENTS> m_blendDstMethod = {
 		{BlendMethod::COUNT, BlendMethod::COUNT, BlendMethod::COUNT, BlendMethod::COUNT}};
 
-	template<typename TFunc>
-	void setBlendMethods(U32 attachment, BlendMethod src, BlendMethod dst, TFunc func)
+	Bool setBlendMethods(U32 attachment, BlendMethod src, BlendMethod dst)
 	{
 		if(m_blendSrcMethod[attachment] != src || m_blendDstMethod[attachment] != dst)
 		{
 			m_blendSrcMethod[attachment] = src;
 			m_blendDstMethod[attachment] = dst;
-			func();
+			return true;
 		}
+		return false;
 	}
 
 	Array<BlendFunction, MAX_COLOR_ATTACHMENTS> m_blendFuncs = {
 		{BlendFunction::COUNT, BlendFunction::COUNT, BlendFunction::COUNT, BlendFunction::COUNT}};
 
-	template<typename TFunc>
-	void setBlendFunction(U32 attachment, BlendFunction func, TFunc funct)
+	Bool setBlendFunction(U32 attachment, BlendFunction func)
 	{
 		if(m_blendFuncs[attachment] != func)
 		{
 			m_blendFuncs[attachment] = func;
-			funct();
+			return true;
 		}
+		return false;
 	}
 	/// @}
 
 	/// @name resources
 	/// @{
-	U64 m_progUuid = MAX_U64;
+	class TextureBinding
+	{
+	public:
+		TexturePtr m_tex;
+		SamplerPtr m_sampler;
+		DepthStencilAspectMask m_aspect;
+	};
 
-	template<typename TFunc>
-	void bindShaderProgram(ShaderProgramPtr prog, TFunc func)
+	Array2d<TextureBinding, MAX_BOUND_RESOURCE_GROUPS, MAX_TEXTURE_BINDINGS> m_textures;
+
+	Bool bindTexture(U32 set, U32 binding, TexturePtr tex, DepthStencilAspectMask aspect)
+	{
+		TextureBinding& b = m_textures[set][binding];
+		b.m_tex = tex;
+		b.m_sampler = {};
+		b.m_aspect = aspect;
+		return true;
+	}
+
+	Bool bindTextureAndSampler(U32 set, U32 binding, TexturePtr tex, SamplerPtr sampler, DepthStencilAspectMask aspect)
+	{
+		TextureBinding& b = m_textures[set][binding];
+		b.m_tex = tex;
+		b.m_sampler = sampler;
+		b.m_aspect = aspect;
+		return true;
+	}
+
+	class ShaderBufferBinding
+	{
+	public:
+		BufferPtr m_buff;
+		PtrSize m_offset;
+		TransientMemoryToken m_token;
+	};
+
+	Array2d<ShaderBufferBinding, MAX_BOUND_RESOURCE_GROUPS, MAX_UNIFORM_BUFFER_BINDINGS> m_ubos;
+
+	Bool bindUniformBuffer(U32 set, U32 binding, BufferPtr buff, PtrSize offset)
+	{
+		ShaderBufferBinding& b = m_ubos[set][binding];
+		b.m_buff = buff;
+		b.m_offset = offset;
+		b.m_token = {};
+		return true;
+	}
+
+	Bool bindUniformBuffer(U32 set, U32 binding, const TransientMemoryToken& token)
+	{
+		ShaderBufferBinding& b = m_ubos[set][binding];
+		b.m_buff = {};
+		b.m_offset = 0;
+		b.m_token = token;
+		return true;
+	}
+
+	Array2d<ShaderBufferBinding, MAX_BOUND_RESOURCE_GROUPS, MAX_STORAGE_BUFFER_BINDINGS> m_ssbos;
+
+	Bool bindStorageBuffer(U32 set, U32 binding, BufferPtr buff, PtrSize offset)
+	{
+		ShaderBufferBinding& b = m_ssbos[set][binding];
+		b.m_buff = buff;
+		b.m_offset = offset;
+		b.m_token = {};
+		return true;
+	}
+
+	Bool bindStorageBuffer(U32 set, U32 binding, const TransientMemoryToken& token)
+	{
+		ShaderBufferBinding& b = m_ssbos[set][binding];
+		b.m_buff = {};
+		b.m_offset = 0;
+		b.m_token = token;
+		return true;
+	}
+
+	class ImageBinding
+	{
+	public:
+		TexturePtr m_tex;
+		U8 m_level;
+	};
+
+	Array2d<ImageBinding, MAX_BOUND_RESOURCE_GROUPS, MAX_IMAGE_BINDINGS> m_images;
+
+	Bool bindImage(U32 set, U32 binding, TexturePtr img, U32 level)
 	{
-		if(prog->getUuid() != m_progUuid)
+		ImageBinding& b = m_images[set][binding];
+		b.m_tex = img;
+		b.m_level = level;
+		return true;
+	}
+
+	ShaderProgramPtr m_prog;
+
+	Bool bindShaderProgram(ShaderProgramPtr prog)
+	{
+		if(prog != m_prog)
 		{
-			m_progUuid = prog->getUuid();
-			func();
+			m_prog = prog;
+			return true;
 		}
+		return false;
 	}
 	/// @}
 
 	/// @name other
 	/// @{
-	U64 m_fbUuid = MAX_U64;
-	U8 m_colorBuffCount = MAX_U8;
-	Bool8 m_fbHasDepth = 2;
-	Bool8 m_fbHasStencil = 2;
+	FramebufferPtr m_fb;
 
-	template<typename TFunc>
-	void beginRenderPass(const FramebufferPtr& fb, TFunc func)
+	Bool beginRenderPass(const FramebufferPtr& fb)
 	{
-		ANKI_ASSERT(m_fbUuid == MAX_U64 && "Already inside a renderpass");
-
-		const FramebufferImpl& impl = *fb->m_impl;
-		m_fbUuid = fb->getUuid();
-		m_colorBuffCount = impl.getColorBufferCount();
-		m_fbHasDepth = impl.hasDepthBuffer();
-		m_fbHasStencil = impl.hasStencilBuffer();
-		func();
+		ANKI_ASSERT(!insideRenderPass() && "Already inside a renderpass");
+		m_fb = fb;
+		return true;
 	}
 
 	void endRenderPass()
 	{
-		ANKI_ASSERT(m_fbUuid != MAX_U64 && "Not inside a renderpass");
-		m_fbUuid = MAX_U64;
+		ANKI_ASSERT(insideRenderPass() && "Not inside a renderpass");
+		m_fb = {};
 	}
 
 	Bool insideRenderPass() const
 	{
-		return m_fbUuid != MAX_U64;
+		return m_fb.isCreated();
 	}
 	/// @}
 
@@ -417,14 +541,14 @@ public:
 	void checkDrawcall() const
 	{
 		ANKI_ASSERT(m_viewport[1] != MAX_U16 && "Forgot to set the viewport");
-		ANKI_ASSERT(m_progUuid != MAX_U64 && "Forgot to bound a program");
-		ANKI_ASSERT(m_fbUuid != MAX_U64 && "Forgot to begin a render pass");
+		ANKI_ASSERT(m_prog.isCreated() && "Forgot to bound a program");
+		ANKI_ASSERT((insideRenderPass() || m_secondLevel) && "Forgot to begin a render pass");
 	}
 
 	void checkDispatch() const
 	{
-		ANKI_ASSERT(m_progUuid != MAX_U64 && "Forgot to bound a program");
-		ANKI_ASSERT(m_fbUuid == MAX_U64 && "Forgot to end the render pass");
+		ANKI_ASSERT(m_prog.isCreated() && "Forgot to bound a program");
+		ANKI_ASSERT(!insideRenderPass() && "Forgot to end the render pass");
 	}
 	/// @}
 };

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

@@ -130,6 +130,7 @@ Error Fs::buildCommandBuffers(RenderingContext& ctx, U threadId, U threadCount)
 
 	cmdb->setBlendMethods(0, BlendMethod::SRC_ALPHA, BlendMethod::ONE_MINUS_SRC_ALPHA);
 	cmdb->setDepthWrite(false);
+	cmdb->setDepthCompareFunction(CompareOperation::LESS);
 
 	// Start drawing
 	Error err = m_r->getSceneDrawer().drawRange(Pass::MS_FS,

+ 96 - 208
tests/gr/Gr.cpp

@@ -298,20 +298,11 @@ static void createGrManager(NativeWindow*& win, GrManager*& gr)
 	ANKI_TEST_EXPECT_NO_ERR(gr->init(inf));
 }
 
-static PipelinePtr createSimplePpline(CString vertSrc, CString fragSrc, GrManager& gr)
+static ShaderProgramPtr createProgram(CString vertSrc, CString fragSrc, GrManager& gr)
 {
 	ShaderPtr vert = gr.newInstance<Shader>(ShaderType::VERTEX, vertSrc);
 	ShaderPtr frag = gr.newInstance<Shader>(ShaderType::FRAGMENT, fragSrc);
-
-	PipelineInitInfo init;
-	init.m_shaders[ShaderType::VERTEX] = vert;
-	init.m_shaders[ShaderType::FRAGMENT] = frag;
-	init.m_color.m_attachments[0].m_format.m_components = ComponentFormat::DEFAULT_FRAMEBUFFER;
-	init.m_color.m_attachmentCount = 1;
-	init.m_depthStencil.m_depthWriteEnabled = false;
-	init.m_depthStencil.m_depthCompareFunction = CompareOperation::ALWAYS;
-
-	return gr.newInstance<Pipeline>(init);
+	return gr.newInstance<ShaderProgram>(vert, frag);
 }
 
 static FramebufferPtr createDefaultFb(GrManager& gr)
@@ -358,11 +349,11 @@ ANKI_TEST(Gr, Shader)
 	COMMON_END()
 }
 
-ANKI_TEST(Gr, Pipeline)
+ANKI_TEST(Gr, ShaderProgram)
 {
 	COMMON_BEGIN()
 
-	PipelinePtr ppline = createSimplePpline(VERT_SRC, FRAG_SRC, *gr);
+	ShaderProgramPtr ppline = createProgram(VERT_SRC, FRAG_SRC, *gr);
 
 	COMMON_END()
 }
@@ -371,7 +362,7 @@ ANKI_TEST(Gr, SimpleDrawcall)
 {
 	COMMON_BEGIN()
 
-	PipelinePtr ppline = createSimplePpline(VERT_SRC, FRAG_SRC, *gr);
+	ShaderProgramPtr prog = createProgram(VERT_SRC, FRAG_SRC, *gr);
 	FramebufferPtr fb = createDefaultFb(*gr);
 
 	U iterations = 100;
@@ -383,13 +374,13 @@ ANKI_TEST(Gr, SimpleDrawcall)
 		gr->beginFrame();
 
 		CommandBufferInitInfo cinit;
+		cinit.m_flags = CommandBufferFlag::GRAPHICS_WORK;
 		CommandBufferPtr cmdb = gr->newInstance<CommandBuffer>(cinit);
 
 		cmdb->setViewport(0, 0, WIDTH, HEIGHT);
-		cmdb->setPolygonOffset(0.0, 0.0);
-		cmdb->bindPipeline(ppline);
+		cmdb->bindShaderProgram(prog);
 		cmdb->beginRenderPass(fb);
-		cmdb->drawArrays(3);
+		cmdb->drawArrays(PrimitiveTopology::TRIANGLES, 3);
 		cmdb->endRenderPass();
 		cmdb->flush();
 
@@ -430,20 +421,6 @@ ANKI_TEST(Gr, Buffer)
 	COMMON_END()
 }
 
-ANKI_TEST(Gr, ResourceGroup)
-{
-	COMMON_BEGIN()
-
-	BufferPtr b = gr->newInstance<Buffer>(sizeof(F32) * 4, BufferUsageBit::UNIFORM_ALL, BufferMapAccessBit::WRITE);
-
-	ResourceGroupInitInfo rcinit;
-	rcinit.m_uniformBuffers[0].m_buffer = b;
-	rcinit.m_uniformBuffers[0].m_usage = BufferUsageBit::UNIFORM_ALL_GRAPHICS;
-	ResourceGroupPtr rc = gr->newInstance<ResourceGroup>(rcinit);
-
-	COMMON_END()
-}
-
 ANKI_TEST(Gr, DrawWithUniforms)
 {
 	COMMON_BEGIN()
@@ -458,16 +435,8 @@ ANKI_TEST(Gr, DrawWithUniforms)
 	ptr[2] = Vec4(0.0, 0.0, 1.0, 0.0);
 	b->unmap();
 
-	// Resource group
-	ResourceGroupInitInfo rcinit;
-	rcinit.m_uniformBuffers[0].m_buffer = b;
-	rcinit.m_uniformBuffers[0].m_usage = BufferUsageBit::UNIFORM_ALL_GRAPHICS;
-	rcinit.m_uniformBuffers[1].m_uploadedMemory = true;
-	rcinit.m_uniformBuffers[1].m_usage = BufferUsageBit::UNIFORM_ALL_GRAPHICS;
-	ResourceGroupPtr rc = gr->newInstance<ResourceGroup>(rcinit);
-
-	// Ppline
-	PipelinePtr ppline = createSimplePpline(VERT_UBO_SRC, FRAG_UBO_SRC, *gr);
+	// Progm
+	ShaderProgramPtr prog = createProgram(VERT_UBO_SRC, FRAG_UBO_SRC, *gr);
 
 	// FB
 	FramebufferPtr fb = createDefaultFb(*gr);
@@ -481,9 +450,9 @@ ANKI_TEST(Gr, DrawWithUniforms)
 		gr->beginFrame();
 
 		// Uploaded buffer
-		TransientMemoryInfo transientInfo;
-		Vec4* rotMat = static_cast<Vec4*>(gr->allocateFrameTransientMemory(
-			sizeof(Vec4), BufferUsageBit::UNIFORM_ALL, transientInfo.m_uniformBuffers[1]));
+		TransientMemoryToken token;
+		Vec4* rotMat =
+			static_cast<Vec4*>(gr->allocateFrameTransientMemory(sizeof(Vec4), BufferUsageBit::UNIFORM_ALL, token));
 		F32 angle = toRad(360.0f / ITERATION_COUNT * iterations);
 		(*rotMat)[0] = cos(angle);
 		(*rotMat)[1] = -sin(angle);
@@ -494,11 +463,13 @@ ANKI_TEST(Gr, DrawWithUniforms)
 		CommandBufferPtr cmdb = gr->newInstance<CommandBuffer>(cinit);
 
 		cmdb->setViewport(0, 0, WIDTH, HEIGHT);
-		cmdb->setPolygonOffset(0.0, 0.0);
-		cmdb->bindPipeline(ppline);
+		cmdb->bindShaderProgram(prog);
 		cmdb->beginRenderPass(fb);
-		cmdb->bindResourceGroup(rc, 0, &transientInfo);
-		cmdb->drawArrays(3);
+
+		cmdb->bindUniformBuffer(0, 0, b, 0);
+		cmdb->bindUniformBuffer(0, 1, token);
+
+		cmdb->drawArrays(PrimitiveTopology::TRIANGLES, 3);
 		cmdb->endRenderPass();
 		cmdb->flush();
 
@@ -550,37 +521,8 @@ ANKI_TEST(Gr, DrawWithVertex)
 	otherColor[2] = Vec3(1.0, 1.0, 0.0);
 	c->unmap();
 
-	// Resource group
-	ResourceGroupInitInfo rcinit;
-	rcinit.m_vertexBuffers[0].m_buffer = b;
-	rcinit.m_vertexBuffers[1].m_buffer = c;
-	ResourceGroupPtr rc = gr->newInstance<ResourceGroup>(rcinit);
-
-	// Shaders
-	ShaderPtr vert = gr->newInstance<Shader>(ShaderType::VERTEX, VERT_INP_SRC);
-	ShaderPtr frag = gr->newInstance<Shader>(ShaderType::FRAGMENT, FRAG_INP_SRC);
-
-	// Ppline
-	PipelineInitInfo init;
-	init.m_shaders[ShaderType::VERTEX] = vert;
-	init.m_shaders[ShaderType::FRAGMENT] = frag;
-	init.m_color.m_attachments[0].m_format.m_components = ComponentFormat::DEFAULT_FRAMEBUFFER;
-	init.m_color.m_attachmentCount = 1;
-	init.m_depthStencil.m_depthWriteEnabled = false;
-	init.m_depthStencil.m_depthCompareFunction = CompareOperation::ALWAYS;
-
-	init.m_vertex.m_attributeCount = 3;
-	init.m_vertex.m_attributes[0].m_format = PixelFormat(ComponentFormat::R32G32B32, TransformFormat::FLOAT);
-	init.m_vertex.m_attributes[1].m_format = PixelFormat(ComponentFormat::R8G8B8, TransformFormat::UNORM);
-	init.m_vertex.m_attributes[1].m_offset = sizeof(Vec3);
-	init.m_vertex.m_attributes[2].m_format = PixelFormat(ComponentFormat::R32G32B32, TransformFormat::FLOAT);
-	init.m_vertex.m_attributes[2].m_binding = 1;
-
-	init.m_vertex.m_bindingCount = 2;
-	init.m_vertex.m_bindings[0].m_stride = sizeof(Vert);
-	init.m_vertex.m_bindings[1].m_stride = sizeof(Vec3);
-
-	PipelinePtr ppline = gr->newInstance<Pipeline>(init);
+	// Prog
+	ShaderProgramPtr prog = createProgram(VERT_INP_SRC, FRAG_INP_SRC, *gr);
 
 	// FB
 	FramebufferPtr fb = createDefaultFb(*gr);
@@ -594,14 +536,20 @@ ANKI_TEST(Gr, DrawWithVertex)
 		gr->beginFrame();
 
 		CommandBufferInitInfo cinit;
+		cinit.m_flags = CommandBufferFlag::GRAPHICS_WORK;
 		CommandBufferPtr cmdb = gr->newInstance<CommandBuffer>(cinit);
 
+		cmdb->bindVertexBuffer(0, b, 0, sizeof(Vert));
+		cmdb->bindVertexBuffer(1, c, 0, sizeof(Vec3));
+		cmdb->setVertexAttribute(0, 0, PixelFormat(ComponentFormat::R32G32B32, TransformFormat::FLOAT), 0);
+		cmdb->setVertexAttribute(1, 0, PixelFormat(ComponentFormat::R8G8B8, TransformFormat::UNORM), sizeof(Vec3));
+		cmdb->setVertexAttribute(2, 1, PixelFormat(ComponentFormat::R32G32B32, TransformFormat::FLOAT), 0);
+
 		cmdb->setViewport(0, 0, WIDTH, HEIGHT);
 		cmdb->setPolygonOffset(0.0, 0.0);
-		cmdb->bindPipeline(ppline);
+		cmdb->bindShaderProgram(prog);
 		cmdb->beginRenderPass(fb);
-		cmdb->bindResourceGroup(rc, 0, nullptr);
-		cmdb->drawArrays(3);
+		cmdb->drawArrays(PrimitiveTopology::TRIANGLES, 3);
 		cmdb->endRenderPass();
 		cmdb->flush();
 
@@ -756,7 +704,6 @@ ANKI_TEST(Gr, DrawWithTexture)
 		a, TextureUsageBit::SAMPLED_FRAGMENT, TextureUsageBit::UPLOAD, TextureSurfaceInfo(1, 0, 0, 0));
 
 	cmdb->setTextureSurfaceBarrier(b, TextureUsageBit::NONE, TextureUsageBit::UPLOAD, TextureSurfaceInfo(0, 0, 0, 0));
-	;
 
 	cmdb->uploadTextureSurfaceCopyData(a, TextureSurfaceInfo(0, 0, 0, 0), &mip0[0], sizeof(mip0));
 
@@ -786,17 +733,9 @@ ANKI_TEST(Gr, DrawWithTexture)
 	cmdb->flush();
 
 	//
-	// Create resource group
-	//
-	ResourceGroupInitInfo rcinit;
-	rcinit.m_textures[0].m_texture = a;
-	rcinit.m_textures[1].m_texture = b;
-	ResourceGroupPtr rc = gr->newInstance<ResourceGroup>(rcinit);
-
-	//
-	// Create ppline
+	// Create prog
 	//
-	PipelinePtr ppline = createSimplePpline(VERT_QUAD_SRC, FRAG_TEX_SRC, *gr);
+	ShaderProgramPtr prog = createProgram(VERT_QUAD_SRC, FRAG_TEX_SRC, *gr);
 
 	//
 	// Create FB
@@ -816,14 +755,15 @@ ANKI_TEST(Gr, DrawWithTexture)
 		gr->beginFrame();
 
 		CommandBufferInitInfo cinit;
+		cinit.m_flags = CommandBufferFlag::GRAPHICS_WORK;
 		CommandBufferPtr cmdb = gr->newInstance<CommandBuffer>(cinit);
 
 		cmdb->setViewport(0, 0, WIDTH, HEIGHT);
-		cmdb->setPolygonOffset(0.0, 0.0);
-		cmdb->bindPipeline(ppline);
+		cmdb->bindShaderProgram(prog);
 		cmdb->beginRenderPass(fb);
-		cmdb->bindResourceGroup(rc, 0, nullptr);
-		cmdb->drawArrays(6);
+		cmdb->bindTexture(0, 0, a);
+		cmdb->bindTexture(0, 1, b);
+		cmdb->drawArrays(PrimitiveTopology::TRIANGLES, 6);
 		cmdb->endRenderPass();
 		cmdb->flush();
 
@@ -840,8 +780,12 @@ ANKI_TEST(Gr, DrawWithTexture)
 	COMMON_END()
 }
 
-static void drawOffscreenDrawcalls(
-	GrManager& gr, PipelinePtr ppline, ResourceGroupPtr rc0, CommandBufferPtr cmdb, U viewPortSize)
+static void drawOffscreenDrawcalls(GrManager& gr,
+	ShaderProgramPtr prog,
+	CommandBufferPtr cmdb,
+	U viewPortSize,
+	BufferPtr indexBuff,
+	BufferPtr vertBuff)
 {
 	static F32 ang = -2.5f;
 	ang += toRad(2.5f);
@@ -851,38 +795,41 @@ static void drawOffscreenDrawcalls(
 
 	Mat4 projMat = Mat4::calculatePerspectiveProjectionMatrix(toRad(60.0), toRad(60.0), 0.1f, 100.0f);
 
-	TransientMemoryInfo transientInfo;
+	TransientMemoryToken token0, token1;
 
 	Mat4 modelMat(Vec4(-0.5, -0.5, 0.0, 1.0), Mat3(Euler(ang, ang / 2.0f, ang / 3.0f)), 1.0f);
 
-	Mat4* mvp = static_cast<Mat4*>(
-		gr.allocateFrameTransientMemory(sizeof(*mvp), BufferUsageBit::UNIFORM_ALL, transientInfo.m_uniformBuffers[0]));
+	Mat4* mvp = static_cast<Mat4*>(gr.allocateFrameTransientMemory(sizeof(*mvp), BufferUsageBit::UNIFORM_ALL, token0));
 	*mvp = projMat * viewMat * modelMat;
 
-	Vec4* color = static_cast<Vec4*>(gr.allocateFrameTransientMemory(
-		sizeof(*color) * 2, BufferUsageBit::UNIFORM_ALL, transientInfo.m_uniformBuffers[1]));
+	Vec4* color =
+		static_cast<Vec4*>(gr.allocateFrameTransientMemory(sizeof(*color) * 2, BufferUsageBit::UNIFORM_ALL, token1));
 	*color++ = Vec4(1.0, 0.0, 0.0, 0.0);
 	*color = Vec4(0.0, 1.0, 0.0, 0.0);
 
-	cmdb->bindPipeline(ppline);
+	cmdb->bindVertexBuffer(0, vertBuff, 0, sizeof(Vec3));
+	cmdb->setVertexAttribute(0, 0, PixelFormat(ComponentFormat::R32G32B32, TransformFormat::FLOAT), 0);
+	cmdb->bindShaderProgram(prog);
+	cmdb->bindIndexBuffer(indexBuff, 0, IndexType::U16);
 	cmdb->setViewport(0, 0, viewPortSize, viewPortSize);
-	cmdb->bindResourceGroup(rc0, 0, &transientInfo);
-	cmdb->drawElements(6 * 2 * 3);
+	cmdb->bindUniformBuffer(0, 0, token0);
+	cmdb->bindUniformBuffer(0, 1, token1);
+	cmdb->drawElements(PrimitiveTopology::TRIANGLES, 6 * 2 * 3);
 
 	// 2nd draw
 	modelMat = Mat4(Vec4(0.5, 0.5, 0.0, 1.0), Mat3(Euler(ang * 2.0, ang, ang / 3.0f * 2.0)), 1.0f);
 
-	mvp = static_cast<Mat4*>(
-		gr.allocateFrameTransientMemory(sizeof(*mvp), BufferUsageBit::UNIFORM_ALL, transientInfo.m_uniformBuffers[0]));
+	mvp = static_cast<Mat4*>(gr.allocateFrameTransientMemory(sizeof(*mvp), BufferUsageBit::UNIFORM_ALL, token0));
 	*mvp = projMat * viewMat * modelMat;
 
-	color = static_cast<Vec4*>(gr.allocateFrameTransientMemory(
-		sizeof(*color) * 2, BufferUsageBit::UNIFORM_ALL, transientInfo.m_uniformBuffers[1]));
+	color =
+		static_cast<Vec4*>(gr.allocateFrameTransientMemory(sizeof(*color) * 2, BufferUsageBit::UNIFORM_ALL, token1));
 	*color++ = Vec4(0.0, 0.0, 1.0, 0.0);
 	*color = Vec4(0.0, 1.0, 1.0, 0.0);
 
-	cmdb->bindResourceGroup(rc0, 0, &transientInfo);
-	cmdb->drawElements(6 * 2 * 3);
+	cmdb->bindUniformBuffer(0, 0, token0);
+	cmdb->bindUniformBuffer(0, 1, token1);
+	cmdb->drawElements(PrimitiveTopology::TRIANGLES, 6 * 2 * 3);
 }
 
 static void drawOffscreen(GrManager& gr, Bool useSecondLevel)
@@ -923,6 +870,7 @@ static void drawOffscreen(GrManager& gr, Bool useSecondLevel)
 	fbinit.m_colorAttachments[1].m_texture = col1;
 	fbinit.m_colorAttachments[1].m_clearValue.m_colorf = {0.0, 0.1, 0.0, 0.0};
 	fbinit.m_depthStencilAttachment.m_texture = dp;
+	fbinit.m_depthStencilAttachment.m_aspect = DepthStencilAspectMask::DEPTH;
 	fbinit.m_depthStencilAttachment.m_clearValue.m_depthStencil.m_depth = 1.0;
 
 	FramebufferPtr fb = gr.newInstance<Framebuffer>(fbinit);
@@ -933,51 +881,16 @@ static void drawOffscreen(GrManager& gr, Bool useSecondLevel)
 	FramebufferPtr dfb = createDefaultFb(gr);
 
 	//
-	// Create buffs and rc groups
+	// Create buffs
 	//
 	BufferPtr verts, indices;
 	createCube(gr, verts, indices);
 
-	ResourceGroupInitInfo rcinit;
-	rcinit.m_uniformBuffers[0].m_uploadedMemory = true;
-	rcinit.m_uniformBuffers[0].m_usage = BufferUsageBit::UNIFORM_FRAGMENT | BufferUsageBit::UNIFORM_VERTEX;
-	rcinit.m_uniformBuffers[1].m_uploadedMemory = true;
-	rcinit.m_uniformBuffers[1].m_usage = BufferUsageBit::UNIFORM_FRAGMENT | BufferUsageBit::UNIFORM_VERTEX;
-	rcinit.m_vertexBuffers[0].m_buffer = verts;
-	rcinit.m_indexBuffer.m_buffer = indices;
-	rcinit.m_indexSize = 2;
-
-	ResourceGroupPtr rc0 = gr.newInstance<ResourceGroup>(rcinit);
-
-	rcinit = {};
-	rcinit.m_textures[0].m_texture = col0;
-	rcinit.m_textures[1].m_texture = col1;
-	ResourceGroupPtr rc1 = gr.newInstance<ResourceGroup>(rcinit);
-
 	//
-	// Create pplines
+	// Create progs
 	//
-	ShaderPtr vert = gr.newInstance<Shader>(ShaderType::VERTEX, VERT_MRT_SRC);
-	ShaderPtr frag = gr.newInstance<Shader>(ShaderType::FRAGMENT, FRAG_MRT_SRC);
-
-	PipelineInitInfo pinit;
-	pinit.m_shaders[ShaderType::VERTEX] = vert;
-	pinit.m_shaders[ShaderType::FRAGMENT] = frag;
-	pinit.m_color.m_attachmentCount = 2;
-	pinit.m_color.m_attachments[0].m_format = COL_FORMAT;
-	pinit.m_color.m_attachments[1].m_format = COL_FORMAT;
-	pinit.m_depthStencil.m_depthWriteEnabled = true;
-	pinit.m_depthStencil.m_format = DS_FORMAT;
-
-	pinit.m_vertex.m_attributeCount = 1;
-	pinit.m_vertex.m_attributes[0].m_format = PixelFormat(ComponentFormat::R32G32B32, TransformFormat::FLOAT);
-
-	pinit.m_vertex.m_bindingCount = 1;
-	pinit.m_vertex.m_bindings[0].m_stride = sizeof(Vec3);
-
-	PipelinePtr ppline = gr.newInstance<Pipeline>(pinit);
-
-	PipelinePtr pplineResolve = createSimplePpline(VERT_QUAD_SRC, FRAG_MRT2_SRC, gr);
+	ShaderProgramPtr prog = createProgram(VERT_MRT_SRC, FRAG_MRT_SRC, gr);
+	ShaderProgramPtr resolveProg = createProgram(VERT_QUAD_SRC, FRAG_MRT2_SRC, gr);
 
 	//
 	// Draw
@@ -991,6 +904,7 @@ static void drawOffscreen(GrManager& gr, Bool useSecondLevel)
 		gr.beginFrame();
 
 		CommandBufferInitInfo cinit;
+		cinit.m_flags = CommandBufferFlag::GRAPHICS_WORK;
 		CommandBufferPtr cmdb = gr.newInstance<CommandBuffer>(cinit);
 
 		cmdb->setPolygonOffset(0.0, 0.0);
@@ -1007,18 +921,16 @@ static void drawOffscreen(GrManager& gr, Bool useSecondLevel)
 
 		if(!useSecondLevel)
 		{
-			drawOffscreenDrawcalls(gr, ppline, rc0, cmdb, TEX_SIZE);
+			drawOffscreenDrawcalls(gr, prog, cmdb, TEX_SIZE, indices, verts);
 		}
 		else
 		{
 			CommandBufferInitInfo cinit;
-			cinit.m_flags = CommandBufferFlag::SECOND_LEVEL;
+			cinit.m_flags = CommandBufferFlag::SECOND_LEVEL | CommandBufferFlag::GRAPHICS_WORK;
 			cinit.m_framebuffer = fb;
 			CommandBufferPtr cmdb2 = gr.newInstance<CommandBuffer>(cinit);
 
-			cmdb2->setPolygonOffset(0.0, 0.0);
-
-			drawOffscreenDrawcalls(gr, ppline, rc0, cmdb2, TEX_SIZE);
+			drawOffscreenDrawcalls(gr, prog, cmdb2, TEX_SIZE, indices, verts);
 
 			cmdb->pushSecondLevelCommandBuffer(cmdb2);
 		}
@@ -1040,10 +952,11 @@ static void drawOffscreen(GrManager& gr, Bool useSecondLevel)
 
 		// Draw quad
 		cmdb->beginRenderPass(dfb);
-		cmdb->bindPipeline(pplineResolve);
+		cmdb->bindShaderProgram(resolveProg);
 		cmdb->setViewport(0, 0, WIDTH, HEIGHT);
-		cmdb->bindResourceGroup(rc1, 0, nullptr);
-		cmdb->drawArrays(6);
+		cmdb->bindTexture(0, 0, col0);
+		cmdb->bindTexture(0, 1, col1);
+		cmdb->drawArrays(PrimitiveTopology::TRIANGLES, 6);
 		cmdb->endRenderPass();
 
 		cmdb->flush();
@@ -1092,31 +1005,12 @@ ANKI_TEST(Gr, ImageLoadStore)
 
 	TexturePtr tex = gr->newInstance<Texture>(init);
 
-	// Ppline
-	PipelinePtr ppline = createSimplePpline(VERT_QUAD_SRC, FRAG_SIMPLE_TEX_SRC, *gr);
+	// Prog
+	ShaderProgramPtr prog = createProgram(VERT_QUAD_SRC, FRAG_SIMPLE_TEX_SRC, *gr);
 
-	// Create shader & compute ppline
+	// Create shader & compute prog
 	ShaderPtr shader = gr->newInstance<Shader>(ShaderType::COMPUTE, COMP_WRITE_IMAGE_SRC);
-
-	PipelineInitInfo ppinit;
-	ppinit.m_shaders[ShaderType::COMPUTE] = shader;
-	PipelinePtr compPpline = gr->newInstance<Pipeline>(ppinit);
-
-	// RC group
-	ResourceGroupInitInfo rcinit;
-	rcinit.m_textures[0].m_texture = tex;
-	ResourceGroupPtr rc0 = gr->newInstance<ResourceGroup>(rcinit);
-
-	rcinit = ResourceGroupInitInfo();
-	rcinit.m_images[0].m_texture = tex;
-	rcinit.m_images[0].m_usage = TextureUsageBit::IMAGE_COMPUTE_WRITE;
-	rcinit.m_images[0].m_level = 1;
-	ResourceGroupPtr rc1 = gr->newInstance<ResourceGroup>(rcinit);
-
-	rcinit = ResourceGroupInitInfo();
-	rcinit.m_storageBuffers[0].m_uploadedMemory = true;
-	rcinit.m_storageBuffers[0].m_usage = BufferUsageBit::STORAGE_COMPUTE_READ;
-	ResourceGroupPtr rc2 = gr->newInstance<ResourceGroup>(rcinit);
+	ShaderProgramPtr compProg = gr->newInstance<ShaderProgram>(shader);
 
 	// FB
 	FramebufferPtr dfb = createDefaultFb(*gr);
@@ -1153,19 +1047,20 @@ ANKI_TEST(Gr, ImageLoadStore)
 		gr->beginFrame();
 
 		CommandBufferInitInfo cinit;
+		cinit.m_flags = CommandBufferFlag::GRAPHICS_WORK | CommandBufferFlag::COMPUTE_WORK;
 		CommandBufferPtr cmdb = gr->newInstance<CommandBuffer>(cinit);
 
 		// Write image
-		TransientMemoryInfo trans;
-		Vec4* col = static_cast<Vec4*>(
-			gr->allocateFrameTransientMemory(sizeof(*col), BufferUsageBit::STORAGE_ALL, trans.m_storageBuffers[0]));
+		TransientMemoryToken token;
+		Vec4* col =
+			static_cast<Vec4*>(gr->allocateFrameTransientMemory(sizeof(*col), BufferUsageBit::STORAGE_ALL, token));
 		*col = Vec4(iterations / F32(ITERATION_COUNT));
 
 		cmdb->setTextureSurfaceBarrier(
 			tex, TextureUsageBit::NONE, TextureUsageBit::IMAGE_COMPUTE_WRITE, TextureSurfaceInfo(1, 0, 0, 0));
-		cmdb->bindPipeline(compPpline);
-		cmdb->bindResourceGroup(rc1, 0, nullptr);
-		cmdb->bindResourceGroup(rc2, 1, &trans);
+		cmdb->bindShaderProgram(compProg);
+		cmdb->bindImage(0, 0, tex, 1);
+		cmdb->bindStorageBuffer(1, 0, token);
 		cmdb->dispatchCompute(WIDTH / 2, HEIGHT / 2, 1);
 		cmdb->setTextureSurfaceBarrier(tex,
 			TextureUsageBit::IMAGE_COMPUTE_WRITE,
@@ -1173,13 +1068,12 @@ ANKI_TEST(Gr, ImageLoadStore)
 			TextureSurfaceInfo(1, 0, 0, 0));
 
 		// Present image
-		cmdb->setPolygonOffset(0.0, 0.0);
 		cmdb->setViewport(0, 0, WIDTH, HEIGHT);
 
-		cmdb->bindPipeline(ppline);
+		cmdb->bindShaderProgram(prog);
 		cmdb->beginRenderPass(dfb);
-		cmdb->bindResourceGroup(rc0, 0, nullptr);
-		cmdb->drawArrays(6);
+		cmdb->bindTexture(0, 0, tex);
+		cmdb->drawArrays(PrimitiveTopology::TRIANGLES, 6);
 		cmdb->endRenderPass();
 
 		cmdb->flush();
@@ -1282,14 +1176,7 @@ ANKI_TEST(Gr, 3DTextures)
 	//
 	// Rest
 	//
-	PipelinePtr ppline = createSimplePpline(VERT_QUAD_SRC, FRAG_TEX3D_SRC, *gr);
-
-	ResourceGroupInitInfo rcinit;
-	rcinit.m_uniformBuffers[0].m_uploadedMemory = true;
-	rcinit.m_uniformBuffers[0].m_usage = BufferUsageBit::UNIFORM_FRAGMENT;
-	rcinit.m_textures[0].m_texture = a;
-	rcinit.m_textures[0].m_usage = TextureUsageBit::SAMPLED_FRAGMENT;
-	ResourceGroupPtr rc = gr->newInstance<ResourceGroup>(rcinit);
+	ShaderProgramPtr prog = createProgram(VERT_QUAD_SRC, FRAG_TEX3D_SRC, *gr);
 
 	FramebufferPtr dfb = createDefaultFb(*gr);
 
@@ -1312,23 +1199,24 @@ ANKI_TEST(Gr, 3DTextures)
 		gr->beginFrame();
 
 		CommandBufferInitInfo cinit;
+		cinit.m_flags = CommandBufferFlag::GRAPHICS_WORK;
 		CommandBufferPtr cmdb = gr->newInstance<CommandBuffer>(cinit);
 
-		cmdb->setPolygonOffset(0.0, 0.0);
 		cmdb->setViewport(0, 0, WIDTH, HEIGHT);
 		cmdb->beginRenderPass(dfb);
 
-		cmdb->bindPipeline(ppline);
+		cmdb->bindShaderProgram(prog);
 
-		TransientMemoryInfo transientInfo;
-		Vec4* uv = static_cast<Vec4*>(gr->allocateFrameTransientMemory(
-			sizeof(Vec4), BufferUsageBit::UNIFORM_ALL, transientInfo.m_uniformBuffers[0]));
+		TransientMemoryToken token;
+		Vec4* uv =
+			static_cast<Vec4*>(gr->allocateFrameTransientMemory(sizeof(Vec4), BufferUsageBit::UNIFORM_ALL, token));
 
 		U idx = (F32(ITERATION_COUNT - iterations - 1) / ITERATION_COUNT) * TEX_COORDS_LOD.getSize();
 		*uv = TEX_COORDS_LOD[idx];
 
-		cmdb->bindResourceGroup(rc, 0, &transientInfo);
-		cmdb->drawArrays(6);
+		cmdb->bindUniformBuffer(0, 0, token);
+		cmdb->bindTexture(0, 0, a);
+		cmdb->drawArrays(PrimitiveTopology::TRIANGLES, 6);
 
 		cmdb->endRenderPass();