浏览代码

GR: Move the GL backend to the new interface

Panagiotis Christopoulos Charitos 9 年之前
父节点
当前提交
320adc8d92

+ 1 - 2
src/anki/Gr.h

@@ -9,11 +9,10 @@
 #include <anki/gr/Texture.h>
 #include <anki/gr/Sampler.h>
 #include <anki/gr/Shader.h>
+#include <anki/gr/ShaderProgram.h>
 #include <anki/gr/Framebuffer.h>
-#include <anki/gr/Pipeline.h>
 #include <anki/gr/CommandBuffer.h>
 #include <anki/gr/OcclusionQuery.h>
-#include <anki/gr/ResourceGroup.h>
 #include <anki/gr/GrManager.h>
 #include <anki/gr/GrObjectCache.h>
 

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

@@ -18,4 +18,4 @@ else()
 endif()
 
 add_library(ankigr ${ANKI_GR_SOURCES} ${ANKI_GR_BACKEND_SOURCES})
-target_link_libraries(ankigr ankiutil ankicore ${EXTRA_LIBS})
+target_link_libraries(ankigr ankiutil ${EXTRA_LIBS})

+ 9 - 10
src/anki/gr/CommandBuffer.h

@@ -242,28 +242,27 @@ public:
 	/// Bind a program.
 	void bindShaderProgram(ShaderProgramPtr prog);
 
-	/// Bind pipeline.
-	void bindPipeline(PipelinePtr ppline);
-
 	/// Begin renderpass.
 	void beginRenderPass(FramebufferPtr fb);
 
 	/// End renderpass.
 	void endRenderPass();
-
-	/// Bind resources.
-	void bindResourceGroup(ResourceGroupPtr rc, U slot, const TransientMemoryInfo* dynInfo);
 	/// @}
 
 	/// @name Jobs
 	/// @{
-	void drawElements(U32 count, U32 instanceCount = 1, U32 firstIndex = 0, U32 baseVertex = 0, U32 baseInstance = 0);
+	void drawElements(PrimitiveTopology topology,
+		U32 count,
+		U32 instanceCount = 1,
+		U32 firstIndex = 0,
+		U32 baseVertex = 0,
+		U32 baseInstance = 0);
 
-	void drawArrays(U32 count, U32 instanceCount = 1, U32 first = 0, U32 baseInstance = 0);
+	void drawArrays(PrimitiveTopology topology, U32 count, U32 instanceCount = 1, U32 first = 0, U32 baseInstance = 0);
 
-	void drawElementsIndirect(U32 drawCount, PtrSize offset, BufferPtr indirectBuff);
+	void drawElementsIndirect(PrimitiveTopology topology, U32 drawCount, PtrSize offset, BufferPtr indirectBuff);
 
-	void drawArraysIndirect(U32 drawCount, PtrSize offset, BufferPtr indirectBuff);
+	void drawArraysIndirect(PrimitiveTopology topology, U32 drawCount, PtrSize offset, BufferPtr indirectBuff);
 
 	void dispatchCompute(U32 groupCountX, U32 groupCountY, U32 groupCountZ);
 

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

@@ -22,9 +22,7 @@ class GrManagerImpl;
 class TextureInitInfo;
 class SamplerInitInfo;
 class GrManagerInitInfo;
-class PipelineInitInfo;
 class FramebufferInitInfo;
-class ResourceGroupInitInfo;
 
 /// @addtogroup graphics
 /// @{
@@ -43,10 +41,8 @@ ANKI_GR_CLASS(Texture)
 ANKI_GR_CLASS(Sampler)
 ANKI_GR_CLASS(CommandBuffer)
 ANKI_GR_CLASS(Shader)
-ANKI_GR_CLASS(Pipeline)
 ANKI_GR_CLASS(Framebuffer)
 ANKI_GR_CLASS(OcclusionQuery)
-ANKI_GR_CLASS(ResourceGroup)
 ANKI_GR_CLASS(ShaderProgram)
 
 #undef ANKI_GR_CLASS
@@ -194,15 +190,6 @@ anki_internal:
 	}
 };
 
-/// Struct to help update the offset of the dynamic buffers.
-class TransientMemoryInfo
-{
-public:
-	Array<TransientMemoryToken, MAX_UNIFORM_BUFFER_BINDINGS> m_uniformBuffers;
-	Array<TransientMemoryToken, MAX_STORAGE_BUFFER_BINDINGS> m_storageBuffers;
-	Array<TransientMemoryToken, MAX_VERTEX_ATTRIBUTES> m_vertexBuffers;
-};
-
 /// Compute max number of mipmaps for a 2D texture.
 inline U computeMaxMipmapCount2d(U w, U h, U minSizeOfLastMip = 1)
 {

+ 0 - 2
src/anki/gr/GrObject.h

@@ -22,8 +22,6 @@ enum GrObjectType : U16
 	COMMAND_BUFFER,
 	FRAMEBUFFER,
 	OCCLUSION_QUERY,
-	PIPELINE,
-	RESOURCE_GROUP,
 	SAMPLER,
 	SHADER,
 	TEXTURE,

+ 0 - 268
src/anki/gr/Pipeline.h

@@ -1,268 +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/gr/GrObject.h>
-#include <anki/gr/Shader.h>
-#include <anki/util/Hash.h>
-
-namespace anki
-{
-
-/// @addtogroup graphics
-/// @{
-
-class VertexBinding
-{
-public:
-	PtrSize m_stride; ///< Vertex stride.
-	VertexStepRate m_stepRate = VertexStepRate::VERTEX;
-
-	Bool operator==(const VertexBinding& b) const
-	{
-		return m_stride == b.m_stride && m_stepRate == b.m_stepRate;
-	}
-
-	Bool operator!=(const VertexBinding& b) const
-	{
-		return !(*this == b);
-	}
-};
-
-class VertexAttributeBinding
-{
-public:
-	PixelFormat m_format;
-	PtrSize m_offset = 0;
-	U8 m_binding = 0;
-
-	Bool operator==(const VertexAttributeBinding& b) const
-	{
-		return m_format == b.m_format && m_offset == b.m_offset && m_binding == b.m_binding;
-	}
-
-	Bool operator!=(const VertexAttributeBinding& b) const
-	{
-		return !(*this == b);
-	}
-};
-
-class VertexStateInfo
-{
-public:
-	U8 m_bindingCount = 0;
-	Array<VertexBinding, MAX_VERTEX_ATTRIBUTES> m_bindings;
-	U8 m_attributeCount = 0;
-	Array<VertexAttributeBinding, MAX_VERTEX_ATTRIBUTES> m_attributes;
-
-	Bool operator==(const VertexStateInfo& b) const
-	{
-		if(m_bindingCount != b.m_bindingCount || m_attributeCount != b.m_attributeCount)
-		{
-			return false;
-		}
-
-		for(U i = 0; i < m_bindingCount; ++i)
-		{
-			if(m_bindings[i] != b.m_bindings[i])
-			{
-				return false;
-			}
-		}
-
-		for(U i = 0; i < m_attributeCount; ++i)
-		{
-			if(m_attributes[i] != b.m_attributes[i])
-			{
-				return false;
-			}
-		}
-
-		return true;
-	}
-
-	Bool operator!=(const VertexStateInfo& b) const
-	{
-		return !(*this == b);
-	}
-};
-
-class InputAssemblerStateInfo
-{
-public:
-	PrimitiveTopology m_topology = PrimitiveTopology::TRIANGLES;
-	Bool8 m_primitiveRestartEnabled = false;
-
-	Bool operator==(const InputAssemblerStateInfo& b) const
-	{
-		return m_topology == b.m_topology && m_primitiveRestartEnabled == b.m_primitiveRestartEnabled;
-	}
-
-	Bool operator!=(const InputAssemblerStateInfo& b) const
-	{
-		return !(*this == b);
-	}
-};
-
-class TessellationStateInfo
-{
-public:
-	U32 m_patchControlPointCount = 3;
-};
-
-class ViewportStateInfo
-{
-public:
-	Bool8 m_scissorEnabled = false;
-};
-
-class RasterizerStateInfo
-{
-public:
-	FillMode m_fillMode = FillMode::SOLID;
-	FaceSelectionMask m_cullMode = FaceSelectionMask::BACK;
-};
-
-class StencilStateInfo
-{
-public:
-	StencilOperation m_stencilFailOperation = StencilOperation::KEEP;
-	StencilOperation m_stencilPassDepthFailOperation = StencilOperation::KEEP;
-	StencilOperation m_stencilPassDepthPassOperation = StencilOperation::KEEP;
-	CompareOperation m_compareFunction = CompareOperation::ALWAYS;
-};
-
-/// Depth stencil state.
-/// To disable depth test set m_depthWriteEnabled to false and m_depthCompareFunction to always.
-/// To disable stencil test leave m_stencilFront and m_stencilBack as is.
-class DepthStencilStateInfo
-{
-public:
-	// Depth
-	Bool8 m_depthWriteEnabled = true;
-	CompareOperation m_depthCompareFunction = CompareOperation::LESS;
-
-	// Stencil
-	StencilStateInfo m_stencilFront;
-	StencilStateInfo m_stencilBack;
-
-	// Common
-	PixelFormat m_format;
-
-	Bool isInUse() const
-	{
-		return m_format.m_components != ComponentFormat::NONE;
-	}
-};
-
-class ColorAttachmentStateInfo
-{
-public:
-	PixelFormat m_format;
-
-	BlendMethod m_srcBlendMethod = BlendMethod::ONE;
-	BlendMethod m_dstBlendMethod = BlendMethod::ZERO;
-	BlendFunction m_blendFunction = BlendFunction::ADD;
-	ColorBit m_channelWriteMask = ColorBit::ALL;
-};
-
-class ColorStateInfo
-{
-public:
-	Bool8 m_alphaToCoverageEnabled = false;
-	U8 m_attachmentCount = 0;
-	Array<ColorAttachmentStateInfo, MAX_COLOR_ATTACHMENTS> m_attachments;
-};
-
-enum class PipelineSubStateBit : U16
-{
-	NONE = 0,
-	VERTEX = 1 << 0,
-	INPUT_ASSEMBLER = 1 << 1,
-	TESSELLATION = 1 << 2,
-	VIEWPORT = 1 << 3,
-	RASTERIZER = 1 << 4,
-	DEPTH_STENCIL = 1 << 5,
-	COLOR = 1 << 6,
-	SHADERS = 1 << 7,
-	ALL = VERTEX | INPUT_ASSEMBLER | TESSELLATION | VIEWPORT | RASTERIZER | DEPTH_STENCIL | COLOR | SHADERS
-};
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(PipelineSubStateBit, inline)
-
-/// Only the state part of PipelineInitInfo. It's separate for easy hashing.
-class PipelineInitInfoState
-{
-public:
-	PipelineInitInfoState()
-	{
-		// Do a special construction. The state will be hashed and the padding may contain garbage. With this trick
-		// zero the padding
-		memset(this, 0, sizeof(*this));
-
-#define ANKI_CONSTRUCT_AND_ZERO_PADDING(memb_) new(&memb_) decltype(memb_)()
-
-		ANKI_CONSTRUCT_AND_ZERO_PADDING(m_vertex);
-		ANKI_CONSTRUCT_AND_ZERO_PADDING(m_inputAssembler);
-		ANKI_CONSTRUCT_AND_ZERO_PADDING(m_tessellation);
-		ANKI_CONSTRUCT_AND_ZERO_PADDING(m_viewport);
-		ANKI_CONSTRUCT_AND_ZERO_PADDING(m_rasterizer);
-		ANKI_CONSTRUCT_AND_ZERO_PADDING(m_depthStencil);
-		ANKI_CONSTRUCT_AND_ZERO_PADDING(m_color);
-
-#undef ANKI_CONSTRUCT_AND_ZERO_PADDING
-	}
-
-	VertexStateInfo m_vertex;
-	InputAssemblerStateInfo m_inputAssembler;
-	TessellationStateInfo m_tessellation;
-	ViewportStateInfo m_viewport;
-	RasterizerStateInfo m_rasterizer;
-	DepthStencilStateInfo m_depthStencil;
-	ColorStateInfo m_color;
-};
-
-/// Pipeline initializer.
-class PipelineInitInfo : public PipelineInitInfoState
-{
-public:
-	Array<ShaderPtr, U(ShaderType::COUNT)> m_shaders;
-
-	U64 computeHash() const
-	{
-		U64 h = anki::computeHash(static_cast<const PipelineInitInfoState*>(this), sizeof(PipelineInitInfoState));
-
-		Array<U64, U(ShaderType::COUNT)> uuids;
-		for(U i = 0; i < m_shaders.getSize(); ++i)
-		{
-			uuids[i] = (m_shaders[i].isCreated()) ? m_shaders[i]->getUuid() : 0;
-		}
-
-		return appendHash(&uuids[0], sizeof(uuids), h);
-	}
-};
-
-/// Graphics and compute pipeline. Contains the static state.
-class Pipeline : public GrObject
-{
-	ANKI_GR_OBJECT
-
-anki_internal:
-	UniquePtr<PipelineImpl> m_impl;
-
-	static const GrObjectType CLASS_TYPE = GrObjectType::PIPELINE;
-
-	/// Construct.
-	Pipeline(GrManager* manager, U64 hash, GrObjectCache* cache);
-
-	/// Destroy.
-	~Pipeline();
-
-	/// Create.
-	void init(const PipelineInitInfo& init);
-};
-/// @}
-
-} // end namespace anki

+ 0 - 90
src/anki/gr/ResourceGroup.h

@@ -1,90 +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/gr/GrObject.h>
-#include <anki/gr/Texture.h>
-#include <anki/gr/Sampler.h>
-#include <anki/gr/Buffer.h>
-
-namespace anki
-{
-
-/// @addtogroup graphics
-/// @{
-
-/// Texture/Sampler Binding.
-class TextureBinding
-{
-public:
-	TexturePtr m_texture;
-	SamplerPtr m_sampler; ///< Use it to override texture's sampler.
-	TextureUsageBit m_usage = TextureUsageBit::SAMPLED_FRAGMENT;
-	DepthStencilAspectMask m_aspect = DepthStencilAspectMask::DEPTH; ///< Relevant only for depth stencil textures.
-};
-
-/// Buffer binding info.
-class BufferBinding
-{
-public:
-	BufferPtr m_buffer;
-	PtrSize m_offset = 0;
-	PtrSize m_range = 0; ///< If zero it means the whole buffer.
-	Bool m_uploadedMemory = false;
-	BufferUsageBit m_usage = BufferUsageBit::NONE;
-};
-
-/// Image binding info.
-class ImageBinding
-{
-public:
-	TexturePtr m_texture;
-	U8 m_level = 0;
-	TextureUsageBit m_usage = TextureUsageBit::IMAGE_COMPUTE_READ_WRITE;
-};
-
-/// Resource group initializer.
-class ResourceGroupInitInfo
-{
-public:
-	Array<TextureBinding, MAX_TEXTURE_BINDINGS> m_textures;
-	Array<BufferBinding, MAX_UNIFORM_BUFFER_BINDINGS> m_uniformBuffers;
-	Array<BufferBinding, MAX_STORAGE_BUFFER_BINDINGS> m_storageBuffers;
-	Array<ImageBinding, MAX_IMAGE_BINDINGS> m_images;
-	Array<BufferBinding, MAX_VERTEX_ATTRIBUTES> m_vertexBuffers;
-	BufferBinding m_indexBuffer;
-	I8 m_indexSize = -1; ///< Index size in bytes. 2 or 4
-
-	U64 computeHash() const;
-
-private:
-	void appendBufferBinding(const BufferBinding& b, U64 arr[], U& count) const;
-};
-
-/// Resource group.
-class ResourceGroup : public GrObject
-{
-	ANKI_GR_OBJECT
-
-anki_internal:
-	UniquePtr<ResourceGroupImpl> m_impl;
-
-	static const GrObjectType CLASS_TYPE = GrObjectType::RESOURCE_GROUP;
-
-	/// Construct.
-	ResourceGroup(GrManager* manager, U64 hash, GrObjectCache* cache);
-
-	/// Destroy.
-	~ResourceGroup();
-
-	/// Create.
-	void init(const ResourceGroupInitInfo& init);
-};
-/// @}
-
-} // end namespace anki
-
-#include <anki/gr/ResourceGroup.inl.h>

+ 0 - 101
src/anki/gr/ResourceGroup.inl.h

@@ -1,101 +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/gr/ResourceGroup.h>
-
-namespace anki
-{
-
-inline void ResourceGroupInitInfo::appendBufferBinding(const BufferBinding& b, U64 arr[], U& count) const
-{
-	arr[count++] = (b.m_buffer) ? b.m_buffer->getUuid() : 0;
-	arr[count++] = b.m_offset;
-	arr[count++] = b.m_range;
-	arr[count++] = b.m_uploadedMemory;
-	arr[count++] = static_cast<U64>(b.m_usage);
-}
-
-inline U64 ResourceGroupInitInfo::computeHash() const
-{
-	const U TEX_NUMBERS = MAX_TEXTURE_BINDINGS * 4;
-	const U BUFF_NUMBERS = (MAX_UNIFORM_BUFFER_BINDINGS + MAX_STORAGE_BUFFER_BINDINGS + MAX_VERTEX_ATTRIBUTES + 1) * 5;
-	const U IMAGE_NUMBERS = MAX_IMAGE_BINDINGS * 3;
-	const U INDEX_SIZE_NUMBERS = 1;
-	Array<U64, TEX_NUMBERS + BUFF_NUMBERS + IMAGE_NUMBERS + INDEX_SIZE_NUMBERS> numbers;
-	U count = 0;
-
-	for(const auto& tex : m_textures)
-	{
-		if(tex.m_texture)
-		{
-			numbers[count++] = tex.m_texture->getUuid();
-			if(tex.m_sampler)
-			{
-				numbers[count++] = tex.m_sampler->getUuid();
-			}
-			numbers[count++] = static_cast<U64>(tex.m_usage);
-			numbers[count++] = static_cast<U64>(tex.m_aspect);
-		}
-		else
-		{
-			break;
-		}
-	}
-
-	for(const auto& b : m_uniformBuffers)
-	{
-		if(b.m_buffer || b.m_uploadedMemory)
-		{
-			appendBufferBinding(b, &numbers[0], count);
-		}
-		else
-		{
-			break;
-		}
-	}
-	for(const auto& b : m_storageBuffers)
-	{
-		if(b.m_buffer || b.m_uploadedMemory)
-		{
-			appendBufferBinding(b, &numbers[0], count);
-		}
-		else
-		{
-			break;
-		}
-	}
-	for(const auto& b : m_vertexBuffers)
-	{
-		if(b.m_buffer || b.m_uploadedMemory)
-		{
-			appendBufferBinding(b, &numbers[0], count);
-		}
-		else
-		{
-			break;
-		}
-	}
-	appendBufferBinding(m_indexBuffer, &numbers[0], count);
-
-	for(const auto& img : m_images)
-	{
-		if(img.m_texture)
-		{
-			numbers[count++] = img.m_texture->getUuid();
-			numbers[count++] = img.m_level;
-			numbers[count++] = static_cast<U64>(img.m_usage);
-		}
-		else
-		{
-			break;
-		}
-	}
-
-	numbers[count++] = static_cast<U64>(m_indexSize);
-
-	return anki::computeHash(&numbers[0], count * sizeof(U64), 458);
-}
-
-} // end namespace anki

+ 0 - 9
src/anki/gr/common/Misc.cpp

@@ -7,7 +7,6 @@
 #include <anki/gr/Framebuffer.h>
 #include <anki/gr/Texture.h>
 #include <anki/util/StringList.h>
-#include <anki/gr/Pipeline.h>
 
 namespace anki
 {
@@ -234,12 +233,4 @@ PtrSize computeVolumeSize(U width, U height, U depth, const PixelFormat& fmt)
 	}
 }
 
-Bool stencilTestDisabled(const StencilStateInfo& inf)
-{
-	return inf.m_stencilFailOperation == StencilOperation::KEEP
-		&& inf.m_stencilPassDepthFailOperation == StencilOperation::KEEP
-		&& inf.m_stencilPassDepthPassOperation == StencilOperation::KEEP
-		&& inf.m_compareFunction == CompareOperation::ALWAYS;
-}
-
 } // end namespace anki

+ 8 - 4
src/anki/gr/common/Misc.h

@@ -10,9 +10,6 @@
 namespace anki
 {
 
-// Forward
-class StencilStateInfo;
-
 enum class TransientBufferType
 {
 	UNIFORM,
@@ -87,6 +84,13 @@ PtrSize computeSurfaceSize(U width, U height, const PixelFormat& fmt);
 /// Compute the size of the volume.
 PtrSize computeVolumeSize(U width, U height, U depth, const PixelFormat& fmt);
 
-Bool stencilTestDisabled(const StencilStateInfo& inf);
+inline Bool stencilTestDisabled(StencilOperation stencilFail,
+	StencilOperation stencilPassDepthFail,
+	StencilOperation stencilPassDepthPass,
+	CompareOperation compare)
+{
+	return stencilFail == StencilOperation::KEEP && stencilPassDepthFail == StencilOperation::KEEP
+		&& stencilPassDepthPass == StencilOperation::KEEP && compare == CompareOperation::ALWAYS;
+}
 
 } // end namespace anki

+ 203 - 74
src/anki/gr/gl/CommandBuffer.cpp

@@ -11,10 +11,6 @@
 #include <anki/gr/gl/GlState.h>
 #include <anki/gr/gl/TransientMemoryManager.h>
 
-#include <anki/gr/Pipeline.h>
-#include <anki/gr/gl/PipelineImpl.h>
-#include <anki/gr/ResourceGroup.h>
-#include <anki/gr/gl/ResourceGroupImpl.h>
 #include <anki/gr/Framebuffer.h>
 #include <anki/gr/gl/FramebufferImpl.h>
 #include <anki/gr/OcclusionQuery.h>
@@ -230,15 +226,7 @@ void CommandBuffer::setViewport(U16 minx, U16 miny, U16 maxx, U16 maxy)
 
 		Error operator()(GlState& state)
 		{
-			if(state.m_viewport[0] != m_value[0] || state.m_viewport[1] != m_value[1]
-				|| state.m_viewport[2] != m_value[2]
-				|| state.m_viewport[3] != m_value[3])
-			{
-				glViewport(m_value[0], m_value[1], m_value[2], m_value[3]);
-
-				state.m_viewport = m_value;
-			}
-
+			glViewport(m_value[0], m_value[1], m_value[2], m_value[3]);
 			return ErrorCode::NONE;
 		}
 	};
@@ -401,6 +389,21 @@ void CommandBuffer::setStencilWriteMask(FaceSelectionMask face, U32 mask)
 		Error operator()(GlState& state)
 		{
 			glStencilMaskSeparate(m_face, m_mask);
+
+			if(m_face == GL_FRONT)
+			{
+				state.m_stencilWriteMask[0] = m_mask;
+			}
+			else if(m_face == GL_BACK)
+			{
+				state.m_stencilWriteMask[1] = m_mask;
+			}
+			else
+			{
+				ANKI_ASSERT(m_face == GL_FRONT_AND_BACK);
+				state.m_stencilWriteMask[0] = state.m_stencilWriteMask[1] = m_mask;
+			}
+
 			return ErrorCode::NONE;
 		}
 	};
@@ -429,6 +432,7 @@ void CommandBuffer::enableDepthWrite(Bool enable)
 		Error operator()(GlState& state)
 		{
 			glDepthMask(m_enable);
+			state.m_depthWriteMask = m_enable;
 			return ErrorCode::NONE;
 		}
 	};
@@ -478,13 +482,16 @@ void CommandBuffer::setColorChannelWriteMask(U32 attachment, ColorBit mask)
 		{
 		}
 
-		Error operator()(GlState&)
+		Error operator()(GlState& state)
 		{
-			glColorMaski(m_attachment,
-				!!(m_mask & ColorBit::RED),
-				!!(m_mask & ColorBit::GREEN),
-				!!(m_mask & ColorBit::BLUE),
-				!!(m_mask & ColorBit::ALPHA));
+			const Bool r = !!(m_mask & ColorBit::RED);
+			const Bool g = !!(m_mask & ColorBit::GREEN);
+			const Bool b = !!(m_mask & ColorBit::BLUE);
+			const Bool a = !!(m_mask & ColorBit::ALPHA);
+
+			glColorMaski(m_attachment, r, g, b, a);
+
+			state.m_colorWriteMasks[m_attachment] = {{r, g, b, a}};
 
 			return ErrorCode::NONE;
 		}
@@ -767,106 +774,228 @@ void CommandBuffer::bindShaderProgram(ShaderProgramPtr prog)
 	m_impl->m_state.bindShaderProgram(prog, [=]() { m_impl->pushBackNewCommand<Cmd>(prog); });
 }
 
-void CommandBuffer::bindPipeline(PipelinePtr ppline)
+void CommandBuffer::beginRenderPass(FramebufferPtr fb)
 {
-	class BindPipelineCommand final : public GlCommand
+	class BindFramebufferCommand final : public GlCommand
 	{
 	public:
-		PipelinePtr m_ppline;
+		FramebufferPtr m_fb;
 
-		BindPipelineCommand(PipelinePtr& ppline)
-			: m_ppline(ppline)
+		BindFramebufferCommand(FramebufferPtr fb)
+			: m_fb(fb)
 		{
 		}
 
 		Error operator()(GlState& state)
 		{
-			if(state.m_lastPplineBoundUuid != m_ppline->getUuid())
-			{
-				ANKI_TRACE_START_EVENT(GL_BIND_PPLINE);
+			m_fb->m_impl->bind(state);
+			return ErrorCode::NONE;
+		}
+	};
 
-				PipelineImpl& impl = *m_ppline->m_impl;
-				impl.bind(state);
-				state.m_lastPplineBoundUuid = m_ppline->getUuid();
-				ANKI_TRACE_INC_COUNTER(GR_PIPELINE_BINDS_HAPPENED, 1);
+	m_impl->m_state.beginRenderPass(fb, [=]() { m_impl->pushBackNewCommand<BindFramebufferCommand>(fb); });
+}
 
-				ANKI_TRACE_STOP_EVENT(GL_BIND_PPLINE);
-			}
-			else
-			{
-				ANKI_TRACE_INC_COUNTER(GR_PIPELINE_BINDS_SKIPPED, 1);
-			}
+void CommandBuffer::endRenderPass()
+{
+	// Nothing for GL
+	m_impl->m_state.endRenderPass();
+}
+
+void CommandBuffer::drawElements(
+	PrimitiveTopology topology, U32 count, U32 instanceCount, U32 firstIndex, U32 baseVertex, U32 baseInstance)
+{
+	class Cmd final : public GlCommand
+	{
+	public:
+		GLenum m_topology;
+		GLenum m_indexType;
+		DrawElementsIndirectInfo m_info;
 
+		Cmd(GLenum topology, GLenum indexType, const DrawElementsIndirectInfo& info)
+			: m_topology(topology)
+			, m_indexType(indexType)
+			, m_info(info)
+		{
+		}
+
+		Error operator()(GlState&)
+		{
+			glDrawElementsInstancedBaseVertexBaseInstance(m_topology,
+				m_info.m_count,
+				m_indexType,
+				numberToPtr<void*>(m_info.m_firstIndex),
+				m_info.m_instanceCount,
+				m_info.m_baseVertex,
+				m_info.m_baseInstance);
+
+			ANKI_TRACE_INC_COUNTER(GR_DRAWCALLS, 1);
+			ANKI_TRACE_INC_COUNTER(GR_VERTICES, m_info.m_instanceCount * m_info.m_count);
 			return ErrorCode::NONE;
 		}
 	};
 
-	m_impl->pushBackNewCommand<BindPipelineCommand>(ppline);
+	m_impl->m_state.checkIndexedDracall();
+	m_impl->flushDrawcall();
+
+	U idxBytes;
+	if(m_impl->m_state.m_indexType == GL_UNSIGNED_SHORT)
+	{
+		idxBytes = sizeof(U16);
+	}
+	else
+	{
+		ANKI_ASSERT(m_impl->m_state.m_indexType == GL_UNSIGNED_INT);
+		idxBytes = sizeof(U32);
+	}
+
+	firstIndex = firstIndex + m_impl->m_state.m_indexBuffOffset / idxBytes;
+
+	DrawElementsIndirectInfo info(count, instanceCount, firstIndex, baseVertex, baseInstance);
+	m_impl->pushBackNewCommand<Cmd>(convertPrimitiveTopology(topology), m_impl->m_state.m_indexType, info);
 }
 
-void CommandBuffer::beginRenderPass(FramebufferPtr fb)
+void CommandBuffer::drawArrays(PrimitiveTopology topology, U32 count, U32 instanceCount, U32 first, U32 baseInstance)
 {
-	class BindFramebufferCommand final : public GlCommand
+	class DrawArraysCommand final : public GlCommand
 	{
 	public:
-		FramebufferPtr m_fb;
+		GLenum m_topology;
+		DrawArraysIndirectInfo m_info;
 
-		BindFramebufferCommand(FramebufferPtr fb)
-			: m_fb(fb)
+		DrawArraysCommand(GLenum topology, const DrawArraysIndirectInfo& info)
+			: m_topology(topology)
+			, m_info(info)
 		{
 		}
 
 		Error operator()(GlState& state)
 		{
-			m_fb->m_impl->bind(state);
+			glDrawArraysInstancedBaseInstance(
+				m_topology, m_info.m_first, m_info.m_count, m_info.m_instanceCount, m_info.m_baseInstance);
+
+			ANKI_TRACE_INC_COUNTER(GR_DRAWCALLS, 1);
+			ANKI_TRACE_INC_COUNTER(GR_VERTICES, m_info.m_instanceCount * m_info.m_count);
 			return ErrorCode::NONE;
 		}
 	};
 
-	ANKI_ASSERT(!m_impl->m_dbg.m_insideRenderPass);
-#if ANKI_ASSERTS_ENABLED
-	m_impl->m_dbg.m_insideRenderPass = true;
-#endif
-	m_impl->pushBackNewCommand<BindFramebufferCommand>(fb);
-}
+	m_impl->m_state.checkNonIndexedDrawcall();
+	m_impl->flushDrawcall();
 
-void CommandBuffer::endRenderPass()
-{
-	// Nothing for GL
-	ANKI_ASSERT(m_impl->m_dbg.m_insideRenderPass);
-#if ANKI_ASSERTS_ENABLED
-	m_impl->m_dbg.m_insideRenderPass = false;
-#endif
+	DrawArraysIndirectInfo info(count, instanceCount, first, baseInstance);
+	m_impl->pushBackNewCommand<DrawArraysCommand>(convertPrimitiveTopology(topology), info);
 }
 
-void CommandBuffer::bindResourceGroup(ResourceGroupPtr rc, U slot, const TransientMemoryInfo* info)
+void CommandBuffer::drawElementsIndirect(
+	PrimitiveTopology topology, U32 drawCount, PtrSize offset, BufferPtr indirectBuff)
 {
-	m_impl->bindResourceGroup(rc, slot, info);
-}
+	class DrawElementsIndirectCommand final : public GlCommand
+	{
+	public:
+		GLenum m_topology;
+		GLenum m_indexType;
+		U32 m_drawCount;
+		PtrSize m_offset;
+		BufferPtr m_buff;
 
-void CommandBuffer::drawElements(U32 count, U32 instanceCount, U32 firstIndex, U32 baseVertex, U32 baseInstance)
-{
-	m_impl->drawElements(count, instanceCount, firstIndex, baseVertex, baseInstance);
-}
+		DrawElementsIndirectCommand(GLenum topology, GLenum indexType, U32 drawCount, PtrSize offset, BufferPtr buff)
+			: m_topology(topology)
+			, m_indexType(indexType)
+			, m_drawCount(drawCount)
+			, m_offset(offset)
+			, m_buff(buff)
+		{
+			ANKI_ASSERT(drawCount > 0);
+			ANKI_ASSERT((m_offset % 4) == 0);
+		}
 
-void CommandBuffer::drawArrays(U32 count, U32 instanceCount, U32 first, U32 baseInstance)
-{
-	m_impl->drawArrays(count, instanceCount, first, baseInstance);
-}
+		Error operator()(GlState&)
+		{
+			const BufferImpl& buff = *m_buff->m_impl;
 
-void CommandBuffer::drawElementsIndirect(U32 drawCount, PtrSize offset, BufferPtr indirectBuff)
-{
-	m_impl->drawElementsIndirect(drawCount, offset, indirectBuff);
+			ANKI_ASSERT(m_offset + sizeof(DrawElementsIndirectInfo) * m_drawCount <= buff.m_size);
+
+			glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buff.getGlName());
+
+			glMultiDrawElementsIndirect(
+				m_topology, m_indexType, numberToPtr<void*>(m_offset), m_drawCount, sizeof(DrawElementsIndirectInfo));
+
+			glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
+			return ErrorCode::NONE;
+		}
+	};
+
+	m_impl->m_state.checkIndexedDracall();
+	m_impl->flushDrawcall();
+	m_impl->pushBackNewCommand<DrawElementsIndirectCommand>(
+		convertPrimitiveTopology(topology), m_impl->m_state.m_indexType, drawCount, offset, indirectBuff);
 }
 
-void CommandBuffer::drawArraysIndirect(U32 drawCount, PtrSize offset, BufferPtr indirectBuff)
+void CommandBuffer::drawArraysIndirect(
+	PrimitiveTopology topology, U32 drawCount, PtrSize offset, BufferPtr indirectBuff)
 {
-	m_impl->drawArraysIndirect(drawCount, offset, indirectBuff);
+	class DrawArraysIndirectCommand final : public GlCommand
+	{
+	public:
+		GLenum m_topology;
+		U32 m_drawCount;
+		PtrSize m_offset;
+		BufferPtr m_buff;
+
+		DrawArraysIndirectCommand(GLenum topology, U32 drawCount, PtrSize offset, BufferPtr buff)
+			: m_topology(topology)
+			, m_drawCount(drawCount)
+			, m_offset(offset)
+			, m_buff(buff)
+		{
+			ANKI_ASSERT(drawCount > 0);
+			ANKI_ASSERT((m_offset % 4) == 0);
+		}
+
+		Error operator()(GlState& state)
+		{
+			const BufferImpl& buff = *m_buff->m_impl;
+
+			ANKI_ASSERT(m_offset + sizeof(DrawArraysIndirectInfo) * m_drawCount <= buff.m_size);
+
+			glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buff.getGlName());
+
+			glMultiDrawArraysIndirect(
+				m_topology, numberToPtr<void*>(m_offset), m_drawCount, sizeof(DrawArraysIndirectInfo));
+
+			glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
+			return ErrorCode::NONE;
+		}
+	};
+
+	m_impl->m_state.checkNonIndexedDrawcall();
+	m_impl->flushDrawcall();
+	m_impl->pushBackNewCommand<DrawArraysIndirectCommand>(
+		convertPrimitiveTopology(topology), drawCount, offset, indirectBuff);
 }
 
 void CommandBuffer::dispatchCompute(U32 groupCountX, U32 groupCountY, U32 groupCountZ)
 {
-	m_impl->dispatchCompute(groupCountX, groupCountY, groupCountZ);
+	class DispatchCommand final : public GlCommand
+	{
+	public:
+		Array<U32, 3> m_size;
+
+		DispatchCommand(U32 x, U32 y, U32 z)
+			: m_size({{x, y, z}})
+		{
+		}
+
+		Error operator()(GlState&)
+		{
+			glDispatchCompute(m_size[0], m_size[1], m_size[2]);
+			return ErrorCode::NONE;
+		}
+	};
+
+	m_impl->m_state.checkDispatch();
+	m_impl->pushBackNewCommand<DispatchCommand>(groupCountX, groupCountY, groupCountZ);
 }
 
 void CommandBuffer::resetOcclusionQuery(OcclusionQueryPtr query)

+ 24 - 221
src/anki/gr/gl/CommandBufferImpl.cpp

@@ -9,9 +9,9 @@
 #include <anki/gr/gl/GlState.h>
 #include <anki/gr/gl/Error.h>
 
-#include <anki/gr/gl/ResourceGroupImpl.h>
 #include <anki/gr/OcclusionQuery.h>
 #include <anki/gr/gl/OcclusionQueryImpl.h>
+#include <anki/gr/Buffer.h>
 #include <anki/gr/gl/BufferImpl.h>
 
 #include <anki/util/Logger.h>
@@ -96,241 +96,44 @@ GrAllocator<U8> CommandBufferImpl::getAllocator() const
 	return m_manager->getAllocator();
 }
 
-class BindResourcesCommand final : public GlCommand
+void CommandBufferImpl::flushDrawcall()
 {
-public:
-	ResourceGroupPtr m_rc;
-	TransientMemoryInfo m_info;
-	U8 m_slot;
-
-	BindResourcesCommand(ResourceGroupPtr rc, U8 slot, const TransientMemoryInfo* info)
-		: m_rc(rc)
-		, m_slot(slot)
-	{
-		if(info)
-		{
-			m_info = *info;
-		}
-	}
-
-	Error operator()(GlState& state)
-	{
-		ANKI_TRACE_START_EVENT(GL_BIND_RESOURCES);
-		m_rc->m_impl->bind(m_slot, m_info, state);
-		ANKI_TRACE_STOP_EVENT(GL_BIND_RESOURCES);
-		return ErrorCode::NONE;
-	}
-};
-
-void CommandBufferImpl::bindResourceGroup(ResourceGroupPtr rc, U slot, const TransientMemoryInfo* info)
-{
-	ANKI_ASSERT(rc.isCreated());
-
-	pushBackNewCommand<BindResourcesCommand>(rc, slot, info);
-}
-
-void CommandBufferImpl::drawElements(U32 count, U32 instanceCount, U32 firstIndex, U32 baseVertex, U32 baseInstance)
-{
-	class DrawElementsCommand : public GlCommand
-	{
-	public:
-		DrawElementsIndirectInfo m_info;
-
-		DrawElementsCommand(const DrawElementsIndirectInfo& info)
-			: m_info(info)
-		{
-		}
-
-		Error operator()(GlState& state)
-		{
-			GLenum indicesType = 0;
-			switch(state.m_indexSize)
-			{
-			case 2:
-				indicesType = GL_UNSIGNED_SHORT;
-				break;
-			case 4:
-				indicesType = GL_UNSIGNED_INT;
-				break;
-			default:
-				ANKI_ASSERT(0);
-				break;
-			};
-
-			state.flushVertexState();
-			state.flushStencilState();
-			glDrawElementsInstancedBaseVertexBaseInstance(state.m_topology,
-				m_info.m_count,
-				indicesType,
-				(const void*)(PtrSize)(m_info.m_firstIndex * state.m_indexSize),
-				m_info.m_instanceCount,
-				m_info.m_baseVertex,
-				m_info.m_baseInstance);
-
-			ANKI_TRACE_INC_COUNTER(GR_DRAWCALLS, 1);
-			ANKI_TRACE_INC_COUNTER(GR_VERTICES, m_info.m_instanceCount * m_info.m_count);
-
-			return ErrorCode::NONE;
-		}
-	};
-
-	ANKI_ASSERT(m_dbg.m_insideRenderPass);
-	DrawElementsIndirectInfo info(count, instanceCount, firstIndex, baseVertex, baseInstance);
-
-	checkDrawcall();
-	pushBackNewCommand<DrawElementsCommand>(info);
-}
-
-void CommandBufferImpl::drawArrays(U32 count, U32 instanceCount, U32 first, U32 baseInstance)
-{
-	class DrawArraysCommand final : public GlCommand
-	{
-	public:
-		DrawArraysIndirectInfo m_info;
-
-		DrawArraysCommand(const DrawArraysIndirectInfo& info)
-			: m_info(info)
-		{
-		}
-
-		Error operator()(GlState& state)
-		{
-			state.flushVertexState();
-			state.flushStencilState();
-			glDrawArraysInstancedBaseInstance(
-				state.m_topology, m_info.m_first, m_info.m_count, m_info.m_instanceCount, m_info.m_baseInstance);
-
-			ANKI_TRACE_INC_COUNTER(GR_DRAWCALLS, 1);
-			return ErrorCode::NONE;
-		}
-	};
-
-	ANKI_ASSERT(m_dbg.m_insideRenderPass);
-	DrawArraysIndirectInfo info(count, instanceCount, first, baseInstance);
-
-	checkDrawcall();
-	pushBackNewCommand<DrawArraysCommand>(info);
-}
-
-void CommandBufferImpl::drawElementsIndirect(U32 drawCount, PtrSize offset, BufferPtr indirectBuff)
-{
-	class DrawElementsIndirectCommand final : public GlCommand
+	class Cmd final : public GlCommand
 	{
 	public:
-		U32 m_drawCount;
-		PtrSize m_offset;
-		BufferPtr m_buff;
-
-		DrawElementsIndirectCommand(U32 drawCount, PtrSize offset, BufferPtr buff)
-			: m_drawCount(drawCount)
-			, m_offset(offset)
-			, m_buff(buff)
+		GLenum m_face;
+		GLenum m_func;
+		GLint m_ref;
+		GLuint m_compareMask;
+
+		Cmd(GLenum face, GLenum func, GLint ref, GLuint mask)
+			: m_face(face)
+			, m_func(func)
+			, m_ref(ref)
+			, m_compareMask(mask)
 		{
-			ANKI_ASSERT(drawCount > 0);
-			ANKI_ASSERT((m_offset % 4) == 0);
-		}
-
-		Error operator()(GlState& state)
-		{
-			state.flushVertexState();
-			state.flushStencilState();
-			const BufferImpl& buff = *m_buff->m_impl;
-
-			ANKI_ASSERT(m_offset + sizeof(DrawElementsIndirectInfo) * m_drawCount <= buff.m_size);
-
-			glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buff.getGlName());
-
-			GLenum indicesType = 0;
-			switch(state.m_indexSize)
-			{
-			case 2:
-				indicesType = GL_UNSIGNED_SHORT;
-				break;
-			case 4:
-				indicesType = GL_UNSIGNED_INT;
-				break;
-			default:
-				ANKI_ASSERT(0);
-				break;
-			};
-
-			glMultiDrawElementsIndirect(state.m_topology,
-				indicesType,
-				numberToPtr<void*>(m_offset),
-				m_drawCount,
-				sizeof(DrawElementsIndirectInfo));
-
-			glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
-			return ErrorCode::NONE;
 		}
-	};
-
-	checkDrawcall();
-	pushBackNewCommand<DrawElementsIndirectCommand>(drawCount, offset, indirectBuff);
-}
-
-void CommandBufferImpl::drawArraysIndirect(U32 drawCount, PtrSize offset, BufferPtr indirectBuff)
-{
-	class DrawArraysIndirectCommand final : public GlCommand
-	{
-	public:
-		U32 m_drawCount;
-		PtrSize m_offset;
-		BufferPtr m_buff;
 
-		DrawArraysIndirectCommand(U32 drawCount, PtrSize offset, BufferPtr buff)
-			: m_drawCount(drawCount)
-			, m_offset(offset)
-			, m_buff(buff)
-		{
-			ANKI_ASSERT(drawCount > 0);
-			ANKI_ASSERT((m_offset % 4) == 0);
-		}
-
-		Error operator()(GlState& state)
+		Error operator()(GlState&)
 		{
-			state.flushVertexState();
-			state.flushStencilState();
-			const BufferImpl& buff = *m_buff->m_impl;
-
-			ANKI_ASSERT(m_offset + sizeof(DrawArraysIndirectInfo) * m_drawCount <= buff.m_size);
-
-			glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buff.getGlName());
-
-			glMultiDrawArraysIndirect(
-				state.m_topology, numberToPtr<void*>(m_offset), m_drawCount, sizeof(DrawArraysIndirectInfo));
-
-			glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
+			glStencilFuncSeparate(m_face, m_func, m_ref, m_compareMask);
 			return ErrorCode::NONE;
 		}
 	};
 
-	checkDrawcall();
-	pushBackNewCommand<DrawArraysIndirectCommand>(drawCount, offset, indirectBuff);
-}
-
-void CommandBufferImpl::dispatchCompute(U32 groupCountX, U32 groupCountY, U32 groupCountZ)
-{
-	ANKI_ASSERT(!m_dbg.m_insideRenderPass);
-
-	class DispatchCommand final : public GlCommand
+	const Array<GLenum, 2> FACE = {{GL_FRONT, GL_BACK}};
+	for(U i = 0; i < 2; ++i)
 	{
-	public:
-		Array<U32, 3> m_size;
-
-		DispatchCommand(U32 x, U32 y, U32 z)
-			: m_size({{x, y, z}})
+		if(m_state.m_glStencilFuncSeparateDirty[i])
 		{
-		}
+			pushBackNewCommand<Cmd>(FACE[i],
+				convertCompareOperation(m_state.m_stencilCompare[i]),
+				m_state.m_stencilRef[i],
+				m_state.m_stencilCompareMask[i]);
 
-		Error operator()(GlState&)
-		{
-			glDispatchCompute(m_size[0], m_size[1], m_size[2]);
-			return ErrorCode::NONE;
+			m_state.m_glStencilFuncSeparateDirty[i] = false;
 		}
-	};
-
-	pushBackNewCommand<DispatchCommand>(groupCountX, groupCountY, groupCountZ);
+	}
 }
 
 } // end namespace anki

+ 2 - 39
src/anki/gr/gl/CommandBufferImpl.h

@@ -42,17 +42,6 @@ class CommandBufferImpl
 public:
 	using InitHints = CommandBufferInitHints;
 
-#if ANKI_ASSERTS_ENABLED
-	class StateSet
-	{
-	public:
-		Bool m_viewport = false;
-		Bool m_polygonOffset = false;
-		Bool m_insideRenderPass = false;
-		Bool m_secondLevel = false;
-	} m_dbg;
-#endif
-
 	GrManager* m_manager = nullptr;
 	GlCommand* m_firstCommand = nullptr;
 	GlCommand* m_lastCommand = nullptr;
@@ -123,41 +112,15 @@ public:
 		return m_firstCommand == nullptr;
 	}
 
-	void bindResourceGroup(ResourceGroupPtr rc, U slot, const TransientMemoryInfo* info);
-
-	void drawElements(U32 count, U32 instanceCount = 1, U32 firstIndex = 0, U32 baseVertex = 0, U32 baseInstance = 0);
-
-	void drawArrays(U32 count, U32 instanceCount = 1, U32 first = 0, U32 baseInstance = 0);
-
-	void drawElementsIndirect(U32 drawCount, PtrSize offset, BufferPtr indirectBuff);
-
-	void drawArraysIndirect(U32 drawCount, PtrSize offset, BufferPtr indirectBuff);
-
-	void drawElementsConditional(OcclusionQueryPtr query,
-		U32 count,
-		U32 instanceCount = 1,
-		U32 firstIndex = 0,
-		U32 baseVertex = 0,
-		U32 baseInstance = 0);
-
-	void drawArraysConditional(
-		OcclusionQueryPtr query, U32 count, U32 instanceCount = 1, U32 first = 0, U32 baseInstance = 0);
-
-	void dispatchCompute(U32 groupCountX, U32 groupCountY, U32 groupCountZ);
-
 	Bool isSecondLevel() const
 	{
 		return !!(m_flags & CommandBufferFlag::SECOND_LEVEL);
 	}
 
+	void flushDrawcall();
+
 private:
 	void destroy();
-
-	void checkDrawcall() const
-	{
-		ANKI_ASSERT(m_dbg.m_viewport == true);
-		ANKI_ASSERT(m_dbg.m_polygonOffset == true);
-	}
 };
 
 template<typename TCommand, typename... TArgs>

+ 31 - 0
src/anki/gr/gl/Common.h

@@ -131,6 +131,37 @@ inline GLenum convertBlendFunction(BlendFunction ak)
 
 	return out;
 }
+
+inline GLenum convertPrimitiveTopology(PrimitiveTopology ak)
+{
+	GLenum out;
+	switch(ak)
+	{
+	case PrimitiveTopology::POINTS:
+		out = GL_POINTS;
+		break;
+	case PrimitiveTopology::LINES:
+		out = GL_LINES;
+		break;
+	case PrimitiveTopology::LINE_STIP:
+		out = GL_LINE_STRIP;
+		break;
+	case PrimitiveTopology::TRIANGLES:
+		out = GL_TRIANGLES;
+		break;
+	case PrimitiveTopology::TRIANGLE_STRIP:
+		out = GL_TRIANGLE_STRIP;
+		break;
+	case PrimitiveTopology::PATCHES:
+		out = GL_PATCHES;
+		break;
+	default:
+		ANKI_ASSERT(0);
+		out = 0;
+	}
+
+	return out;
+}
 /// @}
 
 } // end namespace anki

+ 17 - 0
src/anki/gr/gl/FramebufferImpl.h

@@ -35,6 +35,23 @@ public:
 	/// Bind it to the state. Call it in rendering thread
 	void bind(const GlState& state);
 
+	U getColorBufferCount() const
+	{
+		return m_in.m_colorAttachmentCount;
+	}
+
+	Bool hasDepthBuffer() const
+	{
+		return m_in.m_depthStencilAttachment.m_texture.isCreated()
+			&& !!(m_in.m_depthStencilAttachment.m_aspect & DepthStencilAspectMask::DEPTH);
+	}
+
+	Bool hasStencilBuffer() const
+	{
+		return m_in.m_depthStencilAttachment.m_texture.isCreated()
+			&& !!(m_in.m_depthStencilAttachment.m_aspect & DepthStencilAspectMask::STENCIL);
+	}
+
 private:
 	FramebufferInitInfo m_in;
 

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

@@ -139,9 +139,6 @@ void GlState::initRenderThread()
 	{
 		glEnableVertexAttribArray(i);
 	}
-
-	// Other
-	memset(&m_vertexBindingStrides[0], 0, sizeof(m_vertexBindingStrides));
 }
 
 void GlState::destroy()
@@ -149,30 +146,4 @@ void GlState::destroy()
 	glDeleteVertexArrays(1, &m_defaultVao);
 }
 
-void GlState::flushVertexState()
-{
-	if(m_vertBindingsDirty)
-	{
-		m_vertBindingsDirty = false;
-
-		glBindVertexBuffers(
-			0, m_vertBindingCount, &m_vertBuffNames[0], &m_vertBuffOffsets[0], &m_vertexBindingStrides[0]);
-	}
-}
-
-void GlState::flushStencilState()
-{
-	if(m_glStencilFuncSeparateDirtyMask & 1)
-	{
-		glStencilFuncSeparate(GL_FRONT, m_stencilCompareFunc[0], m_stencilRef[0], m_stencilCompareMask[0]);
-		m_glStencilFuncSeparateDirtyMask &= ~1u;
-	}
-
-	if(m_glStencilFuncSeparateDirtyMask & 2)
-	{
-		glStencilFuncSeparate(GL_BACK, m_stencilCompareFunc[1], m_stencilRef[1], m_stencilCompareMask[1]);
-		m_glStencilFuncSeparateDirtyMask &= ~2u;
-	}
-}
-
 } // end namespace anki

+ 4 - 43
src/anki/gr/gl/GlState.h

@@ -26,54 +26,18 @@ public:
 	GpuVendor m_gpu = GpuVendor::UNKNOWN;
 	Bool8 m_registerMessages = false;
 
-	GLuint m_defaultVao;
+	GLuint m_defaultVao = 0;
 
-	/// @name Cached state
+	/// @name FB
 	/// @{
-	Array<U16, 4> m_viewport = {{0, 0, 0, 0}};
-
-	GLenum m_blendSfunc = GL_ONE;
-	GLenum m_blendDfunc = GL_ZERO;
-	/// @}
-
-	/// @name Pipeline/resource group state
-	/// @{
-	U64 m_lastPplineBoundUuid = MAX_U64;
-
-	Array<GLuint, MAX_VERTEX_ATTRIBUTES> m_vertBuffNames;
-	Array<GLintptr, MAX_VERTEX_ATTRIBUTES> m_vertBuffOffsets;
-	Array<GLsizei, MAX_VERTEX_ATTRIBUTES> m_vertexBindingStrides;
-	U8 m_vertBindingCount = 0;
-	Bool8 m_vertBindingsDirty = true;
-
-	GLenum m_topology = 0;
-	U8 m_indexSize = 4;
-
-	class
-	{
-	public:
-		U64 m_vertex = 0;
-		U64 m_inputAssembler = 0;
-		U64 m_tessellation = 0;
-		U64 m_viewport = 0;
-		U64 m_rasterizer = 0;
-		U64 m_depthStencil = 0;
-		U64 m_color = 0;
-	} m_stateHashes;
-
 	Array2d<Bool, MAX_COLOR_ATTACHMENTS, 4> m_colorWriteMasks = {{{{true, true, true, true}},
 		{{true, true, true, true}},
 		{{true, true, true, true}},
 		{{true, true, true, true}}}};
-	Bool m_depthWriteMask = true;
 
-	// Stencil
-	Array<GLenum, 2> m_stencilCompareFunc = {{GL_ALWAYS, GL_ALWAYS}}; ///< Pipeline sets it
-	Array<U32, 2> m_stencilRef = {{0, 0}}; ///< CommandBuffer sets it
-	Array<U32, 2> m_stencilCompareMask = {{MAX_U32, MAX_U32}}; ///< CommandBuffer sets it
-	U8 m_glStencilFuncSeparateDirtyMask = 0;
+	Bool8 m_depthWriteMask = true;
 
-	Array<U32, 2> m_stencilWriteMask = {{MAX_U32, MAX_U32}}; ///< Framebuffer wants that.
+	Array<U32, 2> m_stencilWriteMask = {{MAX_U32, MAX_U32}};
 	/// @}
 
 	GlState(GrManager* manager)
@@ -89,9 +53,6 @@ public:
 
 	/// Call this from the rendering thread.
 	void destroy();
-
-	void flushVertexState();
-	void flushStencilState();
 };
 /// @}
 

+ 0 - 62
src/anki/gr/gl/Pipeline.cpp

@@ -1,62 +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/gr/Pipeline.h>
-#include <anki/gr/gl/PipelineImpl.h>
-#include <anki/gr/GrManager.h>
-#include <anki/gr/gl/CommandBufferImpl.h>
-#include <anki/core/Trace.h>
-
-namespace anki
-{
-
-Pipeline::Pipeline(GrManager* manager, U64 hash, GrObjectCache* cache)
-	: GrObject(manager, CLASS_TYPE, hash, cache)
-{
-	ANKI_TRACE_INC_COUNTER(GR_PIPELINES_CREATED, 1);
-}
-
-Pipeline::~Pipeline()
-{
-}
-
-class CreatePipelineCommand final : public GlCommand
-{
-public:
-	PipelinePtr m_ppline;
-	PipelineInitInfo m_init;
-
-	CreatePipelineCommand(Pipeline* ppline, const PipelineInitInfo& init)
-		: m_ppline(ppline)
-		, m_init(init)
-	{
-	}
-
-	Error operator()(GlState&)
-	{
-		PipelineImpl& impl = *m_ppline->m_impl;
-
-		Error err = impl.init(m_init);
-
-		GlObject::State oldState = impl.setStateAtomically(err ? GlObject::State::ERROR : GlObject::State::CREATED);
-		ANKI_ASSERT(oldState == GlObject::State::TO_BE_CREATED);
-		(void)oldState;
-
-		return err;
-	}
-};
-
-void Pipeline::init(const PipelineInitInfo& init)
-{
-	m_impl.reset(getAllocator().newInstance<PipelineImpl>(&getManager()));
-
-	CommandBufferInitInfo inf;
-	CommandBufferPtr cmdb = getManager().newInstance<CommandBuffer>(inf);
-
-	cmdb->m_impl->pushBackNewCommand<CreatePipelineCommand>(this, init);
-	cmdb->flush();
-}
-
-} // end namespace anki

+ 0 - 554
src/anki/gr/gl/PipelineImpl.cpp

@@ -1,554 +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/gr/gl/PipelineImpl.h>
-#include <anki/gr/gl/ShaderImpl.h>
-#include <anki/gr/gl/GlState.h>
-#include <anki/gr/common/Misc.h>
-#include <anki/util/Logger.h>
-#include <anki/util/Hash.h>
-
-namespace anki
-{
-
-static void deletePrograms(GLsizei n, const GLuint* names)
-{
-	ANKI_ASSERT(n == 1);
-	ANKI_ASSERT(names);
-	glDeleteProgram(*names);
-}
-
-PipelineImpl::~PipelineImpl()
-{
-	destroyDeferred(deletePrograms);
-}
-
-Error PipelineImpl::init(const PipelineInitInfo& init)
-{
-	m_in = init;
-
-	ANKI_CHECK(createGlPipeline());
-	if(!m_compute)
-	{
-		initVertexState();
-		initInputAssemblerState();
-		initTessellationState();
-		initRasterizerState();
-		initDepthStencilState();
-		initColorState();
-	}
-
-	return ErrorCode::NONE;
-}
-
-Error PipelineImpl::createGlPipeline()
-{
-	Error err = ErrorCode::NONE;
-
-	// Do checks
-	U mask = 0;
-	U count = 6;
-	while(count-- != 0)
-	{
-		const ShaderPtr& shader = m_in.m_shaders[count];
-		if(shader.isCreated())
-		{
-			ANKI_ASSERT(count == enumToType(shader->m_impl->m_type));
-			mask |= 1 << count;
-		}
-	}
-
-	if(mask & (1 << 5))
-	{
-		// Is compute
-
-		m_compute = true;
-
-		ANKI_ASSERT((mask & (1 << 5)) == (1 << 5) && "Compute should be alone in the pipeline");
-	}
-	else
-	{
-		m_compute = false;
-
-		const U fragVert = (1 << 0) | (1 << 4);
-		ANKI_ASSERT((mask & fragVert) && "Should contain vert and frag");
-		(void)fragVert;
-
-		const U tess = (1 << 1) | (1 << 2);
-		if((mask & tess) != 0)
-		{
-			ANKI_ASSERT(((mask & tess) == 0x6) && "Should set both the tessellation shaders");
-		}
-	}
-
-	// Create and attach programs
-	m_glName = glCreateProgram();
-	ANKI_ASSERT(m_glName != 0);
-
-	for(U i = 0; i < m_in.m_shaders.getSize(); i++)
-	{
-		ShaderPtr& shader = m_in.m_shaders[i];
-
-		if(shader.isCreated())
-		{
-			glAttachShader(m_glName, shader->m_impl->getGlName());
-
-			if(i == U(ShaderType::TESSELLATION_CONTROL) || i == U(ShaderType::TESSELLATION_EVALUATION))
-			{
-				m_tessellation = true;
-			}
-		}
-	}
-
-	// Validate and check error
-	glLinkProgram(m_glName);
-	GLint status = 0;
-	glGetProgramiv(m_glName, GL_LINK_STATUS, &status);
-
-	if(!status)
-	{
-		GLint infoLen = 0;
-		GLint charsWritten = 0;
-		DynamicArrayAuto<char> infoLogTxt(getAllocator());
-
-		glGetProgramiv(m_glName, GL_INFO_LOG_LENGTH, &infoLen);
-
-		infoLogTxt.create(infoLen + 1);
-
-		glGetProgramInfoLog(m_glName, infoLen, &charsWritten, &infoLogTxt[0]);
-
-		ANKI_LOGE("Ppline error log follows (vs:%u, fs:%u):\n%s",
-			m_in.m_shaders[ShaderType::VERTEX].isCreated() ? m_in.m_shaders[ShaderType::VERTEX]->m_impl->getGlName()
-														   : -1,
-			m_in.m_shaders[ShaderType::FRAGMENT].isCreated() ? m_in.m_shaders[ShaderType::FRAGMENT]->m_impl->getGlName()
-															 : -1,
-			&infoLogTxt[0]);
-		err = ErrorCode::USER_DATA;
-	}
-
-	return err;
-}
-
-void PipelineImpl::bind(GlState& state)
-{
-	glUseProgram(m_glName);
-
-	if(m_compute)
-	{
-		return;
-	}
-
-	// Set state
-	setVertexState(state);
-	setInputAssemblerState(state);
-	setTessellationState(state);
-	setViewportState(state);
-	setRasterizerState(state);
-	setDepthStencilState(state);
-	setColorState(state);
-}
-
-void PipelineImpl::initVertexState()
-{
-	for(U i = 0; i < m_in.m_vertex.m_attributeCount; ++i)
-	{
-		const VertexAttributeBinding& binding = m_in.m_vertex.m_attributes[i];
-		Attribute& cache = m_cache.m_attribs[i];
-
-		// Component count
-		if(binding.m_format == PixelFormat(ComponentFormat::R32, TransformFormat::FLOAT))
-		{
-			cache.m_compCount = 1;
-			cache.m_type = GL_FLOAT;
-			cache.m_normalized = false;
-		}
-		else if(binding.m_format == PixelFormat(ComponentFormat::R32G32, TransformFormat::FLOAT))
-		{
-			cache.m_compCount = 2;
-			cache.m_type = GL_FLOAT;
-			cache.m_normalized = false;
-		}
-		else if(binding.m_format == PixelFormat(ComponentFormat::R32G32B32, TransformFormat::FLOAT))
-		{
-			cache.m_compCount = 3;
-			cache.m_type = GL_FLOAT;
-			cache.m_normalized = false;
-		}
-		else if(binding.m_format == PixelFormat(ComponentFormat::R32G32B32A32, TransformFormat::FLOAT))
-		{
-			cache.m_compCount = 4;
-			cache.m_type = GL_FLOAT;
-			cache.m_normalized = false;
-		}
-		else if(binding.m_format == PixelFormat(ComponentFormat::R16G16, TransformFormat::FLOAT))
-		{
-			cache.m_compCount = 2;
-			cache.m_type = GL_HALF_FLOAT;
-			cache.m_normalized = false;
-		}
-		else if(binding.m_format == PixelFormat(ComponentFormat::R16G16, TransformFormat::UNORM))
-		{
-			cache.m_compCount = 2;
-			cache.m_type = GL_UNSIGNED_SHORT;
-			cache.m_normalized = true;
-		}
-		else if(binding.m_format == PixelFormat(ComponentFormat::R10G10B10A2, TransformFormat::SNORM))
-		{
-			cache.m_compCount = 4;
-			cache.m_type = GL_INT_2_10_10_10_REV;
-			cache.m_normalized = true;
-		}
-		else if(binding.m_format == PixelFormat(ComponentFormat::R8G8B8A8, TransformFormat::UNORM))
-		{
-			cache.m_compCount = 4;
-			cache.m_type = GL_UNSIGNED_BYTE;
-			cache.m_normalized = true;
-		}
-		else if(binding.m_format == PixelFormat(ComponentFormat::R8G8B8, TransformFormat::UNORM))
-		{
-			cache.m_compCount = 3;
-			cache.m_type = GL_UNSIGNED_BYTE;
-			cache.m_normalized = true;
-		}
-		else
-		{
-			ANKI_ASSERT(0 && "TODO");
-		}
-	}
-
-	m_hashes.m_vertex = computeHash(&m_in.m_vertex, sizeof(m_in.m_vertex));
-}
-
-void PipelineImpl::initInputAssemblerState()
-{
-	switch(m_in.m_inputAssembler.m_topology)
-	{
-	case PrimitiveTopology::POINTS:
-		m_cache.m_topology = GL_POINTS;
-		break;
-	case PrimitiveTopology::LINES:
-		m_cache.m_topology = GL_LINES;
-		break;
-	case PrimitiveTopology::LINE_STIP:
-		m_cache.m_topology = GL_LINE_STRIP;
-		break;
-	case PrimitiveTopology::TRIANGLES:
-		m_cache.m_topology = GL_TRIANGLES;
-		break;
-	case PrimitiveTopology::TRIANGLE_STRIP:
-		m_cache.m_topology = GL_TRIANGLE_STRIP;
-		break;
-	case PrimitiveTopology::PATCHES:
-		m_cache.m_topology = GL_PATCHES;
-		break;
-	default:
-		ANKI_ASSERT(0);
-	}
-
-	m_hashes.m_inputAssembler = computeHash(&m_in.m_inputAssembler, sizeof(m_in.m_inputAssembler));
-}
-
-void PipelineImpl::initTessellationState()
-{
-	m_hashes.m_tessellation = computeHash(&m_in.m_tessellation, sizeof(m_in.m_tessellation));
-}
-
-void PipelineImpl::initRasterizerState()
-{
-	switch(m_in.m_rasterizer.m_fillMode)
-	{
-	case FillMode::POINTS:
-		m_cache.m_fillMode = GL_POINT;
-		break;
-	case FillMode::WIREFRAME:
-		m_cache.m_fillMode = GL_LINE;
-		break;
-	case FillMode::SOLID:
-		m_cache.m_fillMode = GL_FILL;
-		break;
-	default:
-		ANKI_ASSERT(0);
-	}
-
-	switch(m_in.m_rasterizer.m_cullMode)
-	{
-	case FaceSelectionMask::FRONT:
-		m_cache.m_cullMode = GL_FRONT;
-		break;
-	case FaceSelectionMask::BACK:
-		m_cache.m_cullMode = GL_BACK;
-		break;
-	case FaceSelectionMask::FRONT_AND_BACK:
-		m_cache.m_cullMode = GL_FRONT_AND_BACK;
-		break;
-	default:
-		ANKI_ASSERT(0);
-	}
-
-	m_hashes.m_rasterizer = computeHash(&m_in.m_rasterizer, sizeof(m_in.m_rasterizer));
-}
-
-void PipelineImpl::initDepthStencilState()
-{
-	const auto& ds = m_in.m_depthStencil;
-
-	// Depth
-	m_cache.m_depthCompareFunction = convertCompareOperation(ds.m_depthCompareFunction);
-
-	// Stencil
-	m_cache.m_stencilFailOp[0] = convertStencilOperation(ds.m_stencilFront.m_stencilFailOperation);
-	m_cache.m_stencilPassDepthFailOp[0] = convertStencilOperation(ds.m_stencilFront.m_stencilPassDepthFailOperation);
-	m_cache.m_stencilPassDepthPassOp[0] = convertStencilOperation(ds.m_stencilFront.m_stencilPassDepthPassOperation);
-	m_cache.m_stencilCompareFunc[0] = convertCompareOperation(ds.m_stencilFront.m_compareFunction);
-
-	m_cache.m_stencilFailOp[1] = convertStencilOperation(ds.m_stencilBack.m_stencilFailOperation);
-	m_cache.m_stencilPassDepthFailOp[1] = convertStencilOperation(ds.m_stencilBack.m_stencilPassDepthFailOperation);
-	m_cache.m_stencilPassDepthPassOp[1] = convertStencilOperation(ds.m_stencilBack.m_stencilPassDepthPassOperation);
-	m_cache.m_stencilCompareFunc[1] = convertCompareOperation(ds.m_stencilBack.m_compareFunction);
-
-	if(stencilTestDisabled(ds.m_stencilFront) && stencilTestDisabled(ds.m_stencilBack))
-	{
-		m_stencilTestEnabled = false;
-	}
-	else
-	{
-		m_stencilTestEnabled = true;
-	}
-
-	m_hashes.m_depthStencil = computeHash(&ds, sizeof(ds));
-}
-
-void PipelineImpl::initColorState()
-{
-	for(U i = 0; i < m_in.m_color.m_attachmentCount; ++i)
-	{
-		Attachment& out = m_cache.m_attachments[i];
-		const ColorAttachmentStateInfo& in = m_in.m_color.m_attachments[i];
-
-		out.m_srcBlendMethod = convertBlendMethod(in.m_srcBlendMethod);
-		out.m_dstBlendMethod = convertBlendMethod(in.m_dstBlendMethod);
-
-		switch(in.m_blendFunction)
-		{
-		case BlendFunction::ADD:
-			out.m_blendFunction = GL_FUNC_ADD;
-			break;
-		case BlendFunction::SUBTRACT:
-			out.m_blendFunction = GL_FUNC_SUBTRACT;
-			break;
-		case BlendFunction::REVERSE_SUBTRACT:
-			out.m_blendFunction = GL_FUNC_REVERSE_SUBTRACT;
-			break;
-		case BlendFunction::MIN:
-			out.m_blendFunction = GL_MIN;
-			break;
-		case BlendFunction::MAX:
-			out.m_blendFunction = GL_MAX;
-			break;
-		default:
-			ANKI_ASSERT(0);
-		}
-
-		out.m_channelWriteMask[0] = (in.m_channelWriteMask & ColorBit::RED) != 0;
-		out.m_channelWriteMask[1] = (in.m_channelWriteMask & ColorBit::GREEN) != 0;
-		out.m_channelWriteMask[2] = (in.m_channelWriteMask & ColorBit::BLUE) != 0;
-		out.m_channelWriteMask[3] = (in.m_channelWriteMask & ColorBit::ALPHA) != 0;
-
-		if(!(out.m_srcBlendMethod == GL_ONE && out.m_dstBlendMethod == GL_ZERO))
-		{
-			m_blendEnabled = true;
-		}
-	}
-
-	m_hashes.m_color = computeHash(&m_in.m_color, sizeof(m_in.m_color));
-}
-
-void PipelineImpl::setVertexState(GlState& state) const
-{
-	if(state.m_stateHashes.m_vertex == m_hashes.m_vertex)
-	{
-		return;
-	}
-
-	state.m_stateHashes.m_vertex = m_hashes.m_vertex;
-
-	for(U i = 0; i < m_in.m_vertex.m_attributeCount; ++i)
-	{
-		const Attribute& attrib = m_cache.m_attribs[i];
-		ANKI_ASSERT(attrib.m_type);
-
-		glVertexAttribFormat(
-			i, attrib.m_compCount, attrib.m_type, attrib.m_normalized, m_in.m_vertex.m_attributes[i].m_offset);
-
-		glVertexAttribBinding(i, m_in.m_vertex.m_attributes[i].m_binding);
-	}
-
-	for(U i = 0; i < m_in.m_vertex.m_bindingCount; ++i)
-	{
-		ANKI_ASSERT(m_in.m_vertex.m_bindings[i].m_stride > 0);
-		state.m_vertexBindingStrides[i] = m_in.m_vertex.m_bindings[i].m_stride;
-	}
-
-	if(m_in.m_vertex.m_bindingCount)
-	{
-		state.m_vertBindingCount = m_in.m_vertex.m_bindingCount;
-		state.m_vertBindingsDirty = true;
-	}
-}
-
-void PipelineImpl::setInputAssemblerState(GlState& state) const
-{
-	if(state.m_stateHashes.m_inputAssembler == m_hashes.m_inputAssembler)
-	{
-		return;
-	}
-
-	state.m_stateHashes.m_inputAssembler = m_hashes.m_inputAssembler;
-
-	state.m_topology = m_cache.m_topology;
-
-	if(m_in.m_inputAssembler.m_primitiveRestartEnabled)
-	{
-		glEnable(GL_PRIMITIVE_RESTART);
-	}
-	else
-	{
-		glDisable(GL_PRIMITIVE_RESTART);
-	}
-}
-
-void PipelineImpl::setTessellationState(GlState& state) const
-{
-	if(!m_tessellation || state.m_stateHashes.m_tessellation == m_hashes.m_tessellation)
-	{
-		return;
-	}
-
-	state.m_stateHashes.m_tessellation = m_hashes.m_tessellation;
-
-	glPatchParameteri(GL_PATCH_VERTICES, m_in.m_tessellation.m_patchControlPointCount);
-}
-
-void PipelineImpl::setRasterizerState(GlState& state) const
-{
-	if(state.m_stateHashes.m_rasterizer == m_hashes.m_rasterizer)
-	{
-		return;
-	}
-
-	state.m_stateHashes.m_rasterizer = m_hashes.m_rasterizer;
-
-	glPolygonMode(GL_FRONT_AND_BACK, m_cache.m_fillMode);
-	glCullFace(m_cache.m_cullMode);
-	glEnable(GL_CULL_FACE);
-}
-
-void PipelineImpl::setDepthStencilState(GlState& state) const
-{
-	if(state.m_stateHashes.m_depthStencil == m_hashes.m_depthStencil)
-	{
-		return;
-	}
-
-	state.m_stateHashes.m_depthStencil = m_hashes.m_depthStencil;
-
-	// Depth
-	glDepthMask(m_in.m_depthStencil.m_depthWriteEnabled);
-	state.m_depthWriteMask = m_in.m_depthStencil.m_depthWriteEnabled;
-
-	if(m_cache.m_depthCompareFunction == GL_ALWAYS && !m_in.m_depthStencil.m_depthWriteEnabled)
-	{
-		glDisable(GL_DEPTH_TEST);
-	}
-	else
-	{
-		glEnable(GL_DEPTH_TEST);
-	}
-
-	glDepthFunc(m_cache.m_depthCompareFunction);
-
-	// Stencil
-	if(m_stencilTestEnabled)
-	{
-		glEnable(GL_STENCIL_TEST);
-	}
-	else
-	{
-		glDisable(GL_STENCIL_TEST);
-	}
-
-	glStencilOpSeparate(
-		GL_FRONT, m_cache.m_stencilFailOp[0], m_cache.m_stencilPassDepthFailOp[0], m_cache.m_stencilPassDepthPassOp[0]);
-
-	glStencilOpSeparate(
-		GL_BACK, m_cache.m_stencilFailOp[1], m_cache.m_stencilPassDepthFailOp[1], m_cache.m_stencilPassDepthPassOp[1]);
-
-	if(state.m_stencilCompareFunc[0] != m_cache.m_stencilCompareFunc[0])
-	{
-		state.m_stencilCompareFunc[0] = m_cache.m_stencilCompareFunc[0];
-		state.m_glStencilFuncSeparateDirtyMask |= 1 << 0;
-	}
-
-	if(state.m_stencilCompareFunc[1] != m_cache.m_stencilCompareFunc[1])
-	{
-		state.m_stencilCompareFunc[1] = m_cache.m_stencilCompareFunc[1];
-		state.m_glStencilFuncSeparateDirtyMask |= 1 << 1;
-	}
-}
-
-void PipelineImpl::setColorState(GlState& state) const
-{
-	if(state.m_stateHashes.m_color == m_hashes.m_color)
-	{
-		return;
-	}
-
-	state.m_stateHashes.m_color = m_hashes.m_color;
-
-	if(m_blendEnabled)
-	{
-		glEnable(GL_BLEND);
-
-		for(U i = 0; i < m_in.m_color.m_attachmentCount; ++i)
-		{
-			const Attachment& att = m_cache.m_attachments[i];
-
-			glBlendFunci(i, att.m_srcBlendMethod, att.m_dstBlendMethod);
-			glBlendEquationi(i, att.m_blendFunction);
-			glColorMaski(i,
-				att.m_channelWriteMask[0],
-				att.m_channelWriteMask[1],
-				att.m_channelWriteMask[2],
-				att.m_channelWriteMask[3]);
-
-			state.m_colorWriteMasks[i][0] = att.m_channelWriteMask[0];
-			state.m_colorWriteMasks[i][1] = att.m_channelWriteMask[1];
-			state.m_colorWriteMasks[i][2] = att.m_channelWriteMask[2];
-			state.m_colorWriteMasks[i][3] = att.m_channelWriteMask[3];
-		}
-	}
-	else
-	{
-		glDisable(GL_BLEND);
-
-		for(U i = 0; i < m_in.m_color.m_attachmentCount; ++i)
-		{
-			const Attachment& att = m_cache.m_attachments[i];
-
-			glColorMaski(i,
-				att.m_channelWriteMask[0],
-				att.m_channelWriteMask[1],
-				att.m_channelWriteMask[2],
-				att.m_channelWriteMask[3]);
-
-			state.m_colorWriteMasks[i][0] = att.m_channelWriteMask[0];
-			state.m_colorWriteMasks[i][1] = att.m_channelWriteMask[1];
-			state.m_colorWriteMasks[i][2] = att.m_channelWriteMask[2];
-			state.m_colorWriteMasks[i][3] = att.m_channelWriteMask[3];
-		}
-	}
-}
-
-} // end namespace anki

+ 0 - 112
src/anki/gr/gl/PipelineImpl.h

@@ -1,112 +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/gr/gl/GlObject.h>
-#include <anki/gr/Pipeline.h>
-
-namespace anki
-{
-
-/// @addtogroup opengl
-/// @{
-
-/// Program pipeline
-class PipelineImpl : public GlObject
-{
-public:
-	PipelineImpl(GrManager* manager)
-		: GlObject(manager)
-	{
-	}
-
-	~PipelineImpl();
-
-	ANKI_USE_RESULT Error init(const PipelineInitInfo& init);
-
-	/// Bind the pipeline to the state
-	void bind(GlState& state);
-
-private:
-	class Attribute
-	{
-	public:
-		GLenum m_type = 0;
-		U8 m_compCount = 0;
-		Bool8 m_normalized = false;
-	};
-
-	class Attachment
-	{
-	public:
-		GLenum m_srcBlendMethod = GL_ONE;
-		GLenum m_dstBlendMethod = GL_ZERO;
-		GLenum m_blendFunction = GL_ADD;
-		Array<Bool8, 4> m_channelWriteMask;
-	};
-
-	Bool8 m_compute = false; ///< Is compute
-	Bool8 m_tessellation = false;
-	Bool8 m_blendEnabled = false;
-	Bool8 m_stencilTestEnabled = false;
-
-	/// Input values.
-	PipelineInitInfo m_in;
-
-	/// Cached values.
-	class
-	{
-	public:
-		Array<Attribute, MAX_VERTEX_ATTRIBUTES> m_attribs;
-		GLenum m_topology = 0;
-		GLenum m_fillMode = 0;
-		GLenum m_cullMode = 0;
-		Bool8 m_depthWrite = false;
-		GLenum m_depthCompareFunction = 0;
-		Array<Attachment, MAX_COLOR_ATTACHMENTS> m_attachments;
-
-		Array<GLenum, 2> m_stencilFailOp = {{0, 0}};
-		Array<GLenum, 2> m_stencilPassDepthFailOp = {{0, 0}};
-		Array<GLenum, 2> m_stencilPassDepthPassOp = {{0, 0}};
-		Array<GLenum, 2> m_stencilCompareFunc = {{0, 0}};
-	} m_cache;
-
-	/// State hashes.
-	class
-	{
-	public:
-		U64 m_vertex = 0;
-		U64 m_inputAssembler = 0;
-		U64 m_tessellation = 0;
-		U64 m_viewport = 0;
-		U64 m_rasterizer = 0;
-		U64 m_depthStencil = 0;
-		U64 m_color = 0;
-	} m_hashes;
-
-	/// Attach all the programs
-	ANKI_USE_RESULT Error createGlPipeline();
-
-	void initVertexState();
-	void initInputAssemblerState();
-	void initTessellationState();
-	void initRasterizerState();
-	void initDepthStencilState();
-	void initColorState();
-
-	void setVertexState(GlState& state) const;
-	void setInputAssemblerState(GlState& state) const;
-	void setTessellationState(GlState& state) const;
-	void setViewportState(GlState& state) const
-	{
-	}
-	void setRasterizerState(GlState& state) const;
-	void setDepthStencilState(GlState& state) const;
-	void setColorState(GlState& state) const;
-};
-/// @}
-
-} // end namespace anki

+ 0 - 64
src/anki/gr/gl/ResourceGroup.cpp

@@ -1,64 +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/gr/ResourceGroup.h>
-#include <anki/gr/gl/ResourceGroupImpl.h>
-#include <anki/gr/GrManager.h>
-#include <anki/gr/gl/CommandBufferImpl.h>
-#include <anki/gr/Texture.h>
-#include <anki/gr/Sampler.h>
-#include <anki/gr/Buffer.h>
-
-namespace anki
-{
-
-ResourceGroup::ResourceGroup(GrManager* manager, U64 hash, GrObjectCache* cache)
-	: GrObject(manager, CLASS_TYPE, hash, cache)
-{
-}
-
-ResourceGroup::~ResourceGroup()
-{
-}
-
-class RcgCreateCommand final : public GlCommand
-{
-public:
-	ResourceGroupPtr m_ptr;
-	ResourceGroupInitInfo m_init;
-
-	RcgCreateCommand(ResourceGroup* ptr, const ResourceGroupInitInfo& init)
-		: m_ptr(ptr)
-		, m_init(init)
-	{
-	}
-
-	Error operator()(GlState&)
-	{
-		ResourceGroupImpl& impl = *m_ptr->m_impl;
-
-		impl.init(m_init);
-
-		GlObject::State oldState = impl.setStateAtomically(GlObject::State::CREATED);
-
-		(void)oldState;
-		ANKI_ASSERT(oldState == GlObject::State::TO_BE_CREATED);
-
-		return ErrorCode::NONE;
-	}
-};
-
-void ResourceGroup::init(const ResourceGroupInitInfo& init)
-{
-	// NOTE: Create asynchronously because the initialization touches GL names
-	m_impl.reset(getAllocator().newInstance<ResourceGroupImpl>(&getManager()));
-
-	CommandBufferPtr cmdb = getManager().newInstance<CommandBuffer>(CommandBufferInitInfo());
-
-	cmdb->m_impl->pushBackNewCommand<RcgCreateCommand>(this, init);
-	cmdb->flush();
-}
-
-} // end namespace anki

+ 0 - 384
src/anki/gr/gl/ResourceGroupImpl.cpp

@@ -1,384 +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/gr/gl/ResourceGroupImpl.h>
-#include <anki/gr/gl/TextureImpl.h>
-#include <anki/gr/Texture.h>
-#include <anki/gr/gl/SamplerImpl.h>
-#include <anki/gr/Sampler.h>
-#include <anki/gr/gl/BufferImpl.h>
-#include <anki/gr/Buffer.h>
-#include <anki/gr/gl/GlState.h>
-#include <anki/gr/gl/GrManagerImpl.h>
-#include <anki/gr/GrManager.h>
-#include <anki/gr/gl/RenderingThread.h>
-#include <anki/gr/gl/CommandBufferImpl.h>
-#include <anki/gr/gl/TransientMemoryManager.h>
-
-namespace anki
-{
-
-template<typename InBindings, typename OutBindings>
-void ResourceGroupImpl::initBuffers(const InBindings& in, OutBindings& out, U8& count, U& resourcesCount, U& transCount)
-{
-	count = 0;
-
-	for(U i = 0; i < in.getSize(); ++i)
-	{
-		const BufferBinding& binding = in[i];
-
-		if(binding.m_buffer.isCreated())
-		{
-			ANKI_ASSERT(binding.m_uploadedMemory == false);
-
-			const BufferImpl& buff = *binding.m_buffer->m_impl;
-			InternalBufferBinding& outBinding = out[count];
-
-			outBinding.m_name = buff.getGlName();
-			outBinding.m_offset = binding.m_offset;
-			outBinding.m_range = (binding.m_range != 0) ? binding.m_range : (buff.m_size - binding.m_offset);
-
-			ANKI_ASSERT(outBinding.m_offset + outBinding.m_range <= buff.m_size);
-			ANKI_ASSERT(outBinding.m_range > 0);
-
-			++resourcesCount;
-			count = i + 1;
-		}
-		else if(binding.m_uploadedMemory)
-		{
-			InternalBufferBinding& outBinding = out[count];
-			outBinding.m_name = MAX_U32;
-			++transCount;
-			count = i + 1;
-		}
-	}
-}
-
-void ResourceGroupImpl::init(const ResourceGroupInitInfo& init)
-{
-	U resourcesCount = 0;
-	U transCount = 0;
-
-	// Init textures & samplers
-	m_textureNamesCount = 0;
-	m_allSamplersZero = true;
-	for(U i = 0; i < init.m_textures.getSize(); ++i)
-	{
-		if(init.m_textures[i].m_texture.isCreated())
-		{
-			m_textureNames[i] = init.m_textures[i].m_texture->m_impl->getGlName();
-			m_textureNamesCount = i + 1;
-			++resourcesCount;
-		}
-		else
-		{
-			m_textureNames[i] = 0;
-		}
-
-		if(init.m_textures[i].m_sampler.isCreated())
-		{
-			m_samplerNames[i] = init.m_textures[i].m_sampler->m_impl->getGlName();
-			m_allSamplersZero = false;
-			++resourcesCount;
-		}
-		else
-		{
-			m_samplerNames[i] = 0;
-		}
-	}
-
-	// Init shader buffers
-	initBuffers(init.m_uniformBuffers, m_ubos, m_ubosCount, resourcesCount, transCount);
-	initBuffers(init.m_storageBuffers, m_ssbos, m_ssbosCount, resourcesCount, transCount);
-
-	// Init images
-	for(U i = 0; i < MAX_IMAGE_BINDINGS; ++i)
-	{
-		const auto& in = init.m_images[i];
-		if(in.m_texture)
-		{
-			TextureImpl& impl = *in.m_texture->m_impl;
-			impl.checkSurface(TextureSurfaceInfo(in.m_level, 0, 0, 0));
-
-			ImageBinding& out = m_images[i];
-
-			out.m_name = in.m_texture->m_impl->getGlName();
-			out.m_level = in.m_level;
-			out.m_format = impl.m_internalFormat;
-
-			++m_imageCount;
-			++resourcesCount;
-		}
-	}
-
-	// Init vert buffers
-	m_vertBindingsCount = 0;
-	for(U i = 0; i < init.m_vertexBuffers.getSize(); ++i)
-	{
-		const BufferBinding& binding = init.m_vertexBuffers[i];
-		if(binding.m_buffer.isCreated())
-		{
-			ANKI_ASSERT(!binding.m_uploadedMemory);
-
-			m_vertBuffNames[i] = binding.m_buffer->m_impl->getGlName();
-			m_vertBuffOffsets[i] = binding.m_offset;
-
-			++m_vertBindingsCount;
-			++resourcesCount;
-		}
-		else if(binding.m_uploadedMemory)
-		{
-			++transCount;
-
-			m_vertBuffNames[i] = 0;
-			m_vertBuffOffsets[i] = MAX_U32;
-
-			++m_vertBindingsCount;
-			m_hasTransientVertexBuff = true;
-		}
-		else
-		{
-			m_vertBuffNames[i] = 0;
-			m_vertBuffOffsets[i] = 0;
-		}
-	}
-
-	// Init index buffer
-	if(init.m_indexBuffer.m_buffer.isCreated())
-	{
-		const BufferImpl& buff = *init.m_indexBuffer.m_buffer->m_impl;
-
-		ANKI_ASSERT(init.m_indexSize == 2 || init.m_indexSize == 4);
-
-		m_indexBuffName = buff.getGlName();
-		m_indexSize = init.m_indexSize;
-		++resourcesCount;
-	}
-
-	ANKI_ASSERT((resourcesCount > 0 || transCount > 0) && "Resource group empty");
-
-	// Hold references
-	initResourceReferences(init, resourcesCount);
-}
-
-void ResourceGroupImpl::initResourceReferences(const ResourceGroupInitInfo& init, U refCount)
-{
-	m_refs.create(getAllocator(), refCount);
-
-	U count = 0;
-
-	for(U i = 0; i < init.m_textures.getSize(); ++i)
-	{
-		if(init.m_textures[i].m_texture.isCreated())
-		{
-			m_refs[count++] = init.m_textures[i].m_texture;
-		}
-
-		if(init.m_textures[i].m_sampler.isCreated())
-		{
-			m_refs[count++] = init.m_textures[i].m_sampler;
-		}
-	}
-
-	for(U i = 0; i < init.m_uniformBuffers.getSize(); ++i)
-	{
-		const BufferBinding& binding = init.m_uniformBuffers[i];
-		if(binding.m_buffer.isCreated())
-		{
-			m_refs[count++] = binding.m_buffer;
-		}
-	}
-
-	for(U i = 0; i < init.m_storageBuffers.getSize(); ++i)
-	{
-		const BufferBinding& binding = init.m_storageBuffers[i];
-		if(binding.m_buffer.isCreated())
-		{
-			m_refs[count++] = binding.m_buffer;
-		}
-	}
-
-	for(U i = 0; i < MAX_IMAGE_BINDINGS; ++i)
-	{
-		const auto& binding = init.m_images[i];
-		if(binding.m_texture)
-		{
-			m_refs[count++] = binding.m_texture;
-		}
-	}
-
-	for(U i = 0; i < init.m_vertexBuffers.getSize(); ++i)
-	{
-		const BufferBinding& binding = init.m_vertexBuffers[i];
-		if(binding.m_buffer.isCreated())
-		{
-			m_refs[count++] = binding.m_buffer;
-		}
-	}
-
-	if(init.m_indexBuffer.m_buffer.isCreated())
-	{
-		m_refs[count++] = init.m_indexBuffer.m_buffer;
-	}
-
-	ANKI_ASSERT(refCount == count);
-}
-
-void ResourceGroupImpl::bind(U slot, const TransientMemoryInfo& transientInfo, GlState& state)
-{
-	ANKI_ASSERT(slot < MAX_BOUND_RESOURCE_GROUPS);
-
-	// Bind textures
-	if(m_textureNamesCount)
-	{
-		glBindTextures(MAX_TEXTURE_BINDINGS * slot, m_textureNamesCount, &m_textureNames[0]);
-
-		if(m_allSamplersZero)
-		{
-			glBindSamplers(MAX_TEXTURE_BINDINGS * slot, m_textureNamesCount, nullptr);
-		}
-		else
-		{
-			glBindSamplers(MAX_TEXTURE_BINDINGS * slot, m_textureNamesCount, &m_samplerNames[0]);
-		}
-	}
-
-	// Uniform buffers
-	for(U i = 0; i < m_ubosCount; ++i)
-	{
-		const auto& binding = m_ubos[i];
-		if(binding.m_name == MAX_U32)
-		{
-			// Transient
-			TransientMemoryToken token = transientInfo.m_uniformBuffers[i];
-			ANKI_ASSERT(token.m_range != 0);
-
-			if(!token.isUnused())
-			{
-				glBindBufferRange(GL_UNIFORM_BUFFER,
-					MAX_UNIFORM_BUFFER_BINDINGS * slot + i,
-					getManager().getImplementation().getTransientMemoryManager().getGlName(token),
-					token.m_offset,
-					token.m_range);
-			}
-			else
-			{
-				// It's unused
-			}
-		}
-		else if(binding.m_name != 0)
-		{
-			// Static
-			glBindBufferRange(GL_UNIFORM_BUFFER,
-				MAX_UNIFORM_BUFFER_BINDINGS * slot + i,
-				binding.m_name,
-				binding.m_offset,
-				binding.m_range);
-		}
-	}
-
-	// Storage buffers
-	for(U i = 0; i < m_ssbosCount; ++i)
-	{
-		const auto& binding = m_ssbos[i];
-		if(binding.m_name == MAX_U32)
-		{
-			// Transient
-			TransientMemoryToken token = transientInfo.m_storageBuffers[i];
-			ANKI_ASSERT(token.m_range != 0);
-
-			if(!token.isUnused())
-			{
-				glBindBufferRange(GL_SHADER_STORAGE_BUFFER,
-					MAX_STORAGE_BUFFER_BINDINGS * slot + i,
-					getManager().getImplementation().getTransientMemoryManager().getGlName(token),
-					token.m_offset,
-					token.m_range);
-			}
-			else
-			{
-				// It's unused
-			}
-		}
-		else if(binding.m_name != 0)
-		{
-			// Static
-			glBindBufferRange(GL_SHADER_STORAGE_BUFFER,
-				MAX_STORAGE_BUFFER_BINDINGS * slot + i,
-				binding.m_name,
-				binding.m_offset,
-				binding.m_range);
-		}
-	}
-
-	// Images
-	for(U i = 0; i < m_imageCount; ++i)
-	{
-		const ImageBinding& binding = m_images[i];
-		if(binding.m_name)
-		{
-			glBindImageTexture(MAX_IMAGE_BINDINGS * slot + i,
-				binding.m_name,
-				binding.m_level,
-				GL_TRUE,
-				0,
-				GL_READ_WRITE,
-				binding.m_format);
-		}
-	}
-
-	// Vertex buffers
-	if(m_vertBindingsCount)
-	{
-		ANKI_ASSERT(slot == 0 && "Only slot 0 can have vertex buffers");
-
-		if(!m_hasTransientVertexBuff)
-		{
-			memcpy(
-				&state.m_vertBuffOffsets[0], &m_vertBuffOffsets[0], sizeof(m_vertBuffOffsets[0]) * m_vertBindingsCount);
-
-			memcpy(&state.m_vertBuffNames[0], &m_vertBuffNames[0], sizeof(m_vertBuffNames[0]) * m_vertBindingsCount);
-		}
-		else
-		{
-			Array<GLintptr, MAX_VERTEX_ATTRIBUTES> offsets = m_vertBuffOffsets;
-			Array<GLuint, MAX_VERTEX_ATTRIBUTES> names = m_vertBuffNames;
-			const TransientMemoryManager& transManager = getManager().getImplementation().getTransientMemoryManager();
-
-			for(U i = 0; i < MAX_VERTEX_ATTRIBUTES; ++i)
-			{
-				if(offsets[i] == MAX_U32)
-				{
-					// It's dynamic
-					ANKI_ASSERT(transientInfo.m_vertexBuffers[i].m_range != 0);
-					offsets[i] = transientInfo.m_vertexBuffers[i].m_offset;
-					names[i] = transManager.getGlName(transientInfo.m_vertexBuffers[i]);
-				}
-				else
-				{
-					ANKI_ASSERT(transientInfo.m_vertexBuffers[i].m_range == 0);
-				}
-			}
-
-			// Bind to state
-			memcpy(&state.m_vertBuffOffsets[0], &offsets[0], sizeof(offsets[0]) * m_vertBindingsCount);
-
-			memcpy(&state.m_vertBuffNames[0], &names[0], sizeof(names[0]) * m_vertBindingsCount);
-		}
-
-		state.m_vertBindingCount = m_vertBindingsCount;
-		state.m_vertBindingsDirty = true;
-	}
-
-	// Index buffer
-	if(m_indexSize > 0)
-	{
-		ANKI_ASSERT(slot == 0 && "Only slot 0 can have index buffers");
-		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBuffName);
-		state.m_indexSize = m_indexSize;
-	}
-}
-
-} // end namespace anki

+ 0 - 86
src/anki/gr/gl/ResourceGroupImpl.h

@@ -1,86 +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/gr/gl/GlObject.h>
-#include <anki/gr/ResourceGroup.h>
-#include <anki/util/DynamicArray.h>
-
-namespace anki
-{
-
-/// @addtogroup opengl
-/// @{
-
-/// Resource group implementation.
-class ResourceGroupImpl : public GlObject
-{
-public:
-	ResourceGroupImpl(GrManager* manager)
-		: GlObject(manager)
-	{
-	}
-
-	~ResourceGroupImpl()
-	{
-		m_refs.destroy(getAllocator());
-	}
-
-	void init(const ResourceGroupInitInfo& init);
-
-	/// Set state.
-	void bind(U slot, const TransientMemoryInfo& transientInfo, GlState& state);
-
-private:
-	class InternalBufferBinding
-	{
-	public:
-		GLuint m_name = 0; ///< If it's MAX_U32 then it's transient
-		U32 m_offset = 0;
-		U32 m_range = 0;
-	};
-
-	class ImageBinding
-	{
-	public:
-		GLuint m_name = 0;
-		U16 m_level = 0;
-		GLenum m_format = GL_NONE;
-	};
-
-	Array<GLuint, MAX_TEXTURE_BINDINGS> m_textureNames;
-	Array<GLuint, MAX_TEXTURE_BINDINGS> m_samplerNames;
-	U8 m_textureNamesCount = 0;
-	Bool8 m_allSamplersZero = false;
-
-	Array<InternalBufferBinding, MAX_UNIFORM_BUFFER_BINDINGS> m_ubos;
-	U8 m_ubosCount = 0;
-
-	Array<InternalBufferBinding, MAX_STORAGE_BUFFER_BINDINGS> m_ssbos;
-	U8 m_ssbosCount = 0;
-
-	Array<ImageBinding, MAX_IMAGE_BINDINGS> m_images;
-	U8 m_imageCount = 0;
-
-	Array<GLuint, MAX_VERTEX_ATTRIBUTES> m_vertBuffNames;
-	Array<GLintptr, MAX_VERTEX_ATTRIBUTES> m_vertBuffOffsets;
-	Bool8 m_hasTransientVertexBuff = false;
-	U8 m_vertBindingsCount = 0;
-
-	GLuint m_indexBuffName = 0;
-	U8 m_indexSize = 0;
-
-	/// Holds the references to the resources. Used to release the references gracefully.
-	DynamicArray<GrObjectPtr<GrObject>> m_refs;
-
-	template<typename InBindings, typename OutBindings>
-	void initBuffers(const InBindings& in, OutBindings& out, U8& count, U& resourcesCount, U& transCount);
-
-	void initResourceReferences(const ResourceGroupInitInfo& init, U count);
-};
-/// @}
-
-} // end namespace anki

+ 95 - 5
src/anki/gr/gl/StateTracker.h

@@ -7,6 +7,8 @@
 
 #include <anki/gr/gl/Common.h>
 #include <anki/gr/ShaderProgram.h>
+#include <anki/gr/Framebuffer.h>
+#include <anki/gr/gl/FramebufferImpl.h>
 
 namespace anki
 {
@@ -65,7 +67,7 @@ public:
 
 	/// @name viewport_state
 	/// @{
-	Array<U16, 4> m_viewport = {{0, 0, 0, 0}};
+	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)
@@ -177,10 +179,14 @@ public:
 		}
 	}
 
-	Array<U32, 2> m_stencilCompareMask = {{0x969696, 0x969696}};
+	static const U32 DUMMY_STENCIL_MASK = 0x969696;
+
+	Array<U32, 2> m_stencilCompareMask = {{DUMMY_STENCIL_MASK, DUMMY_STENCIL_MASK}};
 
 	void setStencilCompareMask(FaceSelectionMask face, U32 mask)
 	{
+		ANKI_ASSERT(mask != DUMMY_STENCIL_MASK && "Oops");
+
 		if(!!(face & FaceSelectionMask::FRONT) && m_stencilCompareMask[0] != mask)
 		{
 			m_stencilCompareMask[0] = mask;
@@ -194,11 +200,13 @@ public:
 		}
 	}
 
-	Array<U32, 2> m_stencilWriteMask = {{0x969696, 0x969696}};
+	Array<U32, 2> m_stencilWriteMask = {{DUMMY_STENCIL_MASK, DUMMY_STENCIL_MASK}};
 
 	template<typename TFunc>
 	void setStencilWriteMask(FaceSelectionMask face, U32 mask, TFunc func)
 	{
+		ANKI_ASSERT(mask != DUMMY_STENCIL_MASK && "Oops");
+
 		Bool changed = false;
 		if(!!(face & FaceSelectionMask::FRONT) && m_stencilWriteMask[0] != mask)
 		{
@@ -218,10 +226,12 @@ public:
 		}
 	}
 
-	Array<U32, 2> m_stencilRef = {{0x969696, 0x969696}};
+	Array<U32, 2> m_stencilRef = {{DUMMY_STENCIL_MASK, DUMMY_STENCIL_MASK}};
 
 	void setStencilReference(FaceSelectionMask face, U32 mask)
 	{
+		ANKI_ASSERT(mask != DUMMY_STENCIL_MASK && "Oops");
+
 		if(!!(face & FaceSelectionMask::FRONT) && m_stencilRef[0] != mask)
 		{
 			m_stencilRef[0] = mask;
@@ -306,7 +316,7 @@ public:
 	}
 	/// @}
 
-	/// @resources
+	/// @name resources
 	/// @{
 	U64 m_progUuid = MAX_U64;
 
@@ -320,6 +330,86 @@ public:
 		}
 	}
 	/// @}
+
+	/// @name other
+	/// @{
+	U64 m_fbUuid = MAX_U64;
+	U8 m_colorBuffCount = MAX_U8;
+	Bool8 m_fbHasDepth = 2;
+	Bool8 m_fbHasStencil = 2;
+
+	template<typename TFunc>
+	void beginRenderPass(const FramebufferPtr& fb, TFunc func)
+	{
+		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();
+	}
+
+	void endRenderPass()
+	{
+		m_fbUuid = MAX_U64;
+	}
+	/// @}
+
+	/// @name drawcalls
+	/// @{
+	void checkIndexedDracall() const
+	{
+		ANKI_ASSERT(m_indexType != 0 && "Forgot to bind index buffer");
+		checkDrawcall();
+	}
+
+	void checkNonIndexedDrawcall() const
+	{
+		checkDrawcall();
+	}
+
+	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_fillMode != FillMode::COUNT && "Forgot to set fill mode");
+		ANKI_ASSERT(m_cullMode != static_cast<FaceSelectionMask>(0) && "Forgot to set cull mode");
+
+		for(U i = 0; i < m_colorBuffCount; ++i)
+		{
+			ANKI_ASSERT(m_colorWriteMasks[i] != INVALID_COLOR_MASK && "Forgot to set the color write mask");
+			ANKI_ASSERT(m_blendSrcMethod[i] != BlendMethod::COUNT && "Forgot to set blend methods");
+			ANKI_ASSERT(m_blendFuncs[i] != BlendFunction::COUNT && "Forgot to set blend functions");
+		}
+
+		if(m_fbHasDepth)
+		{
+			ANKI_ASSERT(m_depthWrite != 2 && "Forgot to set depth write");
+			ANKI_ASSERT(m_depthOp != CompareOperation::COUNT && "Forgot to set depth compare function");
+		}
+
+		if(m_fbHasStencil)
+		{
+			for(U i = 0; i < 2; ++i)
+			{
+				ANKI_ASSERT(m_stencilFail[i] != StencilOperation::COUNT && "Forgot to set stencil ops");
+				ANKI_ASSERT(m_stencilCompare[i] != CompareOperation::COUNT && "Forgot to set stencil compare");
+				ANKI_ASSERT(m_stencilCompareMask[i] != DUMMY_STENCIL_MASK && "Forgot to set stencil compare mask");
+				ANKI_ASSERT(m_stencilWriteMask[i] != DUMMY_STENCIL_MASK && "Forgot to set stencil write mask");
+				ANKI_ASSERT(m_stencilRef[i] != DUMMY_STENCIL_MASK && "Forgot to set stencil ref mask");
+			}
+		}
+	}
+
+	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");
+	}
+	/// @}
 };
 /// @}