ソースを参照

Move state to the graphics pipeline

Panagiotis Christopoulos Charitos 10 年 前
コミット
57b5f17d05
84 ファイル変更1143 行追加2319 行削除
  1. 3 1
      include/anki/Config.h.cmake
  2. 7 68
      include/anki/gr/CommandBufferPtr.h
  3. 27 20
      include/anki/gr/PipelineCommon.h
  4. 1 4
      include/anki/gr/PipelinePtr.h
  5. 17 7
      include/anki/gr/gl/GlState.h
  6. 30 24
      include/anki/gr/gl/PipelineImpl.h
  7. 1 1
      include/anki/gr/gl/RenderingThread.h
  8. 3 5
      include/anki/renderer/Bloom.h
  9. 0 15
      include/anki/renderer/Common.h
  10. 1 1
      include/anki/renderer/Dbg.h
  11. 7 9
      include/anki/renderer/DebugDrawer.h
  12. 1 3
      include/anki/renderer/Drawer.h
  13. 0 36
      include/anki/renderer/Ez.h
  14. 2 4
      include/anki/renderer/Fs.h
  15. 2 8
      include/anki/renderer/Is.h
  16. 4 6
      include/anki/renderer/Lf.h
  17. 1 5
      include/anki/renderer/MainRenderer.h
  18. 6 8
      include/anki/renderer/Ms.h
  19. 2 0
      include/anki/renderer/Pps.h
  20. 4 6
      include/anki/renderer/Renderer.h
  21. 1 36
      include/anki/renderer/RenderingPass.h
  22. 30 26
      include/anki/renderer/Sm.h
  23. 3 3
      include/anki/renderer/Ssao.h
  24. 2 5
      include/anki/renderer/Sslf.h
  25. 5 6
      include/anki/renderer/Sslr.h
  26. 4 6
      include/anki/renderer/Tiler.h
  27. 2 4
      include/anki/renderer/Tm.h
  28. 1 3
      include/anki/resource/Animation.h
  29. 1 4
      include/anki/resource/AsyncLoader.h
  30. 1 4
      include/anki/resource/CollisionResource.h
  31. 1 3
      include/anki/resource/DummyRsrc.h
  32. 1 4
      include/anki/resource/Forward.h
  33. 31 101
      include/anki/resource/Material.h
  34. 0 35
      include/anki/resource/MaterialCommon.h
  35. 7 9
      include/anki/resource/MaterialProgramCreator.h
  36. 11 38
      include/anki/resource/Mesh.h
  37. 29 67
      include/anki/resource/Model.h
  38. 11 0
      include/anki/resource/ParticleEmitterResource.h
  39. 13 13
      include/anki/resource/RenderingKey.h
  40. 14 27
      include/anki/resource/ResourceManager.h
  41. 1 4
      include/anki/resource/ResourceObject.h
  42. 1 3
      include/anki/resource/ShaderResource.h
  43. 2 4
      include/anki/resource/Skin.h
  44. 4 6
      include/anki/scene/ModelNode.h
  45. 7 7
      include/anki/scene/RenderComponent.h
  46. 1 3
      include/anki/scene/SceneNode.h
  47. 3 5
      include/anki/scene/StaticGeometryNode.h
  48. 1 1
      include/anki/util/Allocator.h
  49. 11 9
      include/anki/util/Array.h
  50. 18 20
      include/anki/util/DArray.h
  51. 9 6
      shaders/IsLp.vert.glsl
  52. 10 4
      shaders/LfSpritePass.vert.glsl
  53. 10 7
      shaders/Quad.vert.glsl
  54. 68 151
      src/gr/gl/CommandBufferPtr.cpp
  55. 3 1
      src/gr/gl/GlState.cpp
  56. 141 183
      src/gr/gl/PipelineImpl.cpp
  57. 18 11
      src/renderer/Bloom.cpp
  58. 1 10
      src/renderer/Dbg.cpp
  59. 24 10
      src/renderer/DebugDrawer.cpp
  60. 4 42
      src/renderer/Drawer.cpp
  61. 0 57
      src/renderer/Ez.cpp
  62. 1 7
      src/renderer/Fs.cpp
  63. 25 26
      src/renderer/Is.cpp
  64. 37 15
      src/renderer/Lf.cpp
  65. 8 17
      src/renderer/MainRenderer.cpp
  66. 17 31
      src/renderer/Ms.cpp
  67. 9 3
      src/renderer/Pps.cpp
  68. 14 16
      src/renderer/Renderer.cpp
  69. 0 72
      src/renderer/RenderingPass.cpp
  70. 6 17
      src/renderer/Sm.cpp
  71. 15 8
      src/renderer/Ssao.cpp
  72. 9 3
      src/renderer/Sslf.cpp
  73. 27 41
      src/renderer/Sslr.cpp
  74. 1 1
      src/renderer/Tiler.cpp
  75. 25 274
      src/resource/Material.cpp
  76. 0 30
      src/resource/MaterialCommon.cpp
  77. 3 213
      src/resource/Mesh.cpp
  78. 186 250
      src/resource/Model.cpp
  79. 41 0
      src/resource/ParticleEmitterResource.cpp
  80. 1 0
      src/resource/ResourceFilesystem.cpp
  81. 36 33
      src/scene/ModelNode.cpp
  82. 17 40
      src/scene/ParticleEmitter.cpp
  83. 41 50
      src/scene/StaticGeometryNode.cpp
  84. 0 3
      src/util/Assert.cpp

+ 3 - 1
include/anki/Config.h.cmake

@@ -12,7 +12,7 @@
 #define ANKI_ASSERTIONS ANKI_DEBUG
 
 // Operating system
-#define ANKI_OS_LINUX 1 
+#define ANKI_OS_LINUX 1
 #define ANKI_OS_ANDROID 2
 #define ANKI_OS_MACOS 3
 #define ANKI_OS_IOS 4
@@ -145,11 +145,13 @@
 #	define ANKI_UNLIKELY(x) __builtin_expect((x), 0)
 #	define ANKI_RESTRICT __restrict
 #	define ANKI_USE_RESULT __attribute__((warn_unused_result))
+#	define ANKI_FORCE_INLINE __attribute__((always_inline))
 #else
 #	define ANKI_LIKELY(x) ((x) == 1)
 #	define ANKI_UNLIKELY(x) ((x) == 1)
 #	define ANKI_RESTRICT
 #	define ANKI_USE_RESULT
+#	define ANKI_FORCE_INLINE
 #endif
 /// @}
 

+ 7 - 68
include/anki/gr/CommandBufferPtr.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_GR_COMMAND_BUFFER_HANDLE_H
-#define ANKI_GR_COMMAND_BUFFER_HANDLE_H
+#pragma once
 
 #include "anki/gr/GrPtr.h"
 
@@ -49,72 +48,14 @@ public:
 	/// @name State manipulation
 	/// @{
 
-	/// Set the viewport
-	void setViewport(U16 minx, U16 miny, U16 maxx, U16 maxy);
-
-	/// Set the color mask
-	void setColorWriteMask(Bool red, Bool green, Bool blue, Bool alpha);
-
-	/// Enable/disable depth test
-	void enableDepthTest(Bool enable);
-
-	/// Set depth compare function
-	void setDepthFunction(GLenum func);
-
-	/// Set depth write mask
-	void setDepthWriteMask(Bool write);
-
-	/// Enable or note stencil test
-	void enableStencilTest(Bool enable);
-
-	/// Set stencil function. Equivalent to glStencilFunc
-	void setStencilFunction(GLenum function, U32 reference, U32 mask);
-
-	/// Set the stencil mask. Equivalent to glStencilMask
-	void setStencilPlaneMask(U32 mask);
-
-	/// Set the operations of stencil fail, depth fail, depth pass. Equivalent
-	/// to glStencilOp
-	void setStencilOperations(GLenum stencFail, GLenum depthFail,
-		GLenum depthPass);
-
-	/// Enable or not blending. Equivalent to glEnable/glDisable(GL_BLEND)
-	void enableBlend(Bool enable);
-
-	/// Set blend equation. Equivalent to glBlendEquation
-	void setBlendEquation(GLenum equation);
+	/// Bind vertex buffer.
+	void bindVertexBuffer(U32 bindingPoint, BufferPtr buff, PtrSize offset);
 
-	/// Set the blend functions. Equivalent to glBlendFunc
-	void setBlendFunctions(GLenum sfactor, GLenum dfactor);
+	/// Bind index buffer.
+	void bindIndexBuffer(BufferPtr buff, U32 indexSize);
 
-	/// Set the blend color. Equivalent to glBlendColor
-	void setBlendColor(F32 r, F32 g, F32 b, F32 a);
-
-	/// Enable primitive restart
-	void enablePrimitiveRestart(Bool enable);
-
-	/// Set patch number of vertices
-	void setPatchVertexCount(U32 count);
-
-	/// Enable or not face culling. Equal to glEnable(GL_CULL_FASE)
-	void enableCulling(Bool enable);
-
-	/// Set the faces to cull. Works when culling is enabled. Equal to
-	/// glCullFace(x)
-	void setCullFace(GLenum mode);
-
-	/// Set the polygon offset. Equal to glPolygonOffset() plus
-	/// glEnable(GL_POLYGON_OFFSET_FILL)
-	void setPolygonOffset(F32 factor, F32 units);
-
-	/// Enable/disable polygon offset
-	void enablePolygonOffset(Bool enable);
-
-	/// Set polygon mode
-	void setPolygonMode(GLenum face, GLenum mode);
-
-	/// Enable/diable point size in vertex/geometry shaders.
-	void enablePointSize(Bool enable);
+	/// Set the viewport
+	void setViewport(U16 minx, U16 miny, U16 maxx, U16 maxy);
 
 	/// Bind many textures
 	/// @param first The unit where the first texture will be bound.
@@ -153,5 +94,3 @@ public:
 
 } // end namespace anki
 
-#endif
-

+ 27 - 20
include/anki/gr/PipelineCommon.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_GR_PIPELINE_COMMON_H
-#define ANKI_GR_PIPELINE_COMMON_H
+#pragma once
 
 #include "anki/gr/Common.h"
 #include "anki/gr/ShaderPtr.h"
@@ -15,58 +14,69 @@ namespace anki {
 /// @addtogroup graphics
 /// @{
 
-struct VertexBinding
+class VertexBinding
 {
+public:
 	PtrSize m_stride; ///< Vertex stride.
 	VertexStepRate m_stepRate = VertexStepRate::VERTEX;
 };
 
-struct VertexAttributeBinding
+class VertexAttributeBinding
 {
+public:
 	PixelFormat m_format;
 	PtrSize m_offset = 0;
 	U8 m_binding = 0;
 };
 
-struct VertexStateInfo
+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;
 };
 
-struct InputAssemblerStateInfo
+class InputAssemblerStateInfo
 {
+public:
 	PrimitiveTopology m_topology = PrimitiveTopology::TRIANGLES;
 	Bool8 m_primitiveRestartEnabled = false;
 };
 
-struct TessellationStateInfo
+class TessellationStateInfo
 {
+public:
 	U32 m_patchControlPointsCount = 3;
 };
 
-struct ViewportStateInfo
+class ViewportStateInfo
 {
+public:
 	Bool8 m_scissorEnabled = false;
 };
 
-struct RasterizerStateInfo
+class RasterizerStateInfo
 {
+public:
 	FillMode m_fillMode = FillMode::SOLID;
 	CullMode m_cullMode = CullMode::BACK;
 };
 
-struct DepthStencilStateInfo
+class DepthStencilStateInfo
 {
+public:
 	Bool8 m_depthWriteEnabled = true;
 	CompareOperation m_depthCompareFunction = CompareOperation::LESS;
 	PixelFormat m_format;
+	F32 m_polygonOffsetFactor = 0.0;
+	F32 m_polygonOffsetUnits = 0.0;
 };
 
-struct ColorAttachmentStateInfo
+class ColorAttachmentStateInfo
 {
+public:
 	PixelFormat m_format;
 	BlendMethod m_srcBlendMethod = BlendMethod::ONE;
 	BlendMethod m_dstBlendMethod = BlendMethod::ZERO;
@@ -74,15 +84,15 @@ struct ColorAttachmentStateInfo
 	ColorBit m_channelWriteMask = ColorBit::ALL;
 };
 
-struct ColorStateInfo
+class ColorStateInfo
 {
+public:
 	Bool8 m_alphaToCoverageEnabled = false;
-	Bool8 m_blendEnabled = false;
-	U8 m_colorAttachmentsCount = 0;
+	U8 m_attachmentCount = 0;
 	Array<ColorAttachmentStateInfo, MAX_COLOR_ATTACHMENTS> m_attachments;
 };
 
-enum class SubStateBit: U16
+enum class PipelineSubStateBit: U16
 {
 	NONE = 0,
 	VERTEX = 1 << 0,
@@ -92,10 +102,10 @@ enum class SubStateBit: U16
 	RASTERIZER = 1 << 4,
 	DEPTH_STENCIL = 1 << 5,
 	COLOR = 1 << 6,
-	ALL = VERTEX | INPUT_ASSEMBLER | TESSELLATION | VIEWPORT | RASTERIZER 
+	ALL = VERTEX | INPUT_ASSEMBLER | TESSELLATION | VIEWPORT | RASTERIZER
 		| DEPTH_STENCIL | COLOR
 };
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(SubStateBit, inline)
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(PipelineSubStateBit, inline)
 
 /// Pipeline initializer.
 class PipelineInitializer
@@ -110,11 +120,8 @@ public:
 	ColorStateInfo m_color;
 
 	Array<ShaderPtr, 6> m_shaders;
-	PipelinePtr m_templatePipeline;
-	SubStateBit m_definedState = SubStateBit::NONE;
 };
 /// @}
 
 } // end namespace anki
 
-#endif

+ 1 - 4
include/anki/gr/PipelinePtr.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_GR_PIPELINE_HANDLE_H
-#define ANKI_GR_PIPELINE_HANDLE_H
+#pragma once
 
 #include "anki/gr/GrPtr.h"
 
@@ -34,5 +33,3 @@ public:
 
 } // end namespace anki
 
-#endif
-

+ 17 - 7
include/anki/gr/gl/GlState.h

@@ -47,15 +47,25 @@ public:
 
 	Array<GLuint, 256> m_texUnits;
 
+	GLenum m_indexSize = GL_NONE;
+	/// @}
+
+	/// @name Pipeline state
+	/// @{
 	Array<GLsizei, MAX_VERTEX_ATTRIBUTES> m_vertexBindingStrides;
-	Bool m_primitiveRestartEnabled = false;
 	GLenum m_topology = 0;
-	U32 m_patchControlPointsCount = 0;
-	GLenum m_fillMode = GL_FILL;
-	GLenum m_cullMode = GL_BACK;
-	GLenum m_depthCompareFunction = GL_LESS;
 
-	PipelinePtr m_lastPipeline;
+	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;
 	/// @}
 
 	/// Global UBO ring buffer
@@ -67,7 +77,7 @@ public:
 	/// @}
 
 	GlState(GrManager* manager)
-	:	m_manager(manager)
+		: m_manager(manager)
 	{}
 
 	/// Call this from the rendering thread.

+ 30 - 24
include/anki/gr/gl/PipelineImpl.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_GR_GL_PIPELINE_IMPL_H
-#define ANKI_GR_GL_PIPELINE_IMPL_H
+#pragma once
 
 #include "anki/gr/gl/GlObject.h"
 #include "anki/gr/PipelineCommon.h"
@@ -18,14 +17,14 @@ class GlState;
 /// @{
 
 /// Program pipeline
-class PipelineImpl: public GlObject, private PipelineInitializer
+class PipelineImpl: public GlObject
 {
 public:
 	using Base = GlObject;
 	using Initializer = PipelineInitializer;
 
 	PipelineImpl(GrManager* manager)
-	:	Base(manager)
+		: Base(manager)
 	{}
 
 	~PipelineImpl()
@@ -56,20 +55,36 @@ private:
 		Array<Bool8, 4> m_channelWriteMask;
 	};
 
-	Bool8 m_complete;
 	Bool8 m_compute = false; ///< Is compute
 
-	// Cached values
-	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;
+	/// Input values.
+	PipelineInitializer m_in;
 
-	/// Create pipeline object
-	void createPpline();
+	/// 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;
+	} 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();
@@ -90,17 +105,8 @@ private:
 	void setRasterizerState(GlState& state) const;
 	void setDepthStencilState(GlState& state) const;
 	void setColorState(GlState& state) const;
-
-	const PipelineImpl* getPipelineForState(
-		const SubStateBit bit, 
-		const PipelineImpl* lastPpline,
-		const PipelineImpl* lastPplineTempl,
-		const PipelineImpl* pplineTempl) const; 
-
 };
 /// @}
 
 } // end namespace anki
 
-#endif
-

+ 1 - 1
include/anki/gr/gl/RenderingThread.h

@@ -15,7 +15,7 @@ namespace anki {
 /// @addtogroup opengl
 /// @{
 
-#define ANKI_DISABLE_GL_RENDERING_THREAD 0
+#define ANKI_DISABLE_GL_RENDERING_THREAD 1
 
 /// Command queue. It's essentialy a queue of command buffers waiting for
 /// execution and a server

+ 3 - 5
include/anki/renderer/Bloom.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RENDERER_BLOOM_H
-#define ANKI_RENDERER_BLOOM_H
+#pragma once
 
 #include "anki/renderer/RenderingPass.h"
 #include "anki/Gr.h"
@@ -22,9 +21,9 @@ class ShaderProgram;
 /// Bloom pass.
 class Bloom: public RenderingPass
 {
-	friend class Pps;
-
 public:
+	static const PixelFormat RT_PIXEL_FORMAT;
+
 	Bloom(Renderer* r)
 		: RenderingPass(r)
 	{}
@@ -97,4 +96,3 @@ private:
 
 } // end namespace anki
 
-#endif

+ 0 - 15
include/anki/renderer/Common.h

@@ -30,21 +30,6 @@ class Tiler;
 /// GL with a huge job chain
 const U RENDERER_COMMAND_BUFFERS_COUNT = 2;
 
-// Render target formats
-const U MS_COLOR_ATTACHMENTS_COUNT = 3;
-
-const Array<PixelFormat, MS_COLOR_ATTACHMENTS_COUNT>
-	MS_COLOR_ATTACHMENTS_PIXEL_FORMAT = {{
-	{ComponentFormat::R8G8B8A8, TransformFormat::UNORM, false},
-	{ComponentFormat::R8G8B8A8, TransformFormat::UNORM, false},
-	{ComponentFormat::R8G8B8A8, TransformFormat::UNORM, false}}};
-
-const PixelFormat MS_DEPTH_STENCIL_ATTACHMENT_FORMAT = {
-	ComponentFormat::D24, TransformFormat::FLOAT, false};
-
-const PixelFormat FS_COLOR_ATTACHMENT_FORMAT = {
-	ComponentFormat::R8G8B8, TransformFormat::UNORM, false};
-
 } // end namespace anki
 
 #endif

+ 1 - 1
include/anki/renderer/Dbg.h

@@ -43,7 +43,7 @@ public:
 	/// @privatesection
 	/// @{
 	Dbg(Renderer* r)
-	:	RenderingPass(r)
+		: RenderingPass(r)
 	{}
 
 	~Dbg();

+ 7 - 9
include/anki/renderer/DebugDrawer.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RENDERER_DEBUG_DRAWER_H
-#define ANKI_RENDERER_DEBUG_DRAWER_H
+#pragma once
 
 #include "anki/Math.h"
 #include "anki/Gr.h"
@@ -40,12 +39,12 @@ public:
 
 	void prepareDraw(CommandBufferPtr& jobs)
 	{
-		m_jobs = jobs;
+		m_cmdb = jobs;
 	}
 
 	void finishDraw()
 	{
-		m_jobs = CommandBufferPtr(); // Release job chain
+		m_cmdb = CommandBufferPtr(); // Release job chain
 	}
 
 	/// @name Render functions. Imitate the GL 1.1 immediate mode
@@ -87,7 +86,7 @@ private:
 	ShaderResourcePtr m_frag;
 	ShaderResourcePtr m_vert;
 	PipelinePtr m_ppline;
-	CommandBufferPtr m_jobs;
+	CommandBufferPtr m_cmdb;
 
 	static const U MAX_POINTS_PER_DRAW = 256;
 	Mat4 m_mMat;
@@ -114,7 +113,7 @@ class CollisionDebugDrawer: public CollisionShape::ConstVisitor
 public:
 	/// Constructor
 	CollisionDebugDrawer(DebugDrawer* dbg)
-	:	m_dbg(dbg)
+		: m_dbg(dbg)
 	{}
 
 	void visit(const LineSegment&);
@@ -142,7 +141,7 @@ class PhysicsDebugDrawer: public PhysicsDrawer
 {
 public:
 	PhysicsDebugDrawer(DebugDrawer* dbg)
-	:	m_dbg(dbg)
+		: m_dbg(dbg)
 	{}
 
 	void drawLines(
@@ -159,7 +158,7 @@ class SceneDebugDrawer
 {
 public:
 	SceneDebugDrawer(DebugDrawer* d)
-	:	m_dbg(d)
+		: m_dbg(d)
 	{}
 
 	~SceneDebugDrawer()
@@ -189,4 +188,3 @@ private:
 
 } // end namespace anki
 
-#endif

+ 1 - 3
include/anki/renderer/Drawer.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RENDERER_DRAWER_H
-#define ANKI_RENDERER_DRAWER_H
+#pragma once
 
 #include "anki/util/StdTypes.h"
 #include "anki/util/Ptr.h"
@@ -73,4 +72,3 @@ private:
 
 } // end namespace anki
 
-#endif

+ 0 - 36
include/anki/renderer/Ez.h

@@ -1,36 +0,0 @@
-// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#ifndef ANKI_RENDERER_EZ_H
-#define ANKI_RENDERER_EZ_H
-
-#include "anki/renderer/RenderingPass.h"
-#include "anki/Gr.h"
-
-namespace anki {
-
-/// @addtogroup renderer
-/// @{
-
-/// Material stage EarlyZ pass
-class Ez: public RenderingPass
-{
-	friend class Ms;
-
-private:
-	U32 m_maxObjectsToDraw;
-
-	Ez(Renderer* r)
-	:	RenderingPass(r)
-	{}
-
-	ANKI_USE_RESULT Error init(const ConfigSet& initializer);
-	ANKI_USE_RESULT Error run(CommandBufferPtr& cmdBuff);
-};
-/// @}
-
-} // end namespace anki
-
-#endif

+ 2 - 4
include/anki/renderer/Fs.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RENDERER_BS_H
-#define ANKI_RENDERER_BS_H
+#pragma once
 
 #include "anki/renderer/RenderingPass.h"
 
@@ -18,7 +17,7 @@ class Fs: public RenderingPass
 {
 public:
 	Fs(Renderer* r)
-	:	RenderingPass(r) 
+		: RenderingPass(r)
 	{}
 
 	~Fs();
@@ -33,4 +32,3 @@ private:
 
 } // end namespace anki
 
-#endif

+ 2 - 8
include/anki/renderer/Is.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RENDERER_IS_H
-#define ANKI_RENDERER_IS_H
+#pragma once
 
 #include "anki/renderer/RenderingPass.h"
 #include "anki/resource/TextureResource.h"
@@ -42,6 +41,7 @@ class Is: public RenderingPass
 
 public:
 	static const U MIPMAPS_COUNT = 7;
+	static const PixelFormat RT_PIXEL_FORMAT;
 
 	/// @privatesection
 	/// @{
@@ -127,11 +127,6 @@ private:
 	/// Keep the prev light dir to avoid uniform block updates
 	Vec3 m_prevGroundLightDir = Vec3(0.0);
 
-	/// @name For drawing a quad into the active framebuffer
-	/// @{
-	BufferPtr m_quadPositionsVertBuff;
-	/// @}
-
 	/// @name Limits
 	/// @{
 	U16 m_maxPointLights;
@@ -176,4 +171,3 @@ private:
 
 } // end namespace anki
 
-#endif

+ 4 - 6
include/anki/renderer/Lf.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RENDERER_LF_H
-#define ANKI_RENDERER_LF_H
+#pragma once
 
 #include "anki/renderer/RenderingPass.h"
 #include "anki/Gr.h"
@@ -16,14 +15,14 @@ namespace anki {
 /// @addtogroup renderer
 /// @{
 
-/// Lens flare rendering pass
+/// Lens flare rendering pass. Part of forward shading.
 class Lf: public RenderingPass
 {
 public:
 	/// @privatesection
 	/// @{
 	Lf(Renderer* r)
-	:	RenderingPass(r)
+		: RenderingPass(r)
 	{}
 
 	~Lf();
@@ -51,7 +50,7 @@ private:
 	U32 m_flareSize;
 	U8 m_maxSpritesPerFlare;
 	U8 m_maxFlares;
-	
+
 
 	ANKI_USE_RESULT Error initSprite(const ConfigSet& config);
 	ANKI_USE_RESULT Error initOcclusion(const ConfigSet& config);
@@ -62,4 +61,3 @@ private:
 
 } // end namespace anki
 
-#endif

+ 1 - 5
include/anki/renderer/MainRenderer.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RENDERER_MAIN_RENDERER_H
-#define ANKI_RENDERER_MAIN_RENDERER_H
+#pragma once
 
 #include "anki/renderer/Common.h"
 #include "anki/core/Timestamp.h"
@@ -70,11 +69,8 @@ private:
 
 	/// Optimize job chain
 	Array<CommandBufferInitHints, RENDERER_COMMAND_BUFFERS_COUNT> m_cbInitHints;
-
-	void initGl();
 };
 /// @}
 
 } // end namespace anki
 
-#endif

+ 6 - 8
include/anki/renderer/Ms.h

@@ -3,12 +3,10 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RENDERER_MS_H
-#define ANKI_RENDERER_MS_H
+#pragma once
 
 #include "anki/renderer/RenderingPass.h"
 #include "anki/Gr.h"
-#include "anki/renderer/Ez.h"
 
 namespace anki {
 
@@ -19,11 +17,14 @@ namespace anki {
 class Ms: public RenderingPass
 {
 public:
+	static const U ATTACHMENT_COUNT = 3;
+	static const Array<PixelFormat, ATTACHMENT_COUNT> RT_PIXEL_FORMATS;
+	static const PixelFormat DEPTH_RT_PIXEL_FORMAT;
+
 	/// @privatesection
 	/// @{
 	Ms(Renderer* r)
-	:	RenderingPass(r),
-		m_ez(r)
+		: RenderingPass(r)
 	{}
 
 	~Ms();
@@ -80,8 +81,6 @@ private:
 		TexturePtr m_depthRt;
 	};
 
-	Ez m_ez; /// EarlyZ pass
-
 	/// One for multisampled and one for not. 0: multisampled, 1: not
 	Array<Plane, 2> m_planes;
 
@@ -95,4 +94,3 @@ private:
 
 } // end namespace anki
 
-#endif

+ 2 - 0
include/anki/renderer/Pps.h

@@ -18,6 +18,8 @@ namespace anki {
 class Pps: public RenderingPass
 {
 public:
+	static const PixelFormat RT_PIXEL_FORMAT;
+
 	Pps(Renderer* r);
 	~Pps();
 

+ 4 - 6
include/anki/renderer/Renderer.h

@@ -219,8 +219,10 @@ public:
 
 	/// Create a pipeline object that has as a vertex shader the m_drawQuadVert
 	/// and the given fragment progam
-	ANKI_USE_RESULT Error createDrawQuadPipeline(
-		ShaderPtr frag, PipelinePtr& ppline);
+	void createDrawQuadPipeline(
+		ShaderPtr frag,
+		const ColorStateInfo& colorState,
+		PipelinePtr& ppline);
 
 	/// Init the renderer given an initialization class
 	/// @param initializer The initializer class
@@ -297,11 +299,7 @@ private:
 	UVec2 m_tilesCount;
 	U32 m_tilesCountXY;
 
-	/// @name For drawing a quad into the active framebuffer
-	/// @{
-	BufferPtr m_quadPositionsBuff; ///< The VBO for quad positions
 	ShaderResourcePtr m_drawQuadVert;
-	/// @}
 
 	/// @name Optimization vars
 	/// Used in other stages

+ 1 - 36
include/anki/renderer/RenderingPass.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RENDERER_RENDERING_PASS_H
-#define ANKI_RENDERER_RENDERING_PASS_H
+#pragma once
 
 #include "anki/renderer/Common.h"
 #include "anki/util/StdTypes.h"
@@ -58,41 +57,7 @@ protected:
 
 	ResourceManager& getResourceManager();
 };
-
-/// Blurring pass
-class BlurringRenderingPass: public RenderingPass
-{
-protected:
-	U32 m_blurringIterationsCount = 1; ///< The blurring iterations
-
-	BlurringRenderingPass(Renderer* r)
-		: RenderingPass(r)
-	{}
-
-	class Direction
-	{
-	public:
-		FramebufferPtr m_fb;
-		TexturePtr m_rt;
-		ShaderResourcePtr m_frag;
-		PipelinePtr m_ppline;
-	};
-
-	enum class DirectionEnum: U
-	{
-		VERTICAL,
-		HORIZONTAL
-	};
-
-	Array<Direction, 2> m_dirs;
-
-	ANKI_USE_RESULT Error initBlurring(Renderer& r, U width, U height, U samples,
-		F32 blurringDistance);
-
-	void runBlurring(Renderer& r, CommandBufferPtr& jobs);
-};
 /// @}
 
 } // end namespace anki
 
-#endif

+ 30 - 26
include/anki/renderer/Sm.h

@@ -13,7 +13,7 @@
 
 namespace anki {
 
-// Forward 
+// Forward
 class SceneNode;
 
 /// @addtogroup renderer
@@ -22,13 +22,27 @@ class SceneNode;
 /// Shadowmapping pass
 class Sm: private RenderingPass
 {
-	friend class Is;
-
 public:
 	static const U32 MAX_SHADOW_CASTERS = 8;
+	static const PixelFormat DEPTH_RT_PIXEL_FORMAT;
 
-	/// @name Accessors
+	/// @privatesection
 	/// @{
+	Sm(Renderer* r)
+		: RenderingPass(r)
+	{}
+
+	~Sm()
+	{
+		m_sms.destroy(getAllocator());
+	}
+
+	ANKI_USE_RESULT Error init(const ConfigSet& initializer);
+	ANKI_USE_RESULT Error run(
+		SceneNode* shadowCasters[],
+		U32 shadowCastersCount,
+		CommandBufferPtr& cmdBuff);
+
 	Bool getEnabled() const
 	{
 		return m_enabled;
@@ -38,6 +52,17 @@ public:
 	{
 		return m_poissonEnabled;
 	}
+
+	/// Get max shadow casters
+	U32 getMaxLightsCount()
+	{
+		return m_sms.getSize();
+	}
+
+	TexturePtr& getTextureArray()
+	{
+		return m_sm2DArrayTex;
+	}
 	/// @}
 
 private:
@@ -55,7 +80,7 @@ private:
 	DArray<Shadowmap> m_sms;
 
 	/// If false then disable SM at all
-	Bool8 m_enabled; 
+	Bool8 m_enabled;
 
 	/// Enable Poisson for all the levels
 	Bool8 m_poissonEnabled;
@@ -66,27 +91,6 @@ private:
 	/// Shadowmap resolution
 	U32 m_resolution;
 
-	Sm(Renderer* r)
-	:	RenderingPass(r)
-	{}
-
-	~Sm()
-	{
-		m_sms.destroy(getAllocator());
-	}
-
-	ANKI_USE_RESULT Error init(const ConfigSet& initializer);
-	ANKI_USE_RESULT Error run(
-		SceneNode* shadowCasters[], 
-		U32 shadowCastersCount, 
-		CommandBufferPtr& cmdBuff);
-
-	/// Get max shadow casters
-	U32 getMaxLightsCount()
-	{
-		return m_sms.getSize();
-	}
-
 	void prepareDraw(CommandBufferPtr& cmdBuff);
 	void finishDraw(CommandBufferPtr& cmdBuff);
 

+ 3 - 3
include/anki/renderer/Ssao.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RENDERER_SSAO_H
-#define ANKI_RENDERER_SSAO_H
+#pragma once
 
 #include "anki/renderer/RenderingPass.h"
 #include "anki/resource/ShaderResource.h"
@@ -23,6 +22,8 @@ class Ssao: public RenderingPass
 public:
 	/// @privatesection
 	/// @{
+	static const PixelFormat RT_PIXEL_FORMAT;
+
 	Ssao(Renderer* r)
 		: RenderingPass(r)
 	{}
@@ -69,4 +70,3 @@ private:
 
 } // end namespace anki
 
-#endif

+ 2 - 5
include/anki/renderer/Sslf.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RENDERER_SSLF_H
-#define ANKI_RENDERER_SSLF_H
+#pragma once
 
 #include "anki/renderer/RenderingPass.h"
 
@@ -20,7 +19,7 @@ public:
 	/// @privatesection
 	/// @{
 	Sslf(Renderer* r)
-	:	RenderingPass(r)
+		: RenderingPass(r)
 	{}
 
 	ANKI_USE_RESULT Error init(const ConfigSet& config);
@@ -45,5 +44,3 @@ private:
 
 } // end namespace anki
 
-#endif
-

+ 5 - 6
include/anki/renderer/Sslr.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RENDERER_SSLR_H
-#define ANKI_RENDERER_SSLR_H
+#pragma once
 
 #include "anki/renderer/RenderingPass.h"
 #include "anki/Gr.h"
@@ -15,13 +14,13 @@ namespace anki {
 /// @{
 
 /// Screen space local reflections pass
-class Sslr: public BlurringRenderingPass
+class Sslr: public RenderingPass
 {
 public:
 	/// @privatesection
 	/// @{
 	Sslr(Renderer* r)
-	:	BlurringRenderingPass(r)
+		: RenderingPass(r)
 	{}
 
 	ANKI_USE_RESULT Error init(const ConfigSet& config);
@@ -36,14 +35,14 @@ private:
 	ShaderResourcePtr m_reflectionFrag;
 	PipelinePtr m_reflectionPpline;
 	SamplerPtr m_depthMapSampler;
+	TexturePtr m_rt;
+	FramebufferPtr m_fb;
 
 	// 2nd pass: blit
 	ShaderResourcePtr m_blitFrag;
 	PipelinePtr m_blitPpline;
 };
-
 /// @}
 
 } // end namespace anki
 
-#endif

+ 4 - 6
include/anki/renderer/Tiler.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RENDERER_TILER_H
-#define ANKI_RENDERER_TILER_H
+#pragma once
 
 #include "anki/Collision.h"
 #include "anki/renderer/RenderingPass.h"
@@ -34,7 +33,7 @@ struct TilerTestResult
 	};
 
 	U32 m_count = 0;
-	Array<Pair, ANKI_RENDERER_MAX_TILES_X * ANKI_RENDERER_MAX_TILES_Y> 
+	Array<Pair, ANKI_RENDERER_MAX_TILES_X * ANKI_RENDERER_MAX_TILES_Y>
 		m_tileIds;
 
 	TilerTestResult() = default;
@@ -123,13 +122,13 @@ private:
 	ANKI_USE_RESULT Error initPbos();
 
 	void testRange(const CollisionShape& cs, Bool nearPlane,
-		U iFrom, U iTo, U jFrom, U jTo, TestResult* visible, 
+		U iFrom, U iTo, U jFrom, U jTo, TestResult* visible,
 		U& count) const;
 
 	void testFastSphere(const Sphere& s, const Aabb& aabb,
 		TestResult* visible, U& count) const;
 
-	void update(U32 threadId, PtrSize threadsCount, 
+	void update(U32 threadId, PtrSize threadsCount,
 		Camera& cam, Bool frustumChanged);
 
 	/// Calculate and set a top looking plane
@@ -142,4 +141,3 @@ private:
 
 } // end namespace anki
 
-#endif

+ 2 - 4
include/anki/renderer/Tm.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RENDERER_TM_H
-#define ANKI_RENDERER_TM_H
+#pragma once
 
 #include "anki/renderer/RenderingPass.h"
 
@@ -18,7 +17,7 @@ class Tm: public RenderingPass
 {
 public:
 	Tm(Renderer* r)
-	:	RenderingPass(r)
+		: RenderingPass(r)
 	{}
 
 	BufferPtr& getAverageLuminanceBuffer()
@@ -39,4 +38,3 @@ private:
 
 } // end namespace anki
 
-#endif

+ 1 - 3
include/anki/resource/Animation.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RESOURCE_ANIMATION_H
-#define ANKI_RESOURCE_ANIMATION_H
+#pragma once
 
 #include "anki/resource/ResourceObject.h"
 #include "anki/resource/ResourcePointer.h"
@@ -114,4 +113,3 @@ private:
 
 } // end namespace anki
 
-#endif

+ 1 - 4
include/anki/resource/AsyncLoader.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RESOURCE_ASYNC_LOADER_H
-#define ANKI_RESOURCE_ASYNC_LOADER_H
+#pragma once
 
 #include "anki/resource/Common.h"
 #include "anki/util/Thread.h"
@@ -94,5 +93,3 @@ Error AsyncLoader::newTask(TArgs&&... args)
 
 } // end namespace anki
 
-#endif
-

+ 1 - 4
include/anki/resource/CollisionResource.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RESOURCE_COLLISION_RESOURCE_H
-#define ANKI_RESOURCE_COLLISION_RESOURCE_H
+#pragma once
 
 #include "anki/resource/ResourceObject.h"
 #include "anki/resource/ResourcePointer.h"
@@ -46,5 +45,3 @@ private:
 
 } // end namespace anki
 
-#endif
-

+ 1 - 3
include/anki/resource/DummyRsrc.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RESOURCE_DUMMY_RSRC_H
-#define ANKI_RESOURCE_DUMMY_RSRC_H
+#pragma once
 
 #include "anki/resource/ResourceObject.h"
 #include "anki/resource/ResourcePointer.h"
@@ -57,4 +56,3 @@ private:
 
 } // end namespace anki
 
-#endif

+ 1 - 4
include/anki/resource/Forward.h

@@ -3,11 +3,8 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RESOURCE_FORWARD_H
-#define ANKI_RESOURCE_FORWARD_H
+#pragma once
 
 #include "anki/resource/Common.h"
 #include "anki/resource/ResourcePointer.h"
 
-#endif
-

+ 31 - 101
include/anki/resource/Material.h

@@ -11,7 +11,6 @@
 #include "anki/resource/RenderingKey.h"
 #include "anki/Math.h"
 #include "anki/util/Visitor.h"
-#include "anki/util/Dictionary.h"
 #include "anki/util/NonCopyable.h"
 
 namespace anki {
@@ -187,83 +186,7 @@ private:
 	DArray<TData> m_data;
 };
 
-/// Contains a few properties that other classes may use. For an explanation of
-/// the variables refer to Material class documentation
-class MaterialProperties
-{
-public:
-	/// @name Accessors
-	/// @{
-	U getLevelsOfDetail() const
-	{
-		return m_lodsCount;
-	}
-
-	U getPassesCount() const
-	{
-		return m_passesCount;
-	}
-
-	Bool getShadow() const
-	{
-		return m_shadow;
-	}
-
-	GLenum getBlendingSfactor() const
-	{
-		return m_blendingSfactor;
-	}
-
-	GLenum getBlendingDfactor() const
-	{
-		return m_blendingDfactor;
-	}
-
-	Bool getDepthTestingEnabled() const
-	{
-		return m_depthTesting;
-	}
-
-	Bool getWireframeEnabled() const
-	{
-		return m_wireframe;
-	}
-
-	Bool getTessellation() const
-	{
-		return m_tessellation;
-	}
-	/// @}
-
-	/// Check if blending is enabled
-	Bool isBlendingEnabled() const
-	{
-		return m_blendingSfactor != GL_ONE || m_blendingDfactor != GL_ZERO;
-	}
-
-protected:
-	GLenum m_blendingSfactor = GL_ONE; ///< Default GL_ONE
-	GLenum m_blendingDfactor = GL_ZERO; ///< Default GL_ZERO
-
-	Bool8 m_depthTesting = true;
-	Bool8 m_wireframe = false;
-	Bool8 m_shadow = true;
-	Bool8 m_tessellation = false;
-
-	U8 m_passesCount = 1;
-	U8 m_lodsCount = 1;
-};
-
-/// Material resource
-///
-/// Every material keeps info of how to render a RenedrableNode. Using a node
-/// based logic it creates a couple of shader programs dynamically. One for
-/// color passes and one for depth. It also keeps two sets of material
-/// variables. The first is the build in and the second the user defined.
-/// During the renderer's shader setup the buildins will be set automatically,
-/// for the user variables the user needs to have its value in the material
-/// file. Some material variables may be present in both shader programs and
-/// some in only one of them
+/// Material resource.
 ///
 /// Material XML file format:
 /// @code
@@ -272,10 +195,7 @@ protected:
 ///
 /// 	[<shadow>0 | 1</shadow>]
 ///
-/// 	[<blendFunctions>
-/// 		<sFactor>GL_SOMETHING</sFactor>
-/// 		<dFactor>GL_SOMETHING</dFactor>
-/// 	</blendFunctions>]
+/// 	[<forwardShading>0 | 1</forwardShading>]
 ///
 /// 	[<depthTesting>0 | 1</depthTesting>]
 ///
@@ -326,7 +246,7 @@ protected:
 /// (2): The \<value\> can be left empty for build-in variables
 /// (3): The \<const\> will mark a variable as constant and it cannot be changed
 ///      at all. Default is 0
-class Material: public ResourceObject, public MaterialProperties
+class Material: public ResourceObject
 {
 	friend class MaterialVariable;
 
@@ -335,12 +255,6 @@ public:
 
 	~Material();
 
-	/// Access the base class just for copying in other classes
-	const MaterialProperties& getBaseClass() const
-	{
-		return *this;
-	}
-
 	// Variable accessors
 	const DArray<MaterialVariable*>& getVariables() const
 	{
@@ -352,9 +266,6 @@ public:
 		return m_shaderBlockSize;
 	}
 
-	ANKI_USE_RESULT Error getProgramPipeline(
-		const RenderingKey& key, PipelinePtr& out);
-
 	/// Load a material file
 	ANKI_USE_RESULT Error load(const ResourceFilename& filename);
 
@@ -364,21 +275,43 @@ public:
 		return m_hash < b.m_hash;
 	}
 
+	U getLodCount() const
+	{
+		return m_lodCount;
+	}
+
+	Bool getShadowEnabled() const
+	{
+		return m_shadow;
+	}
+
+	Bool getTessellationEnabled() const
+	{
+		return m_tessellation;
+	}
+
+	Bool getForwardShading() const
+	{
+		return m_forwardShading;
+	}
+
+	ShaderPtr getShader(const RenderingKey& key, ShaderType type) const;
+
 private:
 	DArray<MaterialVariable*> m_vars;
-	Dictionary<MaterialVariable*> m_varDict;
 
-	DArray<ShaderResourcePtr> m_progs;
-	DArray<PipelinePtr> m_pplines;
+	/// [pass][lod][tess][shader]
+	Array4d<ShaderResourcePtr, U(Pass::COUNT), MAX_LODS, 2, 5> m_shaders;
 
 	U32 m_shaderBlockSize;
 
 	/// Used for sorting
 	U64 m_hash;
 
-	/// Get a program resource
-	ShaderResourcePtr& getProgram(
-		const RenderingKey key, ShaderType shaderId);
+	Bool8 m_shadow = true;
+	Bool8 m_tessellation = false;
+	Bool8 m_forwardShading = false;
+	U8 m_lodCount = 1;
 
 	/// Parse what is within the @code <material></material> @endcode
 	ANKI_USE_RESULT Error parseMaterialTag(const XmlElement& el);
@@ -390,9 +323,6 @@ private:
 	/// Read all shader programs and pupulate the @a vars and @a nameToVar
 	/// containers
 	ANKI_USE_RESULT Error populateVariables(const MaterialProgramCreator& mspc);
-
-	U countShaders(ShaderType type) const;
-	U getShaderIndex(const RenderingKey key, ShaderType type) const;
 };
 /// @}
 

+ 0 - 35
include/anki/resource/MaterialCommon.h

@@ -1,35 +0,0 @@
-// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#ifndef ANKI_RESOURSE_MATERIAL_COMMON_H
-#define ANKI_RESOURSE_MATERIAL_COMMON_H
-
-#include "anki/resource/Common.h"
-#include "anki/resource/RenderingKey.h"
-#include "anki/util/NonCopyable.h"
-#include "anki/Gr.h"
-
-namespace anki {
-
-/// @addtogroup resource
-/// @{
-
-/// Data that will be used in material loading.
-class MaterialResourceData: public NonCopyable
-{
-public:
-	PipelinePtr m_pipelines[U(Pass::COUNT)];
-
-	MaterialResourceData() = default;
-	~MaterialResourceData() = default;
-
-	ANKI_USE_RESULT Error create(ResourceManager& manager);
-};
-/// @}
-
-} // end namespace anki
-
-#endif
-

+ 7 - 9
include/anki/resource/MaterialProgramCreator.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RESOURCE_MATERIAL_SHADER_PROGRAM_CREATOR_H
-#define ANKI_RESOURCE_MATERIAL_SHADER_PROGRAM_CREATOR_H
+#pragma once
 
 #include "anki/util/StringList.h"
 #include "anki/Gr.h"
@@ -15,7 +14,7 @@ namespace anki {
 // Forward
 class XmlElement;
 
-/// Material loader variable. It's the information on whatever is inside 
+/// Material loader variable. It's the information on whatever is inside
 /// \<input\>
 class MaterialProgramCreatorInputVariable: public NonCopyable
 {
@@ -37,7 +36,7 @@ public:
 	I16 m_binding = -1; ///< Texture unit
 	I32 m_offset = -1; ///< Offset inside the UBO
 	I32 m_arrayStride = -1;
-	/// Identifying the stride between columns of a column-major matrix or 
+	/// Identifying the stride between columns of a column-major matrix or
 	/// rows of a row-major matrix
 	I32 m_matrixStride = -1;
 
@@ -96,8 +95,8 @@ public:
 };
 
 /// Creator of shader programs. This class parses between
-/// @code <shaderProgams></shaderPrograms> @endcode located inside a 
-/// @code <material></material> @endcode and creates the source of a custom 
+/// @code <shaderProgams></shaderPrograms> @endcode located inside a
+/// @code <material></material> @endcode and creates the source of a custom
 /// program.
 ///
 /// @note Be carefull when you change the methods. Some change may create more
@@ -139,7 +138,7 @@ public:
 	}
 
 private:
-	TempResourceAllocator<char> m_alloc; 
+	TempResourceAllocator<char> m_alloc;
 	Array<StringList, 5> m_source; ///< Shader program final source
 	Array<String, 5> m_sourceBaked; ///< Final source baked
 	List<Input> m_inputs;
@@ -160,10 +159,9 @@ private:
 
 	/// Parse what is within the @code <operation></operation> @endcode
 	ANKI_USE_RESULT Error parseOperationTag(
-		const XmlElement& el, GLenum glshader, 
+		const XmlElement& el, GLenum glshader,
 		GLbitfield glshaderbit, String& out);
 };
 
 } // end namespace anki
 
-#endif

+ 11 - 38
include/anki/resource/Mesh.h

@@ -12,26 +12,12 @@
 
 namespace anki {
 
+// Forward
 class MeshLoader;
 
 /// @addtogroup resource
 /// @{
 
-/// Vertex attributes. This should match the shaders
-enum class VertexAttribute: U8
-{
-	POSITION,
-	NORMAL,
-	TANGENT,
-	TEXTURE_COORD,
-	TEXTURE_COORD_1,
-	BONE_IDS,
-	BONE_WEIGHTS,
-	INDICES,
-	COUNT
-};
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(VertexAttribute, inline)
-
 /// Mesh Resource. It contains the geometry packed in GPU buffers.
 class Mesh: public ResourceObject
 {
@@ -48,7 +34,7 @@ public:
 		return m_texChannelsCount;
 	}
 
-	Bool hasWeights() const
+	Bool hasBoneWeights() const
 	{
 		return m_weights;
 	}
@@ -88,11 +74,15 @@ public:
 		return m_subMeshes.getSize();
 	}
 
-	/// Get info on how to attach a GL buffer to the state
-	void getBufferInfo(
-		const VertexAttribute attrib, BufferPtr& buffer,
-		U32& size, GLenum& type, U32& stride, U32& offset,
-		Bool& normalized) const;
+	BufferPtr getVertexBuffer() const
+	{
+		return m_vertBuff;
+	}
+
+	BufferPtr getIndexBuffer() const
+	{
+		return m_indicesBuff;
+	}
 
 	/// Helper function for correct loading
 	Bool isCompatible(const Mesh& other) const;
@@ -122,23 +112,6 @@ protected:
 	/// Create the VBOs using the mesh data
 	ANKI_USE_RESULT Error createBuffers(const MeshLoader& loader);
 };
-
-// TODO Remove that
-/// A mesh that behaves as a mesh and as a collection of separate meshes.
-class BucketMesh: public Mesh
-{
-public:
-	/// Default constructor.
-	BucketMesh(ResourceManager* manager)
-	:	Mesh(manager)
-	{}
-
-	~BucketMesh()
-	{}
-
-	/// Load from a .mmesh file
-	ANKI_USE_RESULT Error load(const CString& filename);
-};
 /// @}
 
 } // end namespace anki

+ 29 - 67
include/anki/resource/Model.h

@@ -24,18 +24,17 @@ class PhysicsCollisionShape;
 
 /// Model patch interface class. Its very important class and it binds the
 /// material with the mesh
-class ModelPatchBase
+class ModelPatch
 {
 public:
-	ModelPatchBase(ResourceAllocator<U8> alloc)
-		: m_alloc(alloc)
+	ModelPatch(Model* model)
+		: m_model(model)
 	{}
 
-	virtual ~ModelPatchBase();
+	~ModelPatch();
 
 	const Material& getMaterial() const
 	{
-		ANKI_ASSERT(m_mtl);
 		return *m_mtl;
 	}
 
@@ -44,92 +43,55 @@ public:
 		return *m_meshes[key.m_lod];
 	}
 
-	U32 getMeshesCount() const
-	{
-		return m_meshes.getSize();
-	}
-
 	const Obb& getBoundingShape() const
 	{
-		RenderingKey key(Pass::COLOR, 0, false);
-		return getMesh(key).getBoundingShape();
+		return m_meshes[0]->getBoundingShape();
 	}
 
 	const Obb& getBoundingShapeSub(U32 subMeshId) const
 	{
-		RenderingKey key(Pass::COLOR, 0, false);
-		return getMesh(key).getBoundingShapeSub(subMeshId);
+		return m_meshes[0]->getBoundingShapeSub(subMeshId);
 	}
 
 	U32 getSubMeshesCount() const
 	{
-		RenderingKey key(Pass::COLOR, 0, false);
-		return getMesh(key).getSubMeshesCount();
+		return m_meshes[0]->getSubMeshesCount();
 	}
 
+	ANKI_USE_RESULT Error create(
+		SArray<CString> meshFNames,
+		const CString& mtlFName,
+		ResourceManager* resources);
+
 	/// Get information for multiDraw rendering.
 	/// Given an array of submeshes that are visible return the correct indices
-	/// offsets and counts
-	ANKI_USE_RESULT Error getRenderingDataSub(
+	/// offsets and counts.
+	void getRenderingDataSub(
 		const RenderingKey& key,
-		CommandBufferPtr& vertJobs,
+		SArray<U8> subMeshIndicesArray,
+		BufferPtr& vertBuff,
+		BufferPtr& indexBuff,
 		PipelinePtr& ppline,
-		const U8* subMeshIndicesArray,
-		U32 subMeshIndicesCount,
 		Array<U32, ANKI_GL_MAX_SUB_DRAWCALLS>& indicesCountArray,
 		Array<PtrSize, ANKI_GL_MAX_SUB_DRAWCALLS>& indicesOffsetArray,
 		U32& drawcallCount) const;
 
-protected:
-	ResourceAllocator<U8> m_alloc;
-	/// Array [lod][pass]
-	DArray<CommandBufferPtr> m_vertJobs;
-	Material* m_mtl = nullptr;
-	DArray<Mesh*> m_meshes; ///< One for each LOD
-
-	/// Create vertex descriptors using a material and a mesh
-	ANKI_USE_RESULT Error create(GrManager* gr);
-
 private:
-	/// Called by @a create multiple times to create and populate a single
-	/// vertex descriptor
-	static ANKI_USE_RESULT Error createVertexDesc(
-		const Mesh& mesh,
-		CommandBufferPtr& vertexJobs);
+	Model* m_model;
 
-	/// Return the maximum number of LODs
-	U getLodsCount() const;
+	Array<MeshResourcePtr, MAX_LODS> m_meshes; ///< One for each LOD
+	U8 m_meshCount = 0;
+	MaterialResourcePtr m_mtl;
 
-	U getVertexDescIdx(const RenderingKey& key) const;
-};
+	mutable Array3d<PipelinePtr, U(Pass::COUNT), MAX_LODS, 2> m_pplines;
 
-/// Its a chunk of a model. Its very important class and it binds the material
-/// with the mesh
-template<typename MeshResourcePtrType>
-class ModelPatch: public ModelPatchBase
-{
-public:
-	using Base = ModelPatchBase;
-
-	/// Accepts a number of mesh filenames, one for each LOD
-	ModelPatch(ResourceAllocator<U8> alloc)
-		: ModelPatchBase(alloc)
-	{}
-
-	~ModelPatch()
-	{
-		m_meshResources.destroy(ModelPatchBase::m_alloc);
-	}
+	/// Return the maximum number of LODs
+	U getLodCount() const;
 
-	ANKI_USE_RESULT Error create(
-		CString meshFNames[],
-		U32 meshesCount,
-		const CString& mtlFName,
-		ResourceManager* resources);
+	PipelinePtr getPipeline(const RenderingKey& key) const;
 
-private:
-	DArray<MeshResourcePtrType> m_meshResources; ///< Geometries
-	MaterialResourcePtr m_mtlResource; ///< Material
+	void computePipelineInitializer(
+		const RenderingKey& key, PipelineInitializer& pinit) const;
 };
 
 /// Model is an entity that acts as a container for other resources. Models are
@@ -172,7 +134,7 @@ public:
 
 	~Model();
 
-	const DArray<ModelPatchBase*>& getModelPatches() const
+	const DArray<ModelPatch*>& getModelPatches() const
 	{
 		return m_modelPatches;
 	}
@@ -185,7 +147,7 @@ public:
 	ANKI_USE_RESULT Error load(const ResourceFilename& filename);
 
 private:
-	DArray<ModelPatchBase*> m_modelPatches;
+	DArray<ModelPatch*> m_modelPatches;
 	Obb m_visibilityShape;
 	SkeletonResourcePtr m_skeleton;
 	DArray<AnimationResourcePtr> m_animations;

+ 11 - 0
include/anki/resource/ParticleEmitterResource.h

@@ -8,6 +8,7 @@
 #include "anki/resource/ResourceObject.h"
 #include "anki/resource/ResourcePointer.h"
 #include "anki/Math.h"
+#include "anki/Gr.h"
 
 namespace anki {
 
@@ -96,6 +97,9 @@ class ParticleEmitterResource: public ResourceObject,
 	private ParticleEmitterProperties
 {
 public:
+	/// Size of a single vertex.
+	static const U VERTEX_SIZE = 5 * sizeof(F32);
+
 	ParticleEmitterResource(ResourceManager* manager)
 		: ResourceObject(manager)
 	{}
@@ -117,11 +121,18 @@ public:
 		return *m_material;
 	}
 
+	/// Get pipeline for rendering.
+	PipelinePtr getPipeline() const
+	{
+		return m_ppline;
+	}
+
 	/// Load it
 	ANKI_USE_RESULT Error load(const ResourceFilename& filename);
 
 private:
 	MaterialResourcePtr m_material;
+	PipelinePtr m_ppline;
 
 	void loadInternal(const XmlElement& el);
 };

+ 13 - 13
include/anki/resource/RenderingKey.h

@@ -3,22 +3,23 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RESOURCE_RENDERING_KEY_H
-#define ANKI_RESOURCE_RENDERING_KEY_H
+#pragma once
 
 #include "anki/util/StdTypes.h"
 #include "anki/util/Assert.h"
 
 namespace anki {
 
-/// The AnKi passes
+/// The AnKi passes visible to materials.
 enum class Pass: U8
 {
-	COLOR, ///< For MS
-	DEPTH, ///< For shadows
+	MS_FS, ///< MS or FS
+	SM,
 	COUNT
 };
 
+const U MAX_LODS = 3;
+
 /// A key that consistst of the rendering pass and the level of detail
 class RenderingKey
 {
@@ -28,17 +29,17 @@ public:
 	Bool8 m_tessellation;
 
 	explicit RenderingKey(Pass pass, U8 lod, Bool tessellation)
-	:	m_pass(pass), 
-		m_lod(lod), 
-		m_tessellation(tessellation)
+		: m_pass(pass)
+		, m_lod(lod)
+		, m_tessellation(tessellation)
 	{}
 
 	RenderingKey()
-	:	RenderingKey(Pass::COLOR, 0, false)
+		: RenderingKey(Pass::MS_FS, 0, false)
 	{}
 
 	RenderingKey(const RenderingKey& b)
-	:	RenderingKey(b.m_pass, b.m_lod, b.m_tessellation)
+		: RenderingKey(b.m_pass, b.m_lod, b.m_tessellation)
 	{}
 };
 
@@ -48,7 +49,7 @@ class RenderingKeyHasher
 public:
 	PtrSize operator()(const RenderingKey& key) const
 	{
-		return (U8)key.m_pass | (key.m_lod << 8) | (key.m_tessellation << 16);
+		return U8(key.m_pass) | (key.m_lod << 8) | (key.m_tessellation << 16);
 	}
 };
 
@@ -58,11 +59,10 @@ class RenderingKeyEqual
 public:
 	Bool operator()(const RenderingKey& a, const RenderingKey& b) const
 	{
-		return a.m_pass == b.m_pass && a.m_lod == b.m_lod 
+		return a.m_pass == b.m_pass && a.m_lod == b.m_lod
 			&& a.m_tessellation == b.m_tessellation;
 	}
 };
 
 } // end namespace anki
 
-#endif

+ 14 - 27
include/anki/resource/ResourceManager.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RESOURCE_RESOURCE_MANAGER_H
-#define ANKI_RESOURCE_RESOURCE_MANAGER_H
+#pragma once
 
 #include "anki/resource/Common.h"
 #include "anki/util/List.h"
@@ -19,7 +18,7 @@ class GrManager;
 class PhysicsWorld;
 class ResourceManager;
 class AsyncLoader;
-class MaterialResourceData;
+class ResourceManagerModel;
 
 /// @addtogroup resource
 /// @{
@@ -89,22 +88,20 @@ private:
 	}
 };
 
-#define ANKI_RESOURCE(type_) public TypeResourceManager<type_>
-
 /// Resource manager. It holds a few global variables
 class ResourceManager:
-	ANKI_RESOURCE(Animation),
-	ANKI_RESOURCE(TextureResource),
-	ANKI_RESOURCE(ShaderResource),
-	ANKI_RESOURCE(Material),
-	ANKI_RESOURCE(Mesh),
-	ANKI_RESOURCE(BucketMesh),
-	ANKI_RESOURCE(Skeleton),
-	ANKI_RESOURCE(ParticleEmitterResource),
-	ANKI_RESOURCE(Model),
-	ANKI_RESOURCE(Script),
-	ANKI_RESOURCE(DummyRsrc),
-	ANKI_RESOURCE(CollisionResource)
+	TypeResourceManager<Animation>,
+	TypeResourceManager<TextureResource>,
+	TypeResourceManager<ShaderResource>,
+	TypeResourceManager<Material>,
+	TypeResourceManager<Mesh>,
+	TypeResourceManager<BucketMesh>,
+	TypeResourceManager<Skeleton>,
+	TypeResourceManager<ParticleEmitterResource>,
+	TypeResourceManager<Model>,
+	TypeResourceManager<Script>,
+	TypeResourceManager<DummyRsrc>,
+	TypeResourceManager<CollisionResource>
 {
 public:
 	class Initializer
@@ -204,12 +201,6 @@ public:
 	{
 		return *m_asyncLoader;
 	}
-
-	MaterialResourceData& getMaterialData()
-	{
-		ANKI_ASSERT(m_materialData);
-		return *m_materialData;
-	}
 	/// @}
 
 private:
@@ -224,12 +215,8 @@ private:
 	U32 m_textureAnisotropy;
 	String m_shadersPrependedSource;
 	AsyncLoader* m_asyncLoader = nullptr; ///< Async loading thread
-	MaterialResourceData* m_materialData = nullptr;
 };
-
-#undef ANKI_RESOURCE
 /// @}
 
 } // end namespace anki
 
-#endif

+ 1 - 4
include/anki/resource/ResourceObject.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RESOURCE_RESOURCE_OBJECT_H
-#define ANKI_RESOURCE_RESOURCE_OBJECT_H
+#pragma once
 
 #include "anki/resource/Common.h"
 #include "anki/resource/ResourceFilesystem.h"
@@ -84,5 +83,3 @@ private:
 
 } // end namespace anki
 
-#endif
-

+ 1 - 3
include/anki/resource/ShaderResource.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RESOURCE_PROGRAM_RESOURCE_H
-#define ANKI_RESOURCE_PROGRAM_RESOURCE_H
+#pragma once
 
 #include "anki/resource/ResourceObject.h"
 #include "anki/resource/ResourcePointer.h"
@@ -67,4 +66,3 @@ private:
 
 } // end namespace anki
 
-#endif

+ 2 - 4
include/anki/resource/Skin.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RESOURCE_SKIN_H
-#define ANKI_RESOURCE_SKIN_H
+#pragma once
 
 #include "anki/resource/ResourceManager.h"
 #include "anki/resource/Model.h"
@@ -13,7 +12,7 @@
 namespace anki {
 
 /// Skin resource
-/// 
+///
 /// XML file format:
 /// @code<skin>
 /// 	<model>path/to/model.mdl</model>
@@ -66,4 +65,3 @@ private:
 } // end namespace anki
 #endif
 
-#endif

+ 4 - 6
include/anki/scene/ModelNode.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_SCENE_MODEL_NODE_H
-#define ANKI_SCENE_MODEL_NODE_H
+#pragma once
 
 #include "anki/scene/SceneNode.h"
 #include "anki/scene/RenderComponent.h"
@@ -34,15 +33,15 @@ public:
 	~ModelPatchNode();
 
 	ANKI_USE_RESULT Error create(
-		const CString& name, const ModelPatchBase* modelPatch);
+		const CString& name, const ModelPatch* modelPatch);
 
 private:
 	Obb m_obb; ///< In world space
-	const ModelPatchBase* m_modelPatch; ///< The resource
+	const ModelPatch* m_modelPatch; ///< The resource
 	DArray<ObbSpatialComponent*> m_spatials;
 
 	void updateInstanceSpatials(
-		const MoveComponent* instanceMoves[], 
+		const MoveComponent* instanceMoves[],
 		U32 instanceMovesCount);
 
 	ANKI_USE_RESULT Error buildRendering(RenderingBuildData& data);
@@ -84,4 +83,3 @@ private:
 
 } // end namespace anki
 
-#endif

+ 7 - 7
include/anki/scene/RenderComponent.h

@@ -13,7 +13,7 @@
 
 namespace anki {
 
-/// @addtogroup Scene
+/// @addtogroup scene
 /// @{
 
 /// The ID of a buildin material variable
@@ -72,7 +72,7 @@ public:
 	const T* begin() const
 	{
 		ANKI_ASSERT(Base::isTypeOf<RenderComponentVariableTemplate<T>>());
-		auto derived = 
+		auto derived =
 			static_cast<const RenderComponentVariableTemplate<T>*>(this);
 		return derived->begin();
 	}
@@ -81,7 +81,7 @@ public:
 	const T* end() const
 	{
 		ANKI_ASSERT(Base::isTypeOf<RenderComponentVariableTemplate<T>>());
-		auto derived = 
+		auto derived =
 			static_cast<const RenderComponentVariableTemplate<T>*>(this);
 		return derived->end();
 	}
@@ -90,7 +90,7 @@ public:
 	const T& operator[](U idx) const
 	{
 		ANKI_ASSERT(Base::isTypeOf<RenderComponentVariableTemplate<T>>());
-		auto derived = 
+		auto derived =
 			static_cast<const RenderComponentVariableTemplate<T>*>(this);
 		return (*derived)[idx];
 	}
@@ -129,7 +129,7 @@ private:
 	BuildinMaterialVariableId m_buildinId;
 };
 
-/// RenderComponent variable. This class should not be visible to other 
+/// RenderComponent variable. This class should not be visible to other
 /// interfaces except render component
 template<typename T>
 class RenderComponentVariableTemplate: public RenderComponentVariable
@@ -215,7 +215,7 @@ public:
 	RenderingKey m_key;
 	const U8* m_subMeshIndicesArray; ///< @note indices != drawing indices
 	U32 m_subMeshIndicesCount;
-	CommandBufferPtr m_jobs; ///< A job chain 
+	CommandBufferPtr m_cmdb; ///< A command buffer to append to.
 };
 
 /// RenderComponent interface. Implemented by renderable scene nodes
@@ -273,7 +273,7 @@ public:
 	Bool getCastsShadow()
 	{
 		const Material& mtl = getMaterial();
-		return mtl.getShadow() && !mtl.isBlendingEnabled();
+		return mtl.getShadowEnabled();
 	}
 
 	/// Iterate variables using a lambda

+ 1 - 3
include/anki/scene/SceneNode.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_SCENE_SCENE_NODE_H
-#define ANKI_SCENE_SCENE_NODE_H
+#pragma once
 
 #include "anki/scene/Common.h"
 #include "anki/util/Hierarchy.h"
@@ -211,4 +210,3 @@ private:
 
 } // end namespace anki
 
-#endif

+ 3 - 5
include/anki/scene/StaticGeometryNode.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_SCENE_STATIC_GEOMETRY_NODE_H
-#define ANKI_SCENE_STATIC_GEOMETRY_NODE_H
+#pragma once
 
 #include "anki/scene/Common.h"
 #include "anki/scene/SceneNode.h"
@@ -27,10 +26,10 @@ public:
 	~StaticGeometryPatchNode();
 
 	ANKI_USE_RESULT Error create(
-		const CString& name, const ModelPatchBase* modelPatch);
+		const CString& name, const ModelPatch* modelPatch);
 
 private:
-	const ModelPatchBase* m_modelPatch;
+	const ModelPatch* m_modelPatch;
 
 	ANKI_USE_RESULT Error buildRendering(RenderingBuildData& data);
 };
@@ -53,4 +52,3 @@ private:
 
 } // end namespace anki
 
-#endif

+ 1 - 1
include/anki/util/Allocator.h

@@ -182,7 +182,7 @@ public:
 	void construct(Y* p, Args&&... args)
 	{
 		// Placement new
-		::new((void *)p) Y(std::forward<Args>(args)...);
+		::new(static_cast<void*>(p)) Y(std::forward<Args>(args)...);
 	}
 
 	/// Call destructor

+ 11 - 9
include/anki/util/Array.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_PtrSizeTIL_ARRAY_H
-#define ANKI_PtrSizeTIL_ARRAY_H
+#pragma once
 
 #include "anki/util/Assert.h"
 #include "anki/util/StdTypes.h"
@@ -65,7 +64,7 @@ public:
 		return &m_data[0] + N;
 	}
 
-	Reference getFront() 
+	Reference getFront()
 	{
 		return m_data[0];
 	}
@@ -75,7 +74,7 @@ public:
 		return m_data[0];
 	}
 
-	Reference getBack() 
+	Reference getBack()
 	{
 		return m_data[N - 1];
 	}
@@ -110,7 +109,7 @@ public:
 	}
 
 	/// Make it compatible with STL
-	Reference front() 
+	Reference front()
 	{
 		return getFront();
 	}
@@ -122,7 +121,7 @@ public:
 	}
 
 	/// Make it compatible with STL
-	Reference back() 
+	Reference back()
 	{
 		return getBack;
 	}
@@ -145,18 +144,21 @@ public:
 	}
 };
 
-/// 2D Array. @code Array2d<X, 10, 2> a; @endcode is equivelent to 
+/// 2D Array. @code Array2d<X, 10, 2> a; @endcode is equivelent to
 /// @code X a[10][2]; @endcode
 template<typename T, PtrSize I, PtrSize J>
 using Array2d = Array<Array<T, J>, I>;
 
-/// 3D Array. @code Array3d<X, 10, 2, 3> a; @endcode is equivelent to 
+/// 3D Array. @code Array3d<X, 10, 2, 3> a; @endcode is equivelent to
 /// @code X a[10][2][3]; @endcode
 template<typename T, PtrSize I, PtrSize J, PtrSize K>
 using Array3d = Array<Array<Array<T, K>, J>, I>;
 
+/// 4D Array. @code Array4d<X, 10, 2, 3, 4> a; @endcode is equivelent to
+/// @code X a[10][2][3][4]; @endcode
+template<typename T, PtrSize I, PtrSize J, PtrSize K, PtrSize L>
+using Array4d = Array<Array<Array<Array<T, L>, K>, J>, I>;
 /// @}
 
 } // end namespace anki
 
-#endif

+ 18 - 20
include/anki/util/DArray.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_UTIL_D_ARRAY_H
-#define ANKI_UTIL_D_ARRAY_H
+#pragma once
 
 #include "anki/util/Allocator.h"
 #include "anki/util/NonCopyable.h"
@@ -15,8 +14,8 @@ namespace anki {
 /// @addtogroup util_containers
 /// @{
 
-/// Dynamic array with manual destruction. It doesn't hold the allocator and 
-/// that makes it compact. At the same time that requires manual destruction. 
+/// Dynamic array with manual destruction. It doesn't hold the allocator and
+/// that makes it compact. At the same time that requires manual destruction.
 /// Used in permanent classes.
 template<typename T>
 class DArray: public NonCopyable
@@ -29,20 +28,20 @@ public:
 	using ConstReference = const Value&;
 
 	DArray()
-	:	m_data(nullptr),
-		m_size(0)
+		: m_data(nullptr)
+		, m_size(0)
 	{}
 
 	/// Move.
 	DArray(DArray&& b)
-	:	DArray()
+		: DArray()
 	{
 		move(b);
 	}
 
 	~DArray()
 	{
-		ANKI_ASSERT(m_data == nullptr && m_size == 0 
+		ANKI_ASSERT(m_data == nullptr && m_size == 0
 			&& "Requires manual destruction");
 	}
 
@@ -114,7 +113,7 @@ public:
 	}
 
 	/// Get first element.
-	Reference getFront() 
+	Reference getFront()
 	{
 		return m_data[0];
 	}
@@ -126,7 +125,7 @@ public:
 	}
 
 	/// Get last element.
-	Reference getBack() 
+	Reference getBack()
 	{
 		return m_data[m_size - 1];
 	}
@@ -239,7 +238,7 @@ protected:
 	}
 };
 
-/// Dynamic array with automatic destruction. It's the same as DArray but it 
+/// Dynamic array with automatic destruction. It's the same as DArray but it
 /// holds the allocator in order to perform automatic destruction. Use it for
 /// temp operations and on transient classes.
 template<typename T>
@@ -251,13 +250,13 @@ public:
 
 	template<typename TAllocator>
 	DArrayAuto(TAllocator alloc)
-	:	Base(),
-		m_alloc(alloc)
+		: Base()
+		, m_alloc(alloc)
 	{}
 
 	/// Move.
 	DArrayAuto(DArrayAuto&& b)
-	:	DArrayAuto()
+		: DArrayAuto()
 	{
 		move(b);
 	}
@@ -311,21 +310,21 @@ public:
 	using Value = T;
 
 	SArray()
-	:	Base()
+		: Base()
 	{}
 
-	SArray(void* mem, PtrSize size)
-	:	Base()
+	SArray(T* mem, PtrSize size)
+		: Base()
 	{
 		ANKI_ASSERT(mem);
 		ANKI_ASSERT(size);
-		Base::m_data = static_cast<Value*>(mem);
+		Base::m_data = mem;
 		Base::m_size = size;
 	}
 
 	/// Move.
 	SArray(SArray&& b)
-	:	SArray()
+		: SArray()
 	{
 		move(b);
 	}
@@ -358,4 +357,3 @@ private:
 
 } // end namespace anki
 
-#endif

+ 9 - 6
shaders/IsLp.vert.glsl

@@ -4,11 +4,8 @@
 // http://www.anki3d.org/LICENSE
 
 #pragma anki type vert
-
 #pragma anki include "shaders/IsCommon.glsl"
 
-layout(location = 0) in vec2 in_position;
-
 layout(location = 0) out vec2 out_texCoord;
 layout(location = 1) flat out int out_instanceId;
 layout(location = 2) out vec2 out_projectionParams;
@@ -23,15 +20,21 @@ void main()
 	float instIdF = float(gl_InstanceID);
 
 	vec2 ij = vec2(
-		mod(instIdF, float(TILES_X_COUNT)), 
+		mod(instIdF, float(TILES_X_COUNT)),
 		floor(instIdF / float(TILES_X_COUNT)));
 
 	out_instanceId = int(gl_InstanceID);
 
-	const vec2 SIZES = 
+	const vec2 SIZES =
 		vec2(1.0 / float(TILES_X_COUNT), 1.0 / float(TILES_Y_COUNT));
 
-	out_texCoord = (in_position + ij) * SIZES;
+	const vec2 POSITIONS[4] = vec2[](
+		vec2(-1.0, -1.0),
+		vec2(1.0, -1.0),
+		vec2(-1.0, 1.0),
+		vec2(1.0, 1.0));
+
+	out_texCoord = (POSITIONS[gl_VertexID] + ij) * SIZES;
 	vec2 vertPosNdc = out_texCoord * 2.0 - 1.0;
 	gl_Position = vec4(vertPosNdc, 0.0, 1.0);
 

+ 10 - 4
shaders/LfSpritePass.vert.glsl

@@ -21,8 +21,6 @@ layout(std140) uniform _flaresBlock
 	Flare u_flares[MAX_SPRITES];
 };
 
-layout(location = 0) in vec2 in_position;
-
 layout(location = 0) out vec3 out_texCoord;
 layout(location = 1) flat out float out_alpha;
 
@@ -35,10 +33,18 @@ void main()
 {
 	Flare flare = u_flares[gl_InstanceID];
 
-	out_texCoord = vec3((in_position * 0.5) + 0.5, flare.alphaDepth.y);
+	const vec2 POSITIONS[4] = vec2[](
+		vec2(-1.0, -1.0),
+		vec2(1.0, -1.0),
+		vec2(-1.0, 1.0),
+		vec2(1.0, 1.0));
+
+	vec2 position = POSITIONS[gl_VertexID];
+
+	out_texCoord = vec3((position * 0.5) + 0.5, flare.alphaDepth.y);
 
 	vec4 posScale = flare.posScale;
-	gl_Position = vec4(in_position * posScale.zw + posScale.xy , 0.0, 1.0);
+	gl_Position = vec4(position * posScale.zw + posScale.xy , 0.0, 1.0);
 
 	out_alpha = flare.alphaDepth.x;
 }

+ 10 - 7
shaders/Quad.vert.glsl

@@ -6,18 +6,21 @@
 #pragma anki type vert
 #pragma anki include "shaders/Common.glsl"
 
-/// the vert coords are NDC
-layout(location = POSITION_LOCATION) in vec2 inPosition;
-
-layout(location = 0) out vec2 outTexCoord;
-
 out gl_PerVertex
 {
 	vec4 gl_Position;
 };
 
+layout(location = 0) out vec2 out_texCoord;
+
 void main()
 {
-	outTexCoord = (inPosition * 0.5) + 0.5;
-	gl_Position = vec4(inPosition, 0.0, 1.0);
+	const vec2 POSITIONS[3] = vec2[](
+		vec2(-1.0, -1.0),
+		vec2(3.0, -1.0),
+		vec2(-1.0, 3.0));
+
+	vec2 pos = POSITIONS[gl_VertexID];
+	out_texCoord = pos * 0.5 + 0.5;
+	gl_Position = vec4(pos, 0.0, 1.0);
 }

+ 68 - 151
src/gr/gl/CommandBufferPtr.cpp

@@ -247,157 +247,6 @@ void CommandBufferPtr::setViewport(U16 minx, U16 miny, U16 maxx, U16 maxy)
 	get().pushBackNewCommand<Command>(minx, miny, maxx, maxy);
 }
 
-//==============================================================================
-void CommandBufferPtr::setColorWriteMask(
-	Bool red, Bool green, Bool blue, Bool alpha)
-{
-	ANKI_STATE_CMD_4(Bool8, glColorMask, red, green, blue, alpha);
-}
-
-//==============================================================================
-void CommandBufferPtr::enableDepthTest(Bool enable)
-{
-	ANKI_STATE_CMD_ENABLE(GL_DEPTH_TEST, enable);
-}
-
-//==============================================================================
-void CommandBufferPtr::setDepthFunction(GLenum func)
-{
-	ANKI_STATE_CMD_1(GLenum, glDepthFunc, func);
-}
-
-//==============================================================================
-void CommandBufferPtr::setDepthWriteMask(Bool write)
-{
-	ANKI_STATE_CMD_1(Bool8, glDepthMask, write);
-}
-
-//==============================================================================
-void CommandBufferPtr::enableStencilTest(Bool enable)
-{
-	ANKI_STATE_CMD_ENABLE(GL_STENCIL_TEST, enable);
-}
-
-//==============================================================================
-void CommandBufferPtr::setStencilFunction(
-	GLenum function, U32 reference, U32 mask)
-{
-	ANKI_STATE_CMD_3(U32, glStencilFunc, function, reference, mask);
-}
-
-//==============================================================================
-void CommandBufferPtr::setStencilPlaneMask(U32 mask)
-{
-	ANKI_STATE_CMD_1(U32, glStencilMask, mask);
-}
-
-//==============================================================================
-void CommandBufferPtr::setStencilOperations(GLenum stencFail, GLenum depthFail,
-	GLenum depthPass)
-{
-	ANKI_STATE_CMD_3(GLenum, glStencilOp, stencFail, depthFail, depthPass);
-}
-
-//==============================================================================
-void CommandBufferPtr::enableBlend(Bool enable)
-{
-	ANKI_STATE_CMD_ENABLE(GL_BLEND, enable);
-}
-
-//==============================================================================
-void CommandBufferPtr::setBlendEquation(GLenum equation)
-{
-	ANKI_STATE_CMD_1(GLenum, glBlendEquation, equation);
-}
-
-//==============================================================================
-void CommandBufferPtr::setBlendFunctions(GLenum sfactor, GLenum dfactor)
-{
-	class Command: public GlCommand
-	{
-	public:
-		GLenum m_sfactor;
-		GLenum m_dfactor;
-
-		Command(GLenum sfactor, GLenum dfactor)
-			: m_sfactor(sfactor), m_dfactor(dfactor)
-		{}
-
-		Error operator()(CommandBufferImpl* commands)
-		{
-			GlState& state = commands->getManager().getImplementation().
-				getRenderingThread().getState();
-
-			if(state.m_blendSfunc != m_sfactor
-				|| state.m_blendDfunc != m_dfactor)
-			{
-				glBlendFunc(m_sfactor, m_dfactor);
-
-				state.m_blendSfunc = m_sfactor;
-				state.m_blendDfunc = m_dfactor;
-			}
-
-			return ErrorCode::NONE;
-		}
-	};
-
-	get().pushBackNewCommand<Command>(sfactor, dfactor);
-}
-
-//==============================================================================
-void CommandBufferPtr::setBlendColor(F32 r, F32 g, F32 b, F32 a)
-{
-	ANKI_STATE_CMD_4(F32, glBlendColor, r, g, b, a);
-}
-
-//==============================================================================
-void CommandBufferPtr::enablePrimitiveRestart(Bool enable)
-{
-	ANKI_STATE_CMD_ENABLE(GL_PRIMITIVE_RESTART, enable);
-}
-
-//==============================================================================
-void CommandBufferPtr::setPatchVertexCount(U32 count)
-{
-	ANKI_STATE_CMD_2(GLint, glPatchParameteri, GL_PATCH_VERTICES, count);
-}
-
-//==============================================================================
-void CommandBufferPtr::enableCulling(Bool enable)
-{
-	ANKI_STATE_CMD_ENABLE(GL_CULL_FACE, enable);
-}
-
-//==============================================================================
-void CommandBufferPtr::setCullFace(GLenum mode)
-{
-	ANKI_STATE_CMD_1(GLenum, glCullFace, mode);
-}
-
-//==============================================================================
-void CommandBufferPtr::setPolygonOffset(F32 factor, F32 units)
-{
-	ANKI_STATE_CMD_2(F32, glPolygonOffset, factor, units);
-}
-
-//==============================================================================
-void CommandBufferPtr::enablePolygonOffset(Bool enable)
-{
-	ANKI_STATE_CMD_ENABLE(GL_POLYGON_OFFSET_FILL, enable);
-}
-
-//==============================================================================
-void CommandBufferPtr::setPolygonMode(GLenum face, GLenum mode)
-{
-	ANKI_STATE_CMD_2(GLenum, glPolygonMode, face, mode);
-}
-
-//==============================================================================
-void CommandBufferPtr::enablePointSize(Bool enable)
-{
-	ANKI_STATE_CMD_ENABLE(GL_PROGRAM_POINT_SIZE, enable);
-}
-
 //==============================================================================
 class BindTexturesCommand: public GlCommand
 {
@@ -738,4 +587,72 @@ void CommandBufferPtr::updateDynamicUniforms(void* data, U32 originalSize)
 		state.m_globalUbos[uboIdx], subUboOffset, originalSize);
 }
 
+//==============================================================================
+class BindVertexCommand final: public GlCommand
+{
+public:
+	BufferPtr m_buff;
+	PtrSize m_offset;
+	U32 m_binding;
+
+	BindVertexCommand(U32 bindingPoint, BufferPtr buff, PtrSize offset)
+		: m_buff(buff)
+		, m_offset(offset)
+		, m_binding(bindingPoint)
+	{}
+
+	Error operator()(CommandBufferImpl* cmdb)
+	{
+		GlState& state = cmdb->getManager().getImplementation().
+			getRenderingThread().getState();
+		ANKI_ASSERT(state.m_vertexBindingStrides[m_binding] > 0);
+
+		glBindVertexBuffer(m_binding, m_buff.get().getGlName(),
+			m_offset, state.m_vertexBindingStrides[m_binding]);
+
+		return ErrorCode::NONE;
+	}
+};
+
+void CommandBufferPtr::bindVertexBuffer(
+	U32 bindingPoint, BufferPtr buff, PtrSize offset)
+{
+	get().pushBackNewCommand<BindVertexCommand>(bindingPoint, buff, offset);
+}
+
+//==============================================================================
+class BindIndexCommand final: public GlCommand
+{
+public:
+	BufferPtr m_buff;
+	U8 m_indexSize;
+
+	BindIndexCommand(BufferPtr buff, U32 indexSize)
+		: m_buff(buff)
+		, m_indexSize(indexSize)
+	{}
+
+	Error operator()(CommandBufferImpl* cmdb)
+	{
+		// Update the state...
+		ANKI_ASSERT(m_indexSize == 2 || m_indexSize == 4);
+		GLenum type = m_indexSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
+
+		GlState& state = cmdb->getManager().getImplementation().
+			getRenderingThread().getState();
+
+		state.m_indexSize = type;
+
+		// ...and bind
+		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buff.get().getGlName());
+
+		return ErrorCode::NONE;
+	}
+};
+
+void CommandBufferPtr::bindIndexBuffer(BufferPtr buff, U32 indexSize)
+{
+	get().pushBackNewCommand<BindIndexCommand>(buff, indexSize);
+}
+
 } // end namespace anki

+ 3 - 1
src/gr/gl/GlState.cpp

@@ -138,9 +138,11 @@ void GlState::init()
 	glGetInteger64v(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, &alignment);
 	m_ssBuffOffsetAlignment = alignment;
 
+	// Set some GL state
+	glEnable(GL_PROGRAM_POINT_SIZE);
+
 	// Other
 	memset(&m_vertexBindingStrides[0], 0, sizeof(m_vertexBindingStrides));
-
 	initGlobalUbo();
 }
 

+ 141 - 183
src/gr/gl/PipelineImpl.cpp

@@ -8,6 +8,7 @@
 #include "anki/gr/gl/GrManagerImpl.h"
 #include "anki/gr/gl/RenderingThread.h"
 #include "anki/util/Logger.h"
+#include "anki/util/Hash.h"
 
 namespace anki {
 
@@ -105,22 +106,7 @@ static GLenum convertBlendMethod(BlendMethod in)
 //==============================================================================
 Error PipelineImpl::create(const Initializer& init)
 {
-	static_cast<Initializer&>(*this) = init;
-
-	// Check if complete
-	m_complete = true;
-
-	if(m_templatePipeline.isCreated())
-	{
-		// If there is a template it should always be complete
-		SubStateBit mask =
-			m_definedState | m_templatePipeline.get().m_definedState;
-		ANKI_ASSERT(mask == SubStateBit::ALL);
-	}
-	else if(m_definedState != SubStateBit::ALL)
-	{
-		m_complete = false;
-	}
+	m_in = init;
 
 	ANKI_CHECK(createGlPipeline());
 	if(!m_compute)
@@ -154,7 +140,7 @@ Error PipelineImpl::createGlPipeline()
 	U count = 6;
 	while(count-- != 0)
 	{
-		const ShaderPtr& shader = m_shaders[count];
+		const ShaderPtr& shader = m_in.m_shaders[count];
 		if(shader.isCreated())
 		{
 			ANKI_ASSERT(count == enumToType(shader.get().getType()));
@@ -193,9 +179,9 @@ Error PipelineImpl::createGlPipeline()
 
 	glBindProgramPipeline(m_glName);
 
-	for(U i = 0; i < m_shaders.getSize(); i++)
+	for(U i = 0; i < m_in.m_shaders.getSize(); i++)
 	{
-		ShaderPtr& shader = m_shaders[i];
+		ShaderPtr& shader = m_in.m_shaders[i];
 
 		if(shader.isCreated())
 		{
@@ -236,75 +222,44 @@ Error PipelineImpl::createGlPipeline()
 //==============================================================================
 void PipelineImpl::bind()
 {
-#if 1
-	ANKI_ASSERT(isCreated());
 	glBindProgramPipeline(m_glName);
-#else
-	// TODO check compute
-	ANKI_ASSERT(m_complete && "Should be complete");
 
-	// Get last pipeline
-	auto& state =
-		getManager().getImplementation().getRenderingThread().getState();
-
-	const PipelineImpl* lastPpline = nullptr;
-	const PipelineImpl* lastPplineTempl = nullptr;
-	if(state.m_lastPipeline.isCreated())
+	if(m_compute)
 	{
-		lastPpline = &state.m_lastPipeline.get();
-
-		if(ANKI_UNLIKELY(lastPpline == this))
-		{
-			// Binding the same pipeline, early out
-			return;
-		}
-
-		if(lastPpline->m_templatePipeline.isCreated())
-		{
-			lastPplineTempl = &lastPpline->m_templatePipeline.get();
-		}
+		return;
 	}
 
-	// Get crnt pipeline template
-	const PipelineImpl* pplineTempl = nullptr;
-	if(m_templatePipeline.isCreated())
-	{
-		pplineTempl = &m_templatePipeline.get();
-	}
+	// Get last pipeline
+	GlState& state =
+		getManager().getImplementation().getRenderingThread().getState();
 
-#define ANKI_PPLINE_BIND(enum_, method_) \
-	do { \
-		const PipelineImpl* ppline = getPipelineForState(SubStateBit::enum_, \
-			lastPpline, lastPplineTempl, pplineTempl); \
-		if(ppline) { \
-			ppline->method_(state); \
-		} \
-	} while(0) \
-
-	ANKI_PPLINE_BIND(VERTEX, setVertexState);
-	ANKI_PPLINE_BIND(INPUT_ASSEMBLER, setInputAssemblerState);
-	ANKI_PPLINE_BIND(TESSELLATION, setTessellationState);
-	ANKI_PPLINE_BIND(VIEWPORT, setViewportState);
-	ANKI_PPLINE_BIND(RASTERIZER, setRasterizerState);
-	ANKI_PPLINE_BIND(DEPTH_STENCIL, setDepthStencilState);
-	ANKI_PPLINE_BIND(COLOR, setColorState);
-
-#undef ANKI_PPLINE_BIND
-
-#endif
+	setVertexState(state);
+	setInputAssemblerState(state);
+	setTessellationState(state);
+	setViewportState(state);
+	setRasterizerState(state);
+	setDepthStencilState(state);
+	setColorState(state);
 }
 
 //==============================================================================
 void PipelineImpl::initVertexState()
 {
-	for(U i = 0; i < m_vertex.m_attributeCount; ++i)
+	for(U i = 0; i < m_in.m_vertex.m_attributeCount; ++i)
 	{
-		const VertexAttributeBinding& binding = m_vertex.m_attributes[i];
+		const VertexAttributeBinding& binding = m_in.m_vertex.m_attributes[i];
 		ANKI_ASSERT(binding.m_format.m_srgb == false);
-		Attribute& cache = m_attribs[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;
@@ -318,6 +273,20 @@ void PipelineImpl::initVertexState()
 			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::R10G10B10A2, TransformFormat::SNORM))
 		{
@@ -330,84 +299,95 @@ void PipelineImpl::initVertexState()
 			ANKI_ASSERT(0 && "TODO");
 		}
 	}
+
+	m_hashes.m_vertex = computeHash(&m_in.m_vertex, sizeof(m_in.m_vertex));
 }
 
 //==============================================================================
 void PipelineImpl::initInputAssemblerState()
 {
-	switch(m_inputAssembler.m_topology)
+	switch(m_in.m_inputAssembler.m_topology)
 	{
-	case POINTS:
-		m_topology = GL_POINTS;
+	case PrimitiveTopology::POINTS:
+		m_cache.m_topology = GL_POINTS;
 		break;
-	case LINES:
-		m_topology = GL_LINES;
+	case PrimitiveTopology::LINES:
+		m_cache.m_topology = GL_LINES;
 		break;
-	case LINE_STIP:
-		m_topology = GL_LINE_STRIP;
+	case PrimitiveTopology::LINE_STIP:
+		m_cache.m_topology = GL_LINE_STRIP;
 		break;
-	case TRIANGLES:
-		m_topology = GL_TRIANGLES;
+	case PrimitiveTopology::TRIANGLES:
+		m_cache.m_topology = GL_TRIANGLES;
 		break;
-	case TRIANGLE_STRIP:
-		m_topology = GL_TRIANGLE_STRIP;
+	case PrimitiveTopology::TRIANGLE_STRIP:
+		m_cache.m_topology = GL_TRIANGLE_STRIP;
 		break;
-	case PATCHES:
-		m_topology = GL_PATCHES;
+	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::initRasterizerState()
 {
-	switch(m_rasterizer.m_fillMode)
+	switch(m_in.m_rasterizer.m_fillMode)
 	{
 	case FillMode::POINTS:
-		m_fillMode = GL_POINT;
+		m_cache.m_fillMode = GL_POINT;
 		break;
 	case FillMode::WIREFRAME:
-		m_fillMode = GL_LINE;
+		m_cache.m_fillMode = GL_LINE;
 		break;
 	case FillMode::SOLID:
-		m_fillMode = GL_FILL;
+		m_cache.m_fillMode = GL_FILL;
 		break;
 	default:
 		ANKI_ASSERT(0);
 	}
 
-	switch(m_rasterizer.m_cullMode)
+	switch(m_in.m_rasterizer.m_cullMode)
 	{
 	case CullMode::FRONT:
-		m_cullMode = GL_FRONT;
+		m_cache.m_cullMode = GL_FRONT;
 		break;
 	case CullMode::BACK:
-		m_cullMode = GL_BACK;
+		m_cache.m_cullMode = GL_BACK;
 		break;
 	case CullMode::FRONT_AND_BACK:
-		m_cullMode = GL_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()
 {
-	m_depthCompareFunction =
-		convertCompareOperation(m_depthStencil.m_depthCompareFunction);
+	m_cache.m_depthCompareFunction =
+		convertCompareOperation(m_in.m_depthStencil.m_depthCompareFunction);
+
+	m_hashes.m_depthStencil =
+		computeHash(&m_in.m_depthStencil, sizeof(m_in.m_depthStencil));
 }
 
 //==============================================================================
 void PipelineImpl::initColorState()
 {
-	for(U i = 0; i < m_color.m_colorAttachmentsCount; ++i)
+	for(U i = 0; i < m_in.m_color.m_attachmentCount; ++i)
 	{
-		Attachment& out = m_attachments[i];
-		const ColorAttachmentStateInfo& in = m_color.m_attachments[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);
@@ -438,147 +418,125 @@ void PipelineImpl::initColorState()
 		out.m_channelWriteMask[2] = in.m_channelWriteMask | ColorBit::BLUE;
 		out.m_channelWriteMask[3] = in.m_channelWriteMask | ColorBit::ALPHA;
 	}
+
+	m_hashes.m_color = computeHash(&m_in.m_color, sizeof(m_in.m_color));
 }
 
 //==============================================================================
 void PipelineImpl::setVertexState(GlState& state) const
 {
-	for(U i = 0; i < m_vertex.m_attributeCount; ++i)
+	if(state.m_stateHashes.m_vertex == m_hashes.m_vertex)
+	{
+		return;
+	}
+
+	for(U i = 0; i < m_in.m_vertex.m_attributeCount; ++i)
 	{
-		const Attribute& attrib = m_attribs[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_vertex.m_attributes[i].m_offset);
+			attrib.m_normalized, m_in.m_vertex.m_attributes[i].m_offset);
 
-		glVertexAttribBinding(i, m_vertex.m_attributes[i].m_binding);
+		glVertexAttribBinding(i, m_in.m_vertex.m_attributes[i].m_binding);
 	}
 
-	for(U i = 0; i < m_vertex.m_bindingCount; ++i)
+	for(U i = 0; i < m_in.m_vertex.m_bindingCount; ++i)
 	{
-		state.m_vertexBindingStrides[i] = m_vertex.m_bindings[i].m_stride;
+		state.m_vertexBindingStrides[i] = m_in.m_vertex.m_bindings[i].m_stride;
 	}
 }
 
 //==============================================================================
 void PipelineImpl::setInputAssemblerState(GlState& state) const
 {
-	if(m_inputAssembler.m_primitiveRestartEnabled
-		!= state.m_primitiveRestartEnabled)
+	if(state.m_stateHashes.m_inputAssembler == m_hashes.m_inputAssembler)
 	{
-		if(m_inputAssembler.m_primitiveRestartEnabled)
-		{
-			glEnable(GL_PRIMITIVE_RESTART);
-		}
-		else
-		{
-			glDisable(GL_PRIMITIVE_RESTART);
-		}
-
-		state.m_primitiveRestartEnabled =
-			m_inputAssembler.m_primitiveRestartEnabled;
+		return;
 	}
 
-	state.m_topology = 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.m_patchControlPointsCount
-		!= state.m_patchControlPointsCount)
+	if(state.m_stateHashes.m_tessellation == m_hashes.m_tessellation)
 	{
-		glPatchParameteri(GL_PATCH_VERTICES,
-			m_tessellation.m_patchControlPointsCount);
-
-		state.m_patchControlPointsCount =
-			m_tessellation.m_patchControlPointsCount;
+		return;
 	}
+
+	glPatchParameteri(GL_PATCH_VERTICES,
+		m_in.m_tessellation.m_patchControlPointsCount);
 }
 
 //==============================================================================
 void PipelineImpl::setRasterizerState(GlState& state) const
 {
-	if(m_fillMode != state.m_fillMode)
+	if(state.m_stateHashes.m_rasterizer == m_hashes.m_rasterizer)
 	{
-		glPolygonMode(GL_FRONT_AND_BACK, m_fillMode);
-		state.m_fillMode = m_fillMode;
+		return;
 	}
 
-	if(m_cullMode != state.m_cullMode)
-	{
-		glCullFace(m_cullMode);
-		state.m_cullMode = m_cullMode;
-	}
+	glPolygonMode(GL_FRONT_AND_BACK, m_cache.m_fillMode);
+	glCullFace(m_cache.m_cullMode);
 }
 
 //==============================================================================
 void PipelineImpl::setDepthStencilState(GlState& state) const
 {
-	if(m_depthCompareFunction != state.m_depthCompareFunction)
+	if(state.m_stateHashes.m_depthStencil == m_hashes.m_depthStencil)
 	{
-		if(m_depthCompareFunction == GL_ALWAYS)
-		{
-			glDisable(GL_DEPTH_TEST);
-		}
-		else
-		{
-			glEnable(GL_DEPTH_TEST);
-		}
-
-		glDepthFunc(m_depthCompareFunction);
-
-		state.m_depthCompareFunction = m_depthCompareFunction;
+		return;
 	}
-}
 
-//==============================================================================
-void PipelineImpl::setColorState(GlState&) const
-{
-	for(U i = 0; i < m_color.m_colorAttachmentsCount; ++i)
+	if(m_cache.m_depthCompareFunction == GL_ALWAYS)
+	{
+		glDisable(GL_DEPTH_TEST);
+	}
+	else
 	{
-		const Attachment& att = m_attachments[i];
+		glEnable(GL_DEPTH_TEST);
+	}
 
-		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]);
+	if(m_in.m_depthStencil.m_polygonOffsetFactor == 0.0
+		&& m_in.m_depthStencil.m_polygonOffsetUnits == 0.0)
+	{
+		glEnable(GL_POLYGON_OFFSET_FILL);
+		glPolygonOffset(m_in.m_depthStencil.m_polygonOffsetFactor,
+			m_in.m_depthStencil.m_polygonOffsetUnits);
+	}
+	else
+	{
+		glDisable(GL_POLYGON_OFFSET_FILL);
 	}
+
+	glDepthFunc(m_cache.m_depthCompareFunction);
 }
 
 //==============================================================================
-const PipelineImpl* PipelineImpl::getPipelineForState(
-	const SubStateBit bit,
-	const PipelineImpl* lastPpline,
-	const PipelineImpl* lastPplineTempl,
-	const PipelineImpl* pplineTempl) const
+void PipelineImpl::setColorState(GlState& state) const
 {
-	const PipelineImpl* out = nullptr;
-
-	if(pplineTempl == nullptr || (m_definedState | bit) != SubStateBit::NONE)
+	if(state.m_stateHashes.m_color == m_hashes.m_color)
 	{
-		// Current pipeline overrides the state
-		out = this;
+		return;
 	}
-	else
-	{
-		// Need to get the state from the templates
 
-		if(lastPplineTempl == nullptr
-			|| lastPplineTempl != pplineTempl
-			|| (lastPpline->m_definedState | bit) != SubStateBit::NONE)
-		{
-			// Last template cannot be used
+	for(U i = 0; i < m_in.m_color.m_attachmentCount; ++i)
+	{
+		const Attachment& att = m_cache.m_attachments[i];
 
-			out = pplineTempl;
-		}
-		else
-		{
-			// Last template can be used but since it's already bound skipp
-			out = nullptr;
-		}
+		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]);
 	}
-
-	return out;
 }
 
 } // end namespace anki

+ 18 - 11
src/renderer/Bloom.cpp

@@ -12,6 +12,10 @@
 
 namespace anki {
 
+//==============================================================================
+const PixelFormat Bloom::RT_PIXEL_FORMAT(
+	ComponentFormat::R8G8B8, TransformFormat::UNORM);
+
 //==============================================================================
 Bloom::~Bloom()
 {}
@@ -20,8 +24,7 @@ Bloom::~Bloom()
 Error Bloom::initFb(FramebufferPtr& fb, TexturePtr& rt)
 {
 	// Set to bilinear because the blurring techniques take advantage of that
-	m_r->createRenderTarget(m_width, m_height,
-		PixelFormat(ComponentFormat::R8G8B8, TransformFormat::UNORM),
+	m_r->createRenderTarget(m_width, m_height, RT_PIXEL_FORMAT,
 		1, SamplingFilter::LINEAR, 1, rt);
 
 	// Create FB
@@ -48,9 +51,9 @@ Error Bloom::initInternal(const ConfigSet& config)
 	const F32 renderingQuality =
 		config.getNumber("pps.bloom.renderingQuality");
 
-	m_width = renderingQuality * (F32)m_r->getWidth();
+	m_width = renderingQuality * F32(m_r->getWidth());
 	alignRoundDown(16, m_width);
-	m_height = renderingQuality * (F32)m_r->getHeight();
+	m_height = renderingQuality * F32(m_r->getHeight());
 	alignRoundDown(16, m_height);
 
 	m_threshold = config.getNumber("pps.bloom.threshold");
@@ -62,9 +65,13 @@ Error Bloom::initInternal(const ConfigSet& config)
 	ANKI_CHECK(initFb(m_hblurFb, m_hblurRt));
 	ANKI_CHECK(initFb(m_vblurFb, m_vblurRt));
 
-	// init shaders
+	// init shaders & pplines
 	GrManager& gl = getGrManager();
 
+	ColorStateInfo colorState;
+	colorState.m_attachmentCount = 1;
+	colorState.m_attachments[0].m_format = RT_PIXEL_FORMAT;
+
 	m_commonBuff.create(&gl, GL_UNIFORM_BUFFER, nullptr,
 		sizeof(Vec4), GL_DYNAMIC_STORAGE_BIT);
 
@@ -84,8 +91,8 @@ Error Bloom::initInternal(const ConfigSet& config)
 	ANKI_CHECK(m_toneFrag.loadToCache(&getResourceManager(),
 		"shaders/PpsBloom.frag.glsl", pps.toCString(), "r_"));
 
-	ANKI_CHECK(m_r->createDrawQuadPipeline(
-		m_toneFrag->getGrShader(), m_tonePpline));
+	m_r->createDrawQuadPipeline(
+		m_toneFrag->getGrShader(), colorState, m_tonePpline);
 
 	const char* SHADER_FILENAME =
 		"shaders/VariableSamplingBlurGeneric.frag.glsl";
@@ -102,8 +109,8 @@ Error Bloom::initInternal(const ConfigSet& config)
 	ANKI_CHECK(m_hblurFrag.loadToCache(&getResourceManager(),
 		SHADER_FILENAME, pps.toCString(), "r_"));
 
-	ANKI_CHECK(m_r->createDrawQuadPipeline(
-		m_hblurFrag->getGrShader(), m_hblurPpline));
+	m_r->createDrawQuadPipeline(
+		m_hblurFrag->getGrShader(), colorState, m_hblurPpline);
 
 	pps.destroy(getAllocator());
 	pps.sprintf(
@@ -117,8 +124,8 @@ Error Bloom::initInternal(const ConfigSet& config)
 	ANKI_CHECK(m_vblurFrag.loadToCache(&getResourceManager(),
 		SHADER_FILENAME, pps.toCString(), "r_"));
 
-	ANKI_CHECK(m_r->createDrawQuadPipeline(
-		m_vblurFrag->getGrShader(), m_vblurPpline));
+	m_r->createDrawQuadPipeline(
+		m_vblurFrag->getGrShader(), colorState, m_vblurPpline);
 
 	// Set timestamps
 	m_parameterUpdateTimestamp = getGlobalTimestamp();

+ 1 - 10
src/renderer/Dbg.cpp

@@ -74,7 +74,6 @@ Error Dbg::run(CommandBufferPtr& cmdb)
 	ANKI_ASSERT(m_enabled);
 
 	m_fb.bind(cmdb);
-	cmdb.enableDepthTest(m_depthTest);
 
 	SceneNode& cam = m_r->getActiveCamera();
 	FrustumComponent& camFr = cam.getComponent<FrustumComponent>();
@@ -182,15 +181,7 @@ Error Dbg::run(CommandBufferPtr& cmdb)
 	}
 #endif
 
-	err = m_drawer->flush();
-
-	if(!err)
-	{
-		m_drawer->finishDraw();
-		cmdb.enableDepthTest(false);
-	}
-
-	return err;
+	return m_drawer->flush();
 }
 
 } // end namespace anki

+ 24 - 10
src/renderer/DebugDrawer.cpp

@@ -6,12 +6,14 @@
 #include "anki/renderer/DebugDrawer.h"
 #include "anki/renderer/Renderer.h"
 #include "anki/resource/ShaderResource.h"
-#include "anki/Collision.h"
-#include "anki/Scene.h"
 #include "anki/resource/TextureResource.h"
 #include "anki/renderer/Renderer.h"
+#include "anki/renderer/Pps.h"
+#include "anki/renderer/Ms.h"
 #include "anki/util/Logger.h"
 #include "anki/physics/PhysicsWorld.h"
+#include "anki/Collision.h"
+#include "anki/Scene.h"
 
 namespace anki {
 
@@ -36,6 +38,22 @@ Error DebugDrawer::create(Renderer* r)
 	ANKI_CHECK(m_frag.load("shaders/Dbg.frag.glsl", &r->getResourceManager()));
 
 	PipelinePtr::Initializer init;
+	init.m_vertex.m_bindingCount = 1;
+	init.m_vertex.m_bindings[0].m_stride = 2 * sizeof(Vec4);
+	init.m_vertex.m_attributeCount = 2;
+	init.m_vertex.m_attributes[0].m_format =
+		PixelFormat(ComponentFormat::R32G32B32A32, TransformFormat::FLOAT);
+	init.m_vertex.m_attributes[0].m_offset = 0;
+	init.m_vertex.m_attributes[0].m_binding = 0;
+	init.m_vertex.m_attributes[1].m_format =
+		PixelFormat(ComponentFormat::R32G32B32A32, TransformFormat::FLOAT);
+	init.m_vertex.m_attributes[1].m_offset = sizeof(Vec4);
+	init.m_vertex.m_attributes[1].m_binding = 0;
+	init.m_inputAssembler.m_topology = PrimitiveTopology::LINES;
+	init.m_depthStencil.m_depthWriteEnabled = false;
+	init.m_depthStencil.m_format = Ms::DEPTH_RT_PIXEL_FORMAT;
+	init.m_color.m_attachmentCount = 1;
+	init.m_color.m_attachments[0].m_format = Pps::RT_PIXEL_FORMAT;
 	init.m_shaders[U(ShaderType::VERTEX)] = m_vert->getGrShader();
 	init.m_shaders[U(ShaderType::FRAGMENT)] = m_frag->getGrShader();
 
@@ -139,17 +157,13 @@ Error DebugDrawer::flushInternal(GLenum primitive)
 
 	U size = sizeof(Vertex) * clientVerts;
 
-	m_vertBuff.write(m_jobs, vertBuff, size, 0, 0, size);
-
-	m_ppline.bind(m_jobs);
+	m_vertBuff.write(m_cmdb, vertBuff, size, 0, 0, size);
 
-	m_vertBuff.bindVertexBuffer(m_jobs,
-		4, GL_FLOAT, false, sizeof(Vertex), 0, 0); // Pos
+	m_ppline.bind(m_cmdb);
 
-	m_vertBuff.bindVertexBuffer(m_jobs,
-		4, GL_FLOAT, true, sizeof(Vertex), sizeof(Vec4), 1); // Color
+	m_cmdb.bindVertexBuffer(0, m_vertBuff, 0);
 
-	m_jobs.drawArrays(primitive, clientVerts);
+	m_cmdb.drawArrays(primitive, clientVerts);
 
 	return err;
 }

+ 4 - 42
src/renderer/Drawer.cpp

@@ -39,7 +39,7 @@ public:
 	F32 m_flod;
 
 	SetupRenderableVariableVisitor(RenderableDrawer* drawer)
-	:	m_drawer(drawer)
+		: m_drawer(drawer)
 	{}
 
 	HeapAllocator<U8> getAllocator() const
@@ -315,48 +315,21 @@ Error RenderableDrawer::render(SceneNode& frsn, VisibleNode& visibleNode)
 	build.m_key.m_pass = m_pass;
 	build.m_key.m_tessellation =
 		m_r->getTessellationEnabled()
-		&& mtl.getTessellation()
+		&& mtl.getTessellationEnabled()
 		&& build.m_key.m_lod == 0;
 
-	if(m_pass == Pass::DEPTH)
+	if(m_pass == Pass::SM)
 	{
 		build.m_key.m_tessellation = false;
 	}
 
-	// Blending
-	Bool blending = mtl.isBlendingEnabled();
-	if(!blending)
-	{
-		if(m_stage == RenderingStage::BLEND)
-		{
-			return ErrorCode::NONE;
-		}
-	}
-	else
-	{
-		if(m_stage != RenderingStage::BLEND)
-		{
-			return ErrorCode::NONE;
-		}
-
-		m_cmdBuff.setBlendFunctions(
-			mtl.getBlendingSfactor(), mtl.getBlendingDfactor());
-	}
-
-	// Wireframe
-	Bool wireframeOn = mtl.getWireframeEnabled();
-	if(wireframeOn)
-	{
-		m_cmdBuff.setPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-	}
-
 	// Enqueue uniform state updates
 	setupUniforms(visibleNode, renderable, fr, flod);
 
 	// Enqueue vertex, program and drawcall
 	build.m_subMeshIndicesArray = &visibleNode.m_spatialIndices[0];
 	build.m_subMeshIndicesCount = visibleNode.m_spatialsCount;
-	build.m_jobs = m_cmdBuff;
+	build.m_cmdb = m_cmdBuff;
 
 	Error err = renderable.buildRendering(build);
 	if(err)
@@ -364,12 +337,6 @@ Error RenderableDrawer::render(SceneNode& frsn, VisibleNode& visibleNode)
 		return err;
 	}
 
-	// Wireframe back to what it was
-	if(wireframeOn)
-	{
-		m_cmdBuff.setPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-	}
-
 	return ErrorCode::NONE;
 }
 
@@ -381,11 +348,6 @@ void RenderableDrawer::prepareDraw(RenderingStage stage, Pass pass,
 	m_stage = stage;
 	m_pass = pass;
 	m_cmdBuff = cmdBuff;
-
-	if(m_r->getTessellationEnabled())
-	{
-		m_cmdBuff.setPatchVertexCount(3);
-	}
 }
 
 //==============================================================================

+ 0 - 57
src/renderer/Ez.cpp

@@ -1,57 +0,0 @@
-// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#include "anki/renderer/Ez.h"
-#include "anki/renderer/Renderer.h"
-#include "anki/core/App.h"
-#include "anki/scene/SceneGraph.h"
-#include "anki/scene/Camera.h"
-#include "anki/misc/ConfigSet.h"
-
-namespace anki {
-
-//==============================================================================
-Error Ez::init(const ConfigSet& config)
-{
-	m_enabled = config.getNumber("ms.ez.enabled");
-	m_maxObjectsToDraw = config.getNumber("ms.ez.maxObjectsToDraw");
-
-	return ErrorCode::NONE;
-}
-
-//==============================================================================
-Error Ez::run(CommandBufferPtr& cmdBuff)
-{
-	ANKI_ASSERT(m_enabled);
-
-	Error err = ErrorCode::NONE;
-	SceneNode& cam = m_r->getActiveCamera();
-	FrustumComponent& camFr = cam.getComponent<FrustumComponent>();
-
-	m_r->getSceneDrawer().prepareDraw(
-		RenderingStage::MATERIAL, Pass::DEPTH, cmdBuff);
-
-	U count = m_maxObjectsToDraw;
-	auto it = camFr.getVisibilityTestResults().getRenderablesBegin();
-	auto end = camFr.getVisibilityTestResults().getRenderablesEnd();
-	for(; it != end; ++it)
-	{
-		err = m_r->getSceneDrawer().render(cam, *it);
-
-		if(--count == 0 || err)
-		{
-			break;
-		}
-	}
-
-	if(!err)
-	{
-		m_r->getSceneDrawer().finishDraw();
-	}
-
-	return err;
-}
-
-} // end namespace anki

+ 1 - 7
src/renderer/Fs.cpp

@@ -39,11 +39,8 @@ Error Fs::run(CommandBufferPtr& cmdb)
 
 	m_fb.bind(cmdb);
 
-	cmdb.enableDepthTest(true);
-	cmdb.enableBlend(true);
-
 	RenderableDrawer& drawer = m_r->getSceneDrawer();
-	drawer.prepareDraw(RenderingStage::BLEND, Pass::COLOR, cmdb);
+	drawer.prepareDraw(RenderingStage::BLEND, Pass::MS_FS, cmdb);
 
 	SceneNode& cam = m_r->getActiveCamera();
 	FrustumComponent& camFr = cam.getComponent<FrustumComponent>();
@@ -58,9 +55,6 @@ Error Fs::run(CommandBufferPtr& cmdb)
 	if(!err)
 	{
 		drawer.finishDraw();
-
-		cmdb.enableDepthTest(false);
-		cmdb.enableBlend(false);
 	}
 
 	return err;

+ 25 - 26
src/renderer/Is.cpp

@@ -119,10 +119,14 @@ public:
 	}
 };
 
+//==============================================================================
+const PixelFormat Is::RT_PIXEL_FORMAT(
+	ComponentFormat::R11G11B10, TransformFormat::FLOAT);
+
 //==============================================================================
 Is::Is(Renderer* r)
-:	RenderingPass(r),
-	m_sm(r)
+	: RenderingPass(r)
+	, m_sm(r)
 {}
 
 //==============================================================================
@@ -210,18 +214,22 @@ Error Is::initInternal(const ConfigSet& config)
 		"shaders/IsLp.frag.glsl", pps.toCString(), "r_"));
 
 	PipelinePtr::Initializer init;
-		init.m_shaders[U(ShaderType::VERTEX)] = m_lightVert->getGrShader();
-		init.m_shaders[U(ShaderType::FRAGMENT)] = m_lightFrag->getGrShader();
+
+	init.m_inputAssembler.m_topology = PrimitiveTopology::TRIANGLE_STRIP;
+	init.m_depthStencil.m_depthWriteEnabled = false;
+	init.m_depthStencil.m_depthCompareFunction = CompareOperation::ALWAYS;
+	init.m_color.m_attachmentCount = 1;
+	init.m_color.m_attachments[0].m_format = RT_PIXEL_FORMAT;
+	init.m_shaders[U(ShaderType::VERTEX)] = m_lightVert->getGrShader();
+	init.m_shaders[U(ShaderType::FRAGMENT)] = m_lightFrag->getGrShader();
 	m_lightPpline.create(&getGrManager(), init);
 
 	//
 	// Create framebuffer
 	//
-
 	m_r->createRenderTarget(
 		m_r->getWidth(), m_r->getHeight(),
-		PixelFormat(ComponentFormat::R11G11B10, TransformFormat::FLOAT),
-		1, SamplingFilter::LINEAR, MIPMAPS_COUNT, m_rt);
+		RT_PIXEL_FORMAT, 1, SamplingFilter::LINEAR, MIPMAPS_COUNT, m_rt);
 
 	FramebufferPtr::Initializer fbInit;
 	fbInit.m_colorAttachmentsCount = 1;
@@ -230,15 +238,6 @@ Error Is::initInternal(const ConfigSet& config)
 		AttachmentLoadOperation::DONT_CARE;
 	m_fb.create(&getGrManager(), fbInit);
 
-	//
-	// Init the quad
-	//
-	static const F32 quadVertCoords[][2] =
-		{{1.0, 1.0}, {0.0, 1.0}, {1.0, 0.0}, {0.0, 0.0}};
-
-	m_quadPositionsVertBuff.create(&getGrManager(), GL_ARRAY_BUFFER,
-		&quadVertCoords[0][0], sizeof(quadVertCoords), 0);
-
 	//
 	// Create UBOs
 	//
@@ -376,19 +375,22 @@ Error Is::lightPass(CommandBufferPtr& cmdBuff)
 	if(visiblePointLightsCount)
 	{
 		taskData.m_pointLights = SArray<shader::PointLight>(
-			lightsBase + pointLightsOffset, visiblePointLightsCount);
+			reinterpret_cast<shader::PointLight*>(
+			lightsBase + pointLightsOffset), visiblePointLightsCount);
 	}
 
 	if(visibleSpotLightsCount)
 	{
 		taskData.m_spotLights = SArray<shader::SpotLight>(
-			lightsBase + spotLightsOffset, visibleSpotLightsCount);
+			reinterpret_cast<shader::SpotLight*>(lightsBase + spotLightsOffset),
+			visibleSpotLightsCount);
 	}
 
 	if(visibleSpotTexLightsCount)
 	{
 		taskData.m_spotTexLights = SArray<shader::SpotLight>(
-			lightsBase + spotTexLightsOffset, visibleSpotTexLightsCount);
+			reinterpret_cast<shader::SpotLight*>(
+			lightsBase + spotTexLightsOffset), visibleSpotTexLightsCount);
 	}
 
 	taskData.m_lightsBegin = vi.getLightsBegin();
@@ -452,7 +454,7 @@ Error Is::lightPass(CommandBufferPtr& cmdBuff)
 		m_r->getMs().getRt1(),
 		m_r->getMs().getRt2(),
 		m_r->getMs().getDepthRt(),
-		m_sm.m_sm2DArrayTex}};
+		m_sm.getTextureArray()}};
 
 	cmdBuff.bindTextures(0, tarr.begin(), tarr.getSize());
 
@@ -462,9 +464,6 @@ Error Is::lightPass(CommandBufferPtr& cmdBuff)
 
 	m_lightPpline.bind(cmdBuff);
 
-	m_quadPositionsVertBuff.bindVertexBuffer(cmdBuff,
-		2, GL_FLOAT, false, 0, 0, 0);
-
 	cmdBuff.drawArrays(GL_TRIANGLE_STRIP, 4, m_r->getTilesCountXY());
 
 	return err;
@@ -526,7 +525,7 @@ void Is::binLights(U32 threadId, PtrSize threadsCount, TaskCommonData& task)
 	U tilesCount = tilesCount2d.x() * tilesCount2d.y();
 
 	SArray<shader::Tile> stiles(
-		m_tilesBufferAddresses[m_currentFrame],
+		reinterpret_cast<shader::Tile*>(m_tilesBufferAddresses[m_currentFrame]),
 		tilesCount);
 
 	Threadpool::Task::choseStartEnd(
@@ -551,8 +550,8 @@ void Is::binLights(U32 threadId, PtrSize threadsCount, TaskCommonData& task)
 		if(offset + count <= m_maxLightIds)
 		{
 			SArray<Lid> lightIds(
-				m_lightIdsBufferAddresses[m_currentFrame],
-				m_maxLightIds);
+				reinterpret_cast<Lid*>(
+				m_lightIdsBufferAddresses[m_currentFrame]), m_maxLightIds);
 
 			t.m_offset = offset;
 

+ 37 - 15
src/renderer/Lf.cpp

@@ -5,6 +5,8 @@
 
 #include "anki/renderer/Lf.h"
 #include "anki/renderer/Bloom.h"
+#include "anki/renderer/Is.h"
+#include "anki/renderer/Ms.h"
 #include "anki/renderer/Renderer.h"
 #include "anki/scene/SceneGraph.h"
 #include "anki/scene/MoveComponent.h"
@@ -61,7 +63,7 @@ Error Lf::initSprite(const ConfigSet& config)
 		return ErrorCode::USER_DATA;
 	}
 
-	// Load program + ppline
+	// Load shaders
 	StringAuto pps(getAllocator());
 
 	pps.sprintf("#define MAX_SPRITES %u\n", m_maxSpritesPerFlare);
@@ -72,7 +74,16 @@ Error Lf::initSprite(const ConfigSet& config)
 	ANKI_CHECK(m_realFrag.loadToCache(&getResourceManager(),
 		"shaders/LfSpritePass.frag.glsl", pps.toCString(), "r_"));
 
+	// Create ppline.
+	// Writes to IS with blending
 	PipelinePtr::Initializer init;
+	init.m_inputAssembler.m_topology = PrimitiveTopology::TRIANGLE_STRIP;
+	init.m_depthStencil.m_depthWriteEnabled = false;
+	init.m_depthStencil.m_depthCompareFunction = CompareOperation::ALWAYS;
+	init.m_color.m_attachmentCount = 1;
+	init.m_color.m_attachments[0].m_format = Is::RT_PIXEL_FORMAT;
+	init.m_color.m_attachments[0].m_srcBlendMethod = BlendMethod::ONE;
+	init.m_color.m_attachments[0].m_dstBlendMethod = BlendMethod::ONE;
 	init.m_shaders[U(ShaderType::VERTEX)] = m_realVert->getGrShader();
 	init.m_shaders[U(ShaderType::FRAGMENT)] = m_realFrag->getGrShader();
 	m_realPpline.create(&getGrManager(), init);
@@ -118,10 +129,31 @@ Error Lf::initOcclusion(const ConfigSet& config)
 	ANKI_CHECK(m_occlusionFrag.load("shaders/LfOcclusion.frag.glsl",
 		&getResourceManager()));
 
+	// Create ppline
+	// - only position attribute
+	// - points
+	// - test depth no write
+	// - will run after MS
+	// - will not update color
 	PipelinePtr::Initializer init;
-		init.m_shaders[U(ShaderType::VERTEX)] = m_occlusionVert->getGrShader();
-		init.m_shaders[U(ShaderType::FRAGMENT)] =
-			m_occlusionFrag->getGrShader();
+	init.m_vertex.m_bindingCount = 1;
+	init.m_vertex.m_bindings[0].m_stride = sizeof(Vec3);
+	init.m_vertex.m_attributeCount = 1;
+	init.m_vertex.m_attributes[0].m_format =
+		PixelFormat(ComponentFormat::R32G32B32, TransformFormat::FLOAT);
+	init.m_inputAssembler.m_topology = PrimitiveTopology::POINTS;
+	init.m_depthStencil.m_depthWriteEnabled = false;
+	init.m_depthStencil.m_format = Ms::DEPTH_RT_PIXEL_FORMAT;
+	ANKI_ASSERT(Ms::ATTACHMENT_COUNT == 3);
+	init.m_color.m_attachmentCount = Ms::ATTACHMENT_COUNT;
+	init.m_color.m_attachments[0].m_format = Ms::RT_PIXEL_FORMATS[0];
+	init.m_color.m_attachments[0].m_channelWriteMask = ColorBit::NONE;
+	init.m_color.m_attachments[1].m_format = Ms::RT_PIXEL_FORMATS[1];
+	init.m_color.m_attachments[1].m_channelWriteMask = ColorBit::NONE;
+	init.m_color.m_attachments[2].m_format = Ms::RT_PIXEL_FORMATS[2];
+	init.m_color.m_attachments[2].m_channelWriteMask = ColorBit::NONE;
+	init.m_shaders[U(ShaderType::VERTEX)] = m_occlusionVert->getGrShader();
+	init.m_shaders[U(ShaderType::FRAGMENT)] = m_occlusionFrag->getGrShader();
 	m_occlusionPpline.create(&getGrManager(), init);
 
 	return ErrorCode::NONE;
@@ -153,8 +185,6 @@ void Lf::runOcclusionTests(CommandBufferPtr& cmdb)
 		}
 
 		// Setup state
-		cmdb.setColorWriteMask(false, false, false, false);
-		cmdb.enableDepthTest(true);
 		m_occlusionPpline.bind(cmdb);
 
 		// Setup MVP UBO
@@ -196,10 +226,6 @@ void Lf::runOcclusionTests(CommandBufferPtr& cmdb)
 		}
 
 		ANKI_ASSERT(positions == initialPositions + totalCount);
-
-		// Restore state
-		cmdb.setColorWriteMask(true, true, true, true);
-		cmdb.enableDepthTest(false);
 	}
 }
 
@@ -221,8 +247,6 @@ void Lf::run(CommandBufferPtr& cmdb)
 
 		// Set common rendering state
 		m_realPpline.bind(cmdb);
-		cmdb.enableBlend(true);
-		cmdb.setBlendFunctions(GL_ONE, GL_ONE);
 
 		// Send the command to write the buffer now
 		BufferPtr& flareDataBuff = m_flareDataBuff[
@@ -280,7 +304,7 @@ void Lf::run(CommandBufferPtr& cmdb)
 
 			if(!queryInvalid)
 			{
-				m_r->drawQuadConditional(query, cmdb);
+				cmdb.drawArraysConditional(query, GL_TRIANGLE_STRIP, 4);
 			}
 			else
 			{
@@ -300,8 +324,6 @@ void Lf::run(CommandBufferPtr& cmdb)
 
 		ANKI_ASSERT(
 			reinterpret_cast<U8*>(sprites) <= spritesInitialPtr + bufferSize);
-
-		cmdb.enableBlend(false);
 	}
 }
 

+ 8 - 17
src/renderer/MainRenderer.cpp

@@ -8,6 +8,7 @@
 #include "anki/renderer/Is.h"
 #include "anki/renderer/Pps.h"
 #include "anki/renderer/Dbg.h"
+#include "anki/renderer/Ms.h"
 #include "anki/scene/SceneGraph.h"
 #include "anki/scene/Camera.h"
 #include "anki/util/Logger.h"
@@ -61,8 +62,6 @@ Error MainRenderer::create(
 	ANKI_CHECK(m_r->init(threadpool, resources, gr, m_alloc,
 		m_frameAlloc, config2, globalTimestamp));
 
-	initGl();
-
 	// Set the default preprocessor string
 	m_materialShaderSource.sprintf(
 		m_alloc,
@@ -74,8 +73,12 @@ Error MainRenderer::create(
 	ANKI_CHECK(m_blitFrag.load(
 		"shaders/Final.frag.glsl", &m_r->getResourceManager()));
 
-	ANKI_CHECK(m_r->createDrawQuadPipeline(
-		m_blitFrag->getGrShader(), m_blitPpline));
+	ColorStateInfo colorState;
+	colorState.m_attachmentCount = 1;
+	colorState.m_attachments[0].m_format =
+		PixelFormat(ComponentFormat::R8G8B8, TransformFormat::UNORM);
+	m_r->createDrawQuadPipeline(
+		m_blitFrag->getGrShader(), colorState, m_blitPpline);
 
 	ANKI_LOGI("Main renderer initialized. Rendering size %dx%d",
 		m_width, m_height);
@@ -139,7 +142,7 @@ Error MainRenderer::render(SceneGraph& scene)
 			rt = &m_r->getIs()._getRt();
 		}
 
-		//rt = &getMs().getRt2();
+		//rt = &m_r->getMs().getRt2();
 		//rt = &getPps().getHdr()._getRt();
 
 		rt->bind(cmdb, 0);
@@ -161,18 +164,6 @@ Error MainRenderer::render(SceneGraph& scene)
 	return ErrorCode::NONE;
 }
 
-//==============================================================================
-void MainRenderer::initGl()
-{
-	CommandBufferPtr cmdb;
-	cmdb.create(&m_r->getGrManager());
-
-	cmdb.enableCulling(true);
-	cmdb.setCullFace(GL_BACK);
-	cmdb.enablePointSize(true);
-	cmdb.flush();
-}
-
 //==============================================================================
 Dbg& MainRenderer::getDbg()
 {

+ 17 - 31
src/renderer/Ms.cpp

@@ -4,7 +4,6 @@
 // http://www.anki3d.org/LICENSE
 
 #include "anki/renderer/Ms.h"
-#include "anki/renderer/Ez.h"
 #include "anki/renderer/Renderer.h"
 
 #include "anki/util/Logger.h"
@@ -14,6 +13,15 @@
 
 namespace anki {
 
+//==============================================================================
+const Array<PixelFormat, Ms::ATTACHMENT_COUNT> Ms::RT_PIXEL_FORMATS = {
+	PixelFormat(ComponentFormat::R8G8B8A8, TransformFormat::UNORM),
+	PixelFormat(ComponentFormat::R8G8B8A8, TransformFormat::UNORM),
+	PixelFormat(ComponentFormat::R10G10B10A2, TransformFormat::UNORM)};
+
+const PixelFormat Ms::DEPTH_RT_PIXEL_FORMAT(
+	ComponentFormat::D24, TransformFormat::FLOAT);
+
 //==============================================================================
 Ms::~Ms()
 {}
@@ -24,20 +32,17 @@ Error Ms::createRt(U32 index, U32 samples)
 	Plane& plane = m_planes[index];
 
 	m_r->createRenderTarget(m_r->getWidth(), m_r->getHeight(),
-		PixelFormat(ComponentFormat::D24, TransformFormat::FLOAT),
-		samples, SamplingFilter::NEAREST, 4, plane.m_depthRt);
+		DEPTH_RT_PIXEL_FORMAT, samples, SamplingFilter::NEAREST, 4,
+		plane.m_depthRt);
 
 	m_r->createRenderTarget(m_r->getWidth(), m_r->getHeight(),
-		PixelFormat(ComponentFormat::R8G8B8A8, TransformFormat::UNORM),
-		samples, SamplingFilter::NEAREST, 1, plane.m_rt0);
+		RT_PIXEL_FORMATS[0], samples, SamplingFilter::NEAREST, 1, plane.m_rt0);
 
 	m_r->createRenderTarget(m_r->getWidth(), m_r->getHeight(),
-		PixelFormat(ComponentFormat::R8G8B8A8, TransformFormat::UNORM),
-		samples, SamplingFilter::NEAREST, 1, plane.m_rt1);
+		RT_PIXEL_FORMATS[1], samples, SamplingFilter::NEAREST, 1, plane.m_rt1);
 
 	m_r->createRenderTarget(m_r->getWidth(), m_r->getHeight(),
-		PixelFormat(ComponentFormat::R10G10B10A2, TransformFormat::UNORM),
-		samples, SamplingFilter::NEAREST, 1, plane.m_rt2);
+		RT_PIXEL_FORMATS[2], samples, SamplingFilter::NEAREST, 1, plane.m_rt2);
 
 	AttachmentLoadOperation loadop = AttachmentLoadOperation::DONT_CARE;
 #if ANKI_DEBUG
@@ -45,7 +50,7 @@ Error Ms::createRt(U32 index, U32 samples)
 #endif
 
 	FramebufferPtr::Initializer fbInit;
-	fbInit.m_colorAttachmentsCount = 3;
+	fbInit.m_colorAttachmentsCount = ATTACHMENT_COUNT;
 	fbInit.m_colorAttachments[0].m_texture = plane.m_rt0;
 	fbInit.m_colorAttachments[0].m_loadOperation = loadop;
 	fbInit.m_colorAttachments[1].m_texture = plane.m_rt1;
@@ -83,7 +88,6 @@ Error Ms::initInternal(const ConfigSet& initializer)
 	}
 
 	ANKI_CHECK(createRt(1, 1));
-	ANKI_CHECK(m_ez.init(initializer));
 
 	return ErrorCode::NONE;
 }
@@ -100,26 +104,11 @@ Error Ms::run(CommandBufferPtr& cmdb)
 
 	cmdb.setViewport(0, 0, m_r->getWidth(), m_r->getHeight());
 
-	cmdb.enableDepthTest(true);
-	cmdb.setDepthWriteMask(true);
-
 	m_planes[planeId].m_fb.bind(cmdb);
 
-	/*if(m_ez.getEnabled())
-	{
-		cmdb.setDepthFunction(GL_LESS);
-		cmdb.setColorWriteMask(false, false, false, false);
-
-		err = m_ez.run(cmdb);
-		if(err) return err;
-
-		cmdb.setDepthFunction(GL_LEQUAL);
-		cmdb.setColorWriteMask(true, true, true, true);
-	}*/
-
 	// render all
-	m_r->getSceneDrawer().prepareDraw(RenderingStage::MATERIAL, Pass::COLOR,
-		cmdb);
+	m_r->getSceneDrawer().prepareDraw(
+		RenderingStage::MATERIAL, Pass::MS_FS, cmdb);
 
 	SceneNode& cam = m_r->getActiveCamera();
 
@@ -147,9 +136,6 @@ Error Ms::run(CommandBufferPtr& cmdb)
 		ANKI_ASSERT(0 && "TODO");
 	}
 
-	cmdb.enableDepthTest(false);
-	cmdb.setDepthWriteMask(false);
-
 	return ErrorCode::NONE;
 }
 

+ 9 - 3
src/renderer/Pps.cpp

@@ -17,6 +17,10 @@
 
 namespace anki {
 
+//==============================================================================
+const PixelFormat Pps::RT_PIXEL_FORMAT(
+	ComponentFormat::R8G8B8, TransformFormat::UNORM);
+
 //==============================================================================
 Pps::Pps(Renderer* r)
 	: RenderingPass(r)
@@ -55,8 +59,7 @@ Error Pps::initInternal(const ConfigSet& config)
 	// FBO
 	m_r->createRenderTarget(
 		m_r->getWidth(), m_r->getHeight(),
-		PixelFormat(ComponentFormat::R8G8B8, TransformFormat::UNORM),
-		1, SamplingFilter::LINEAR, 1, m_rt);
+		RT_PIXEL_FORMAT, 1, SamplingFilter::LINEAR, 1, m_rt);
 
 	FramebufferPtr::Initializer fbInit;
 	fbInit.m_colorAttachmentsCount = 1;
@@ -87,7 +90,10 @@ Error Pps::initInternal(const ConfigSet& config)
 	ANKI_CHECK(m_frag.loadToCache(&getResourceManager(),
 		"shaders/Pps.frag.glsl", pps.toCString(), "r_"));
 
-	ANKI_CHECK(m_r->createDrawQuadPipeline(m_frag->getGrShader(), m_ppline));
+	ColorStateInfo colorState;
+	colorState.m_attachmentCount = 1;
+	colorState.m_attachments[0].m_format = RT_PIXEL_FORMAT;
+	m_r->createDrawQuadPipeline(m_frag->getGrShader(), colorState, m_ppline);
 
 	// LUT
 	ANKI_CHECK(loadColorGradingTexture("engine_data/default_lut.ankitex"));

+ 14 - 16
src/renderer/Renderer.cpp

@@ -98,12 +98,6 @@ Error Renderer::initInternal(const ConfigSet& config)
 	ANKI_CHECK(m_sceneDrawer.create(this));
 
 	// quad setup
-	static const F32 quadVertCoords[][2] = {{1.0, 1.0}, {-1.0, 1.0},
-		{1.0, -1.0}, {-1.0, -1.0}};
-
-	m_quadPositionsBuff.create(m_gr, GL_ARRAY_BUFFER,
-		&quadVertCoords[0][0], sizeof(quadVertCoords), 0);
-
 	ANKI_CHECK(m_drawQuadVert.load("shaders/Quad.vert.glsl", m_resources));
 
 	// Init the stages. Careful with the order!!!!!!!!!!
@@ -193,17 +187,14 @@ void Renderer::drawQuad(CommandBufferPtr& cmdBuff)
 void Renderer::drawQuadConditional(OcclusionQueryPtr& q,
 	CommandBufferPtr& cmdBuff)
 {
-	m_quadPositionsBuff.bindVertexBuffer(cmdBuff, 2, GL_FLOAT, false, 0, 0, 0);
-	cmdBuff.drawArraysConditional(q, GL_TRIANGLE_STRIP, 4, 1);
+	cmdBuff.drawArraysConditional(q, GL_TRIANGLES, 3, 1);
 }
 
 //==============================================================================
 void Renderer::drawQuadInstanced(
 	CommandBufferPtr& cmdBuff, U32 primitiveCount)
 {
-	m_quadPositionsBuff.bindVertexBuffer(cmdBuff, 2, GL_FLOAT, false, 0, 0, 0);
-
-	cmdBuff.drawArrays(GL_TRIANGLE_STRIP, 4, primitiveCount);
+	cmdBuff.drawArrays(GL_TRIANGLES, 3, primitiveCount);
 }
 
 //==============================================================================
@@ -229,7 +220,7 @@ Vec3 Renderer::unproject(const Vec3& windowCoords, const Mat4& modelViewMat,
 void Renderer::createRenderTarget(U32 w, U32 h, const PixelFormat& format,
 	U32 samples, SamplingFilter filter, U mipsCount, TexturePtr& rt)
 {
-	// Not very important but keep the resulution of render targets aligned to
+	// Not very important but keep the resolution of render targets aligned to
 	// 16
 	if(0)
 	{
@@ -266,15 +257,22 @@ void Renderer::createRenderTarget(U32 w, U32 h, const PixelFormat& format,
 }
 
 //==============================================================================
-Error Renderer::createDrawQuadPipeline(
-	ShaderPtr frag, PipelinePtr& ppline)
+void Renderer::createDrawQuadPipeline(
+	ShaderPtr frag, const ColorStateInfo& colorState,
+	PipelinePtr& ppline)
 {
 	PipelinePtr::Initializer init;
+
+	init.m_inputAssembler.m_topology = PrimitiveTopology::TRIANGLE_STRIP;
+
+	init.m_depthStencil.m_depthWriteEnabled = false;
+	init.m_depthStencil.m_depthCompareFunction = CompareOperation::ALWAYS;
+
+	init.m_color = colorState;
+
 	init.m_shaders[U(ShaderType::VERTEX)] = m_drawQuadVert->getGrShader();
 	init.m_shaders[U(ShaderType::FRAGMENT)] = frag;
 	ppline.create(m_gr, init);
-
-	return ErrorCode::NONE;
 }
 
 //==============================================================================

+ 0 - 72
src/renderer/RenderingPass.cpp

@@ -45,77 +45,5 @@ ResourceManager& RenderingPass::getResourceManager()
 	return m_r->getResourceManager();
 }
 
-//==============================================================================
-Error BlurringRenderingPass::initBlurring(
-	Renderer& r, U width, U height, U samples, F32 blurringDistance)
-{
-	Array<StringAuto, 2> pps = {{getAllocator(), getAllocator()}};
-
-	pps[1].sprintf(
-		"#define HPASS\n"
-		"#define COL_RGB\n"
-		"#define BLURRING_DIST float(%f)\n"
-		"#define IMG_DIMENSION %u\n"
-		"#define SAMPLES %u\n",
-		blurringDistance, height, samples);
-
-	pps[0].sprintf(
-		"#define VPASS\n"
-		"#define COL_RGB\n"
-		"#define BLURRING_DIST float(%f)\n"
-		"#define IMG_DIMENSION %u\n"
-		"#define SAMPLES %u\n",
-		blurringDistance, width, samples);
-
-	for(U i = 0; i < 2; i++)
-	{
-		Direction& dir = m_dirs[i];
-
-		r.createRenderTarget(width, height,
-			PixelFormat(ComponentFormat::R8G8B8, TransformFormat::UNORM),
-			1, SamplingFilter::LINEAR, 1, dir.m_rt);
-
-		// Create FB
-		FramebufferPtr::Initializer fbInit;
-		fbInit.m_colorAttachmentsCount = 1;
-		fbInit.m_colorAttachments[0].m_texture = dir.m_rt;
-		fbInit.m_colorAttachments[0].m_loadOperation =
-			AttachmentLoadOperation::DONT_CARE;
-		dir.m_fb.create(&getGrManager(), fbInit);
-
-		ANKI_CHECK(dir.m_frag.loadToCache(&getResourceManager(),
-			"shaders/VariableSamplingBlurGeneric.frag.glsl",
-			pps[i].toCString(), "r_"));
-
-		ANKI_CHECK(r.createDrawQuadPipeline(
-			dir.m_frag->getGrShader(), dir.m_ppline));
-	}
-
-	return ErrorCode::NONE;
-}
-
-//==============================================================================
-void BlurringRenderingPass::runBlurring(Renderer& r, CommandBufferPtr& cmdb)
-{
-	// H pass input
-	m_dirs[enumToValue(DirectionEnum::VERTICAL)].m_rt.bind(cmdb, 1);
-
-	// V pass input
-	m_dirs[enumToValue(DirectionEnum::HORIZONTAL)].m_rt.bind(cmdb, 0);
-
-	for(U32 i = 0; i < m_blurringIterationsCount; i++)
-	{
-		// hpass
-		m_dirs[enumToValue(DirectionEnum::HORIZONTAL)].m_fb.bind(cmdb);
-		m_dirs[enumToValue(DirectionEnum::HORIZONTAL)].m_ppline.bind(cmdb);
-		r.drawQuad(cmdb);
-
-		// vpass
-		m_dirs[enumToValue(DirectionEnum::VERTICAL)].m_fb.bind(cmdb);
-		m_dirs[enumToValue(DirectionEnum::VERTICAL)].m_ppline.bind(cmdb);
-		r.drawQuad(cmdb);
-	}
-}
-
 } // end namespace anki
 

+ 6 - 17
src/renderer/Sm.cpp

@@ -14,6 +14,10 @@
 
 namespace anki {
 
+//==============================================================================
+const PixelFormat Sm::DEPTH_RT_PIXEL_FORMAT(
+	ComponentFormat::D16, TransformFormat::FLOAT);
+
 //==============================================================================
 Error Sm::init(const ConfigSet& config)
 {
@@ -43,7 +47,7 @@ Error Sm::init(const ConfigSet& config)
 	sminit.m_width = m_resolution;
 	sminit.m_height = m_resolution;
 	sminit.m_depth = config.getNumber("is.sm.maxLights");
-	sminit.m_format = PixelFormat(ComponentFormat::D16, TransformFormat::FLOAT);
+	sminit.m_format = DEPTH_RT_PIXEL_FORMAT;
 	sminit.m_mipmapsCount = 1;
 	sminit.m_sampling.m_minMagFilter = m_bilinearEnabled
 		? SamplingFilter::LINEAR
@@ -82,29 +86,14 @@ Error Sm::init(const ConfigSet& config)
 //==============================================================================
 void Sm::prepareDraw(CommandBufferPtr& cmdBuff)
 {
-	// disable color & blend & enable depth test
-
-	cmdBuff.enableDepthTest(true);
-	cmdBuff.setDepthWriteMask(true);
-	cmdBuff.setColorWriteMask(false, false, false, false);
-
-	// for artifacts
-	cmdBuff.setPolygonOffset(7.0, 5.0); // keep both as low as possible!!!!
-	cmdBuff.enablePolygonOffset(true);
-
 	m_r->getSceneDrawer().prepareDraw(
-		RenderingStage::MATERIAL, Pass::DEPTH, cmdBuff);
+		RenderingStage::MATERIAL, Pass::SM, cmdBuff);
 }
 
 //==============================================================================
 void Sm::finishDraw(CommandBufferPtr& cmdBuff)
 {
 	m_r->getSceneDrawer().finishDraw();
-
-	cmdBuff.enableDepthTest(false);
-	cmdBuff.setDepthWriteMask(false);
-	cmdBuff.enablePolygonOffset(false);
-	cmdBuff.setColorWriteMask(true, true, true, true);
 }
 
 //==============================================================================

+ 15 - 8
src/renderer/Ssao.cpp

@@ -67,13 +67,16 @@ public:
 // Ssao                                                                        =
 //==============================================================================
 
+//==============================================================================
+const PixelFormat Ssao::RT_PIXEL_FORMAT(
+	ComponentFormat::R8, TransformFormat::UNORM);
+
 //==============================================================================
 Error Ssao::createFb(FramebufferPtr& fb, TexturePtr& rt)
 {
 	// Set to bilinear because the blurring techniques take advantage of that
 	m_r->createRenderTarget(m_width, m_height,
-		PixelFormat(ComponentFormat::R8, TransformFormat::UNORM),
-		1, SamplingFilter::LINEAR, 1, rt);
+		RT_PIXEL_FORMAT, 1, SamplingFilter::LINEAR, 1, rt);
 
 	// Create FB
 	FramebufferPtr::Initializer fbInit;
@@ -164,6 +167,10 @@ Error Ssao::initInternal(const ConfigSet& config)
 	m_uniformsBuff.create(&getGrManager(), GL_SHADER_STORAGE_BUFFER,
 		nullptr, sizeof(ShaderCommonUniforms), GL_DYNAMIC_STORAGE_BIT);
 
+	ColorStateInfo colorState;
+	colorState.m_attachmentCount = 1;
+	colorState.m_attachments[0].m_format = RT_PIXEL_FORMAT;
+
 	StringAuto pps(getAllocator());
 
 	// main pass prog
@@ -178,8 +185,8 @@ Error Ssao::initInternal(const ConfigSet& config)
 	ANKI_CHECK(m_ssaoFrag.loadToCache(&getResourceManager(),
 		"shaders/PpsSsao.frag.glsl", pps.toCString(), "r_"));
 
-	ANKI_CHECK(m_r->createDrawQuadPipeline(
-		m_ssaoFrag->getGrShader(), m_ssaoPpline));
+	m_r->createDrawQuadPipeline(
+		m_ssaoFrag->getGrShader(), colorState, m_ssaoPpline);
 
 	// blurring progs
 	const char* SHADER_FILENAME =
@@ -196,8 +203,8 @@ Error Ssao::initInternal(const ConfigSet& config)
 	ANKI_CHECK(m_hblurFrag.loadToCache(&getResourceManager(),
 		SHADER_FILENAME, pps.toCString(), "r_"));
 
-	ANKI_CHECK(m_r->createDrawQuadPipeline(
-		m_hblurFrag->getGrShader(), m_hblurPpline));
+	m_r->createDrawQuadPipeline(
+		m_hblurFrag->getGrShader(), colorState, m_hblurPpline);
 
 	pps.destroy(getAllocator());
 	pps.sprintf(
@@ -210,8 +217,8 @@ Error Ssao::initInternal(const ConfigSet& config)
 	ANKI_CHECK(m_vblurFrag.loadToCache(&getResourceManager(),
 		SHADER_FILENAME, pps.toCString(), "r_"));
 
-	ANKI_CHECK(m_r->createDrawQuadPipeline(
-		m_vblurFrag->getGrShader(), m_vblurPpline));
+	m_r->createDrawQuadPipeline(
+		m_vblurFrag->getGrShader(), colorState, m_vblurPpline);
 
 	cmdb.flush();
 

+ 9 - 3
src/renderer/Sslf.cpp

@@ -32,6 +32,9 @@ Error Sslf::initInternal(const ConfigSet& config)
 		return ErrorCode::NONE;
 	}
 
+	const PixelFormat pixelFormat(
+		ComponentFormat::R8G8B8, TransformFormat::UNORM);
+
 	// Load program 1
 	StringAuto pps(getAllocator());
 
@@ -43,7 +46,11 @@ Error Sslf::initInternal(const ConfigSet& config)
 	ANKI_CHECK(m_frag.loadToCache(&getResourceManager(),
 		"shaders/PpsSslf.frag.glsl", pps.toCString(), "r_"));
 
-	ANKI_CHECK(m_r->createDrawQuadPipeline(m_frag->getGrShader(), m_ppline));
+	ColorStateInfo colorState;
+	colorState.m_attachmentCount = 1;
+	colorState.m_attachments[0].m_format = pixelFormat;
+
+	m_r->createDrawQuadPipeline(m_frag->getGrShader(), colorState, m_ppline);
 
 	// Textures
 	ANKI_CHECK(m_lensDirtTex.load(
@@ -52,8 +59,7 @@ Error Sslf::initInternal(const ConfigSet& config)
 	// Create the render target and FB
 	m_r->createRenderTarget(m_r->getPps().getBloom().getWidth(),
 		m_r->getPps().getBloom().getHeight(),
-		PixelFormat(ComponentFormat::R8G8B8, TransformFormat::UNORM),
-		1, SamplingFilter::LINEAR, 1, m_rt);
+		pixelFormat, 1, SamplingFilter::LINEAR, 1, m_rt);
 
 	FramebufferPtr::Initializer fbInit;
 	fbInit.m_colorAttachmentsCount = 1;

+ 27 - 41
src/renderer/Sslr.cpp

@@ -25,8 +25,6 @@ Error Sslr::init(const ConfigSet& config)
 
 	// Size
 	const F32 quality = config.getNumber("pps.sslr.renderingQuality");
-	m_blurringIterationsCount =
-		config.getNumber("pps.sslr.blurringIterationsCount");
 
 	m_width = quality * (F32)m_r->getWidth();
 	alignRoundUp(16, m_width);
@@ -44,36 +42,36 @@ Error Sslr::init(const ConfigSet& config)
 	ANKI_CHECK(m_reflectionFrag.loadToCache(&getResourceManager(),
 		"shaders/PpsSslr.frag.glsl", pps.toCString(), "r_"));
 
-	ANKI_CHECK(m_r->createDrawQuadPipeline(
-		m_reflectionFrag->getGrShader(), m_reflectionPpline));
+	ColorStateInfo colorState;
+	colorState.m_attachmentCount = 1;
+	colorState.m_attachments[0].m_format = Is::RT_PIXEL_FORMAT;
+
+	m_r->createDrawQuadPipeline(
+		m_reflectionFrag->getGrShader(), colorState, m_reflectionPpline);
 
 	// Blit
 	ANKI_CHECK(
 		m_blitFrag.load("shaders/Blit.frag.glsl", &getResourceManager()));
-	ANKI_CHECK(
-		m_r->createDrawQuadPipeline(m_blitFrag->getGrShader(), m_blitPpline));
 
-	// Init FBOs and RTs and blurring
-	if(m_blurringIterationsCount > 0)
-	{
-		ANKI_CHECK(initBlurring(*m_r, m_width, m_height, 9, 0.0));
-	}
-	else
-	{
-		Direction& dir = m_dirs[U(DirectionEnum::VERTICAL)];
-
-		m_r->createRenderTarget(m_width, m_height,
-			PixelFormat(ComponentFormat::R11G11B10, TransformFormat::FLOAT),
-			1, SamplingFilter::LINEAR, 1, dir.m_rt);
-
-		// Create FB
-		FramebufferPtr::Initializer fbInit;
-		fbInit.m_colorAttachmentsCount = 1;
-		fbInit.m_colorAttachments[0].m_texture = dir.m_rt;
-		fbInit.m_colorAttachments[0].m_loadOperation =
-			AttachmentLoadOperation::LOAD;
-		dir.m_fb.create(&getGrManager(), fbInit);
-	}
+	colorState.m_attachmentCount = 1;
+	colorState.m_attachments[0].m_format = Is::RT_PIXEL_FORMAT;
+	colorState.m_attachments[0].m_srcBlendMethod = BlendMethod::ONE;
+	colorState.m_attachments[0].m_dstBlendMethod = BlendMethod::ONE;
+
+	m_r->createDrawQuadPipeline(
+		m_blitFrag->getGrShader(), colorState, m_blitPpline);
+
+	// Init FBOs
+	m_r->createRenderTarget(m_width, m_height,
+		Is::RT_PIXEL_FORMAT, 1, SamplingFilter::LINEAR, 1, m_rt);
+
+	// Create FB
+	FramebufferPtr::Initializer fbInit;
+	fbInit.m_colorAttachmentsCount = 1;
+	fbInit.m_colorAttachments[0].m_texture = m_rt;
+	fbInit.m_colorAttachments[0].m_loadOperation =
+		AttachmentLoadOperation::LOAD;
+	m_fb.create(&getGrManager(), fbInit);
 
 	return ErrorCode::NONE;
 }
@@ -85,7 +83,7 @@ void Sslr::run(CommandBufferPtr& cmdBuff)
 
 	// Compute the reflection
 	//
-	m_dirs[(U)DirectionEnum::VERTICAL].m_fb.bind(cmdBuff);
+	m_fb.bind(cmdBuff);
 	cmdBuff.setViewport(0, 0, m_width, m_height);
 
 	m_reflectionPpline.bind(cmdBuff);
@@ -103,27 +101,15 @@ void Sslr::run(CommandBufferPtr& cmdBuff)
 
 	SamplerPtr::bindDefault(cmdBuff, 1); // Unbind the sampler
 
-	// Blurring
-	//
-	if(m_blurringIterationsCount > 0)
-	{
-		runBlurring(*m_r, cmdBuff);
-	}
-
 	// Write the reflection back to IS RT
 	//
 	m_r->getIs().m_fb.bind(cmdBuff);
 	cmdBuff.setViewport(0, 0, m_r->getWidth(), m_r->getHeight());
 
-	cmdBuff.enableBlend(true);
-	cmdBuff.setBlendFunctions(GL_ONE, GL_ONE);
-
-	m_dirs[(U)DirectionEnum::VERTICAL].m_rt.bind(cmdBuff, 0);
+	m_rt.bind(cmdBuff, 0);
 
 	m_blitPpline.bind(cmdBuff);
 	m_r->drawQuad(cmdBuff);
-
-	cmdBuff.enableBlend(false);
 }
 
 } // end namespace anki

+ 1 - 1
src/renderer/Tiler.cpp

@@ -53,7 +53,7 @@ static Vec4 unproject(const F32 depth, const Vec2& ndc, const Vec4& projParams)
 
 //==============================================================================
 Tiler::Tiler(Renderer* r)
-:	RenderingPass(r)
+	: RenderingPass(r)
 {}
 
 //==============================================================================

+ 25 - 274
src/resource/Material.cpp

@@ -14,44 +14,11 @@
 #include "anki/util/File.h"
 #include "anki/util/Filesystem.h"
 #include "anki/misc/Xml.h"
-#include <functional> // TODO
 #include <algorithm>
 #include <sstream>
 
 namespace anki {
 
-//==============================================================================
-// Misc                                                                        =
-//==============================================================================
-
-//==============================================================================
-/// Given a string that defines blending return the GLenum
-static GLenum blendToEnum(const CString& str)
-{
-// Dont make idiotic mistakes
-#define TXT_AND_ENUM(x) \
-	if(str == #x) \
-	{ \
-		return x; \
-	}
-
-	TXT_AND_ENUM(GL_ZERO)
-	TXT_AND_ENUM(GL_ONE)
-	TXT_AND_ENUM(GL_DST_COLOR)
-	TXT_AND_ENUM(GL_ONE_MINUS_DST_COLOR)
-	TXT_AND_ENUM(GL_SRC_ALPHA)
-	TXT_AND_ENUM(GL_ONE_MINUS_SRC_ALPHA)
-	TXT_AND_ENUM(GL_DST_ALPHA)
-	TXT_AND_ENUM(GL_ONE_MINUS_DST_ALPHA)
-	TXT_AND_ENUM(GL_SRC_ALPHA_SATURATE)
-	TXT_AND_ENUM(GL_SRC_COLOR)
-	TXT_AND_ENUM(GL_ONE_MINUS_SRC_COLOR);
-	ANKI_LOGE("Incorrect blend enum");
-	return 0;
-
-#undef TXT_AND_ENUM
-}
-
 //==============================================================================
 // MaterialVariable                                                            =
 //==============================================================================
@@ -156,8 +123,6 @@ Error MaterialVariableTemplate<T>::_newInstance(
 //==============================================================================
 Material::Material(ResourceManager* manager)
 	: ResourceObject(manager)
-	, m_varDict(10, Dictionary<MaterialVariable*>::hasher(),
-		Dictionary<MaterialVariable*>::key_equal(), getAllocator())
 {}
 
 //==============================================================================
@@ -165,8 +130,6 @@ Material::~Material()
 {
 	auto alloc = getAllocator();
 
-	m_progs.destroy(alloc);
-
 	for(auto it : m_vars)
 	{
 		if(it)
@@ -178,172 +141,6 @@ Material::~Material()
 	}
 
 	m_vars.destroy(alloc);
-	m_pplines.destroy(alloc);
-}
-
-//==============================================================================
-U Material::countShaders(ShaderType type) const
-{
-	U count = 0;
-	U tessCount = m_tessellation ? 2 : 1;
-
-	switch(type)
-	{
-	case ShaderType::VERTEX:
-		count = m_passesCount * m_lodsCount * tessCount;
-		break;
-	case ShaderType::TESSELLATION_CONTROL:
-		if(m_tessellation)
-		{
-			count = m_passesCount;
-		}
-		break;
-	case ShaderType::TESSELLATION_EVALUATION:
-		if(m_tessellation)
-		{
-			count = m_passesCount;
-		}
-		break;
-	case ShaderType::GEOMETRY:
-		count = 0;
-		break;
-	case ShaderType::FRAGMENT:
-		count = m_passesCount * m_lodsCount;
-		break;
-	default:
-		ANKI_ASSERT(0);
-	}
-
-	return count;
-}
-
-//==============================================================================
-U Material::getShaderIndex(const RenderingKey key, ShaderType type) const
-{
-	ANKI_ASSERT((U)key.m_pass < m_passesCount);
-	ANKI_ASSERT(key.m_lod < m_lodsCount);
-
-	if(key.m_tessellation)
-	{
-		ANKI_ASSERT(m_tessellation);
-	}
-
-	U tessCount = m_tessellation ? 2 : 1;
-
-	U pass = enumToType(key.m_pass);
-	U lod = key.m_lod;
-	U tess = key.m_tessellation;
-
-	U offset = 0;
-	switch(type)
-	{
-	case ShaderType::FRAGMENT:
-		offset += countShaders(ShaderType::GEOMETRY);
-	case ShaderType::GEOMETRY:
-		offset += countShaders(ShaderType::TESSELLATION_EVALUATION);
-	case ShaderType::TESSELLATION_EVALUATION:
-		offset += countShaders(ShaderType::TESSELLATION_CONTROL);
-	case ShaderType::TESSELLATION_CONTROL:
-		offset += countShaders(ShaderType::VERTEX);
-	case ShaderType::VERTEX:
-		offset += 0;
-		break;
-	default:
-		ANKI_ASSERT(0);
-	}
-
-	U idx = MAX_U32;
-	switch(type)
-	{
-	case ShaderType::VERTEX:
-		// Like referencing an array of [pass][lod][tess]
-		idx = pass * m_lodsCount * tessCount + lod * tessCount + tess;
-		break;
-	case ShaderType::TESSELLATION_CONTROL:
-		// Like an array [pass]
-		idx = pass;
-		break;
-	case ShaderType::TESSELLATION_EVALUATION:
-		// Like an array [pass]
-		idx = pass;
-		break;
-	case ShaderType::GEOMETRY:
-		idx = 0;
-		break;
-	case ShaderType::FRAGMENT:
-		// Like an array [pass][lod]
-		idx = pass * m_lodsCount + lod;
-		break;
-	default:
-		ANKI_ASSERT(0);
-	}
-
-	return offset + idx;
-}
-
-//==============================================================================
-ShaderResourcePtr& Material::getProgram(
-	const RenderingKey key, ShaderType type)
-{
-	ShaderResourcePtr& out = m_progs[getShaderIndex(key, type)];
-
-	if(out.isLoaded())
-	{
-		ANKI_ASSERT(out->getType() == type);
-	}
-
-	return out;
-}
-
-//==============================================================================
-Error Material::getProgramPipeline(
-	const RenderingKey& key, PipelinePtr& out)
-{
-	ANKI_ASSERT(enumToType(key.m_pass) < m_passesCount);
-	ANKI_ASSERT(key.m_lod < m_lodsCount);
-
-	U tessCount = 1;
-	if(m_tessellation)
-	{
-		tessCount = 2;
-	}
-	else
-	{
-		ANKI_ASSERT(!key.m_tessellation);
-	}
-
-	U idx = enumToType(key.m_pass) * m_lodsCount * tessCount
-		+ key.m_lod * tessCount + key.m_tessellation;
-
-	PipelinePtr& ppline = m_pplines[idx];
-
-	// Lazily create it
-	if(ANKI_UNLIKELY(!ppline.isCreated()))
-	{
-		PipelinePtr::Initializer pplineInit;
-
-		pplineInit.m_shaders[U(ShaderType::VERTEX)] =
-			getProgram(key, ShaderType::VERTEX)->getGrShader();
-
-		if(key.m_tessellation)
-		{
-			pplineInit.m_shaders[U(ShaderType::TESSELLATION_CONTROL)] =
-				getProgram(
-				key, ShaderType::TESSELLATION_CONTROL)->getGrShader();
-			pplineInit.m_shaders[U(ShaderType::TESSELLATION_EVALUATION)] =
-				getProgram(
-				key, ShaderType::TESSELLATION_EVALUATION)->getGrShader();
-		}
-
-		pplineInit.m_shaders[U(ShaderType::FRAGMENT)] =
-			getProgram(key, ShaderType::FRAGMENT)->getGrShader();
-
-		ppline.create(&getManager().getGrManager(), pplineInit);
-	}
-
-	out = ppline;
-
-	return ErrorCode::NONE;
 }
 
 //==============================================================================
@@ -373,11 +170,11 @@ Error Material::parseMaterialTag(const XmlElement& materialEl)
 	{
 		I64 tmp;
 		ANKI_CHECK(lodEl.getI64(tmp));
-		m_lodsCount = (tmp < 1) ? 1 : tmp;
+		m_lodCount = (tmp < 1) ? 1 : tmp;
 	}
 	else
 	{
-		m_lodsCount = 1;
+		m_lodCount = 1;
 	}
 
 	// shadow
@@ -392,62 +189,15 @@ Error Material::parseMaterialTag(const XmlElement& materialEl)
 		m_shadow = tmp;
 	}
 
-	// blendFunctions
+	// forwardShading
 	//
-	XmlElement blendFunctionsEl;
-	ANKI_CHECK(
-		materialEl.getChildElementOptional("blendFunctions", blendFunctionsEl));
-
-	if(blendFunctionsEl)
-	{
-		CString cstr;
-
-		// sFactor
-		ANKI_CHECK(blendFunctionsEl.getChildElement("sFactor", el));
-		ANKI_CHECK(el.getText(cstr));
-		m_blendingSfactor = blendToEnum(cstr);
-		if(m_blendingSfactor == 0)
-		{
-			return ErrorCode::USER_DATA;
-		}
-
-		// dFactor
-		ANKI_CHECK(blendFunctionsEl.getChildElement("dFactor", el));
-		ANKI_CHECK(el.getText(cstr));
-		m_blendingDfactor = blendToEnum(cstr);
-		if(m_blendingDfactor == 0)
-		{
-			return ErrorCode::USER_DATA;
-		}
-	}
-	else
-	{
-		m_passesCount = 2;
-	}
-
-	// depthTesting
-	//
-	XmlElement depthTestingEl;
-	ANKI_CHECK(
-		materialEl.getChildElementOptional("depthTesting", depthTestingEl));
-
-	if(depthTestingEl)
+	XmlElement fsEl;
+	ANKI_CHECK(materialEl.getChildElementOptional("forwardShading", fsEl));
+	if(fsEl)
 	{
 		I64 tmp;
-		ANKI_CHECK(depthTestingEl.getI64(tmp));
-		m_depthTesting = tmp;
-	}
-
-	// wireframe
-	//
-	XmlElement wireframeEl;
-	ANKI_CHECK(materialEl.getChildElementOptional("wireframe", wireframeEl));
-
-	if(wireframeEl)
-	{
-		I64 tmp;
-		ANKI_CHECK(wireframeEl.getI64(tmp));
-		m_wireframe = tmp;
+		ANKI_CHECK(fsEl.getI64(tmp));
+		m_forwardShading = tmp;
 	}
 
 	// shaderProgram
@@ -458,17 +208,7 @@ Error Material::parseMaterialTag(const XmlElement& materialEl)
 
 	m_tessellation = loader.hasTessellation();
 	U tessCount = m_tessellation ? 2 : 1;
-
-	// Alloc program vector
-	m_progs.create(getAllocator(),
-		countShaders(ShaderType::VERTEX)
-		+ countShaders(ShaderType::TESSELLATION_CONTROL)
-		+ countShaders(ShaderType::TESSELLATION_EVALUATION)
-		+ countShaders(ShaderType::GEOMETRY)
-		+ countShaders(ShaderType::FRAGMENT));
-
-	// Aloc progam descriptors
-	m_pplines.create(getAllocator(), m_passesCount * m_lodsCount * tessCount);
+	U passesCount = m_shadow ? 2 : 1;
 
 	m_hash = 0;
 	for(ShaderType shader = ShaderType::VERTEX;
@@ -490,14 +230,14 @@ Error Material::parseMaterialTag(const XmlElement& materialEl)
 			continue;
 		}
 
-		for(U level = 0; level < m_lodsCount; ++level)
+		for(U level = 0; level < m_lodCount; ++level)
 		{
 			if(level > 0 && isTessellationShader)
 			{
 				continue;
 			}
 
-			for(U pid = 0; pid < m_passesCount; ++pid)
+			for(U pid = 0; pid < passesCount; ++pid)
 			{
 				for(U tess = 0; tess < tessCount; ++tess)
 				{
@@ -523,8 +263,8 @@ Error Material::parseMaterialTag(const XmlElement& materialEl)
 
 					ANKI_CHECK(createProgramSourceToCache(src, filename));
 
-					RenderingKey key((Pass)pid, level, tess);
-					ShaderResourcePtr& progr = getProgram(key, shader);
+					ShaderResourcePtr& progr =
+						m_shaders[pid][level][tess][U(shader)];
 					ANKI_CHECK(progr.load(filename.toCString(), &getManager()));
 
 					// Update the hash
@@ -537,7 +277,6 @@ Error Material::parseMaterialTag(const XmlElement& materialEl)
 	ANKI_CHECK(populateVariables(loader));
 
 	// Get uniform block size
-	ANKI_ASSERT(m_progs.getSize() > 0);
 	m_shaderBlockSize = loader.getUniformBlockSize();
 
 	return ErrorCode::NONE;
@@ -672,4 +411,16 @@ Error Material::populateVariables(const MaterialProgramCreator& loader)
 	return ErrorCode::NONE;
 }
 
+//==============================================================================
+ShaderPtr Material::getShader(const RenderingKey& key, ShaderType type) const
+{
+	ANKI_ASSERT(!(key.m_tessellation && !m_tessellation));
+	ANKI_ASSERT(key.m_lod < m_lodCount);
+	ANKI_ASSERT(!(key.m_pass == Pass::SM && !m_shadow));
+
+	ShaderResourcePtr resource =
+		m_shaders[U(key.m_pass)][key.m_lod][key.m_tessellation][U(type)];
+	return resource->getGrShader();
+}
+
 } // end namespace anki

+ 0 - 30
src/resource/MaterialCommon.cpp

@@ -1,30 +0,0 @@
-// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#include "anki/resource/MaterialCommon.h"
-#include "anki/resource/ResourceManager.h"
-#include "anki/resource/Mesh.h"
-#include "anki/renderer/Common.h"
-
-namespace anki {
-
-//==============================================================================
-Error MaterialResourceData::create(ResourceManager& resources)
-{
-	PipelinePtr::Initializer init;
-	init.m_depthStencil.m_depthWriteEnabled = true;
-	init.m_color.m_colorAttachmentsCount = MS_COLOR_ATTACHMENTS_COUNT;
-	for(U i = 0; i < MS_COLOR_ATTACHMENTS_COUNT; ++i)
-	{
-		init.m_color.m_attachments[i].m_format = 
-			MS_COLOR_ATTACHMENTS_PIXEL_FORMAT[i];
-	}
-	init.m_depthStencil.m_format = MS_DEPTH_STENCIL_ATTACHMENT_FORMAT;
-
-	return ErrorCode::NONE;
-}
-
-} // end namespace anki
-

+ 3 - 213
src/resource/Mesh.cpp

@@ -11,10 +11,6 @@
 
 namespace anki {
 
-//==============================================================================
-// Mesh                                                                        =
-//==============================================================================
-
 //==============================================================================
 Mesh::~Mesh()
 {
@@ -24,8 +20,9 @@ Mesh::~Mesh()
 //==============================================================================
 Bool Mesh::isCompatible(const Mesh& other) const
 {
-	return hasWeights() == other.hasWeights()
-		&& getSubMeshesCount() == other.getSubMeshesCount();
+	return hasBoneWeights() == other.hasBoneWeights()
+		&& getSubMeshesCount() == other.getSubMeshesCount()
+		&& m_texChannelsCount == other.m_texChannelsCount;
 }
 
 //==============================================================================
@@ -73,211 +70,4 @@ Error Mesh::createBuffers(const MeshLoader& loader)
 	return ErrorCode::NONE;
 }
 
-//==============================================================================
-void Mesh::getBufferInfo(const VertexAttribute attrib,
-	BufferPtr& v, U32& size, GLenum& type,
-	U32& stride, U32& offset, Bool& normalized) const
-{
-	stride = sizeof(Vec3) + sizeof(U32) + sizeof(U32)
-		+ m_texChannelsCount * sizeof(HVec2)
-		+ ((m_weights) ? (sizeof(U8) * 4 + sizeof(HVec4)) : 0);
-
-	// Set all to zero
-	v = BufferPtr();
-	size = 0;
-	type = GL_NONE;
-	offset = 0;
-	normalized = false;
-
-	switch(attrib)
-	{
-	case VertexAttribute::POSITION:
-		v = m_vertBuff;
-		size = 3;
-		type = GL_FLOAT;
-		offset = 0;
-		break;
-	case VertexAttribute::NORMAL:
-		v = m_vertBuff;
-		size = 4;
-		type = GL_INT_2_10_10_10_REV;
-		offset = sizeof(Vec3);
-		normalized = true;
-		break;
-	case VertexAttribute::TANGENT:
-		v = m_vertBuff;
-		size = 4;
-		type = GL_INT_2_10_10_10_REV;
-		offset = sizeof(Vec3) + sizeof(U32);
-		normalized = true;
-		break;
-	case VertexAttribute::TEXTURE_COORD:
-		if(m_texChannelsCount > 0)
-		{
-			v = m_vertBuff;
-			size = 2;
-			type = GL_HALF_FLOAT;
-			offset = sizeof(Vec3) + sizeof(U32) + sizeof(U32);
-		}
-		break;
-	case VertexAttribute::TEXTURE_COORD_1:
-		if(m_texChannelsCount > 1)
-		{
-			v = m_vertBuff;
-			size = 2;
-			type = GL_HALF_FLOAT;
-			offset = sizeof(Vec3) + sizeof(U32) + sizeof(U32)
-				+ sizeof(HVec2);
-		}
-		break;
-	case VertexAttribute::BONE_WEIGHTS:
-		if(m_weights)
-		{
-			v = m_vertBuff;
-			size = 4;
-			type = GL_UNSIGNED_BYTE;
-			offset = sizeof(Vec3) + sizeof(U32) + sizeof(U32)
-				+ m_texChannelsCount * sizeof(HVec2);
-			normalized = true;
-		}
-		break;
-	case VertexAttribute::BONE_IDS:
-		if(m_weights)
-		{
-			v = m_vertBuff;
-			size = 4;
-			type = GL_HALF_FLOAT;
-			offset = sizeof(Vec3) + sizeof(U32) + sizeof(U32)
-				+ m_texChannelsCount * sizeof(HVec2) + sizeof(U8) * 4;
-		}
-		break;
-	case VertexAttribute::INDICES:
-		v = m_indicesBuff;
-		break;
-	default:
-		ANKI_ASSERT(0);
-		break;
-	}
-}
-
-//==============================================================================
-// BucketMesh                                                                  =
-//==============================================================================
-
-//==============================================================================
-Error BucketMesh::load(const CString& filename)
-{
-	Error err = ErrorCode::NONE;
-
-#if 0
-	m_alloc = init.m_alloc;
-
-	XmlDocument doc;
-	ANKI_CHECK(doc.loadFile(filename, init.m_tempAlloc));
-
-	XmlElement rootEl;
-	ANKI_CHECK(doc.getChildElement("bucketMesh", rootEl));
-	XmlElement meshesEl;
-	ANKI_CHECK(rootEl.getChildElement("meshes", meshesEl));
-	XmlElement meshEl;
-	ANKI_CHECK(meshesEl.getChildElement("mesh", meshEl));
-
-	// Count sub meshes
-	U i = 0;
-	do
-	{
-		++i;
-		ANKI_CHECK(meshEl.getNextSiblingElement("mesh", meshEl));
-	} while(meshEl);
-
-	ANKI_CHECK(m_subMeshes.create(m_alloc, i));
-
-	ANKI_CHECK(meshesEl.getChildElement("mesh", meshEl));
-
-	m_vertsCount = 0;
-	m_indicesCount = 0;
-
-	MeshLoader fullLoader(init.m_tempAlloc);
-	do
-	{
-		CString subMeshFilename;
-		ANKI_CHECK(meshEl.getText(subMeshFilename));
-
-		// Load the submesh and if not the first load the append the
-		// vertices to the fullMesh
-		MeshLoader* loader;
-		MeshLoader subLoader(init.m_tempAlloc);
-		if(i != 0)
-		{
-			// Sanity check
-			if(i > ANKI_GL_MAX_SUB_DRAWCALLS)
-			{
-				ANKI_LOGE("Max number of submeshes exceeded");
-				return ErrorCode::USER_DATA;
-			}
-
-			// Load
-			ANKI_CHECK(subLoader.load(subMeshFilename));
-			loader = &subLoader;
-
-			// Sanity checks
-			if(m_weights != (loader->getWeights().getSize() > 1))
-			{
-				ANKI_LOGE("All sub meshes should have or not "
-					"have vertex weights");
-				return ErrorCode::USER_DATA;
-			}
-
-			if(m_texChannelsCount
-				!= loader->getTextureChannelsCount())
-			{
-				ANKI_LOGE("All sub meshes should have the "
-					"same number of texture channels");
-				return ErrorCode::USER_DATA;
-			}
-
-			// Append
-			ANKI_CHECK(fullLoader.append(subLoader));
-		}
-		else
-		{
-			// Load
-			ANKI_CHECK(fullLoader.load(subMeshFilename));
-			loader = &fullLoader;
-
-			// Set properties
-			m_weights = loader->getWeights().getSize() > 1;
-			m_texChannelsCount = loader->getTextureChannelsCount();
-		}
-
-		// Push back the new submesh
-		SubMesh& submesh = m_subMeshes[i];
-
-		submesh.m_indicesCount = loader->getIndices().getSize();
-		submesh.m_indicesOffset = m_indicesCount * sizeof(U16);
-
-		const auto& positions = loader->getPositions();
-		submesh.m_obb.setFromPointCloud(&positions[0], positions.getSize(),
-			sizeof(Vec3), positions.getSizeInBytes());
-
-		// Set the global numbers
-		m_vertsCount += loader->getPositions().getSize();
-		m_indicesCount += loader->getIndices().getSize();
-
-		++i;
-		// Move to next
-		ANKI_CHECK(meshEl.getNextSiblingElement("mesh", meshEl));
-	} while(meshEl);
-
-	// Create the bucket mesh
-	ANKI_CHECK(createBuffers(fullLoader, init));
-
-	const auto& positions = fullLoader.getPositions();
-	m_obb.setFromPointCloud(&positions[0], positions.getSize(),
-		sizeof(Vec3), positions.getSizeInBytes());
-#endif
-
-	return err;
-}
-
 } // end namespace anki

+ 186 - 250
src/resource/Model.cpp

@@ -11,95 +11,45 @@
 #include "anki/resource/ShaderResource.h"
 #include "anki/misc/Xml.h"
 #include "anki/util/Logger.h"
+#include "anki/renderer/Ms.h"
+#include "anki/renderer/Is.h"
+#include "anki/renderer/Sm.h"
 
 namespace anki {
 
 //==============================================================================
-// ModelPatchBase                                                              =
-//==============================================================================
-
+// ModelPatch                                                                  =
 //==============================================================================
-ModelPatchBase::~ModelPatchBase()
-{
-	m_vertJobs.destroy(m_alloc);
-	m_meshes.destroy(m_alloc);
-}
 
 //==============================================================================
-Error ModelPatchBase::createVertexDesc(
-	const Mesh& mesh,
-	CommandBufferPtr& vertexJobs)
-{
-	BufferPtr vbo;
-	U32 size;
-	GLenum type;
-	U32 stride;
-	U32 offset;
-	Bool normalized;
-
-	U count = 0;
-	for(VertexAttribute attrib = VertexAttribute::POSITION;
-		attrib < VertexAttribute::INDICES; ++attrib)
-	{
-		mesh.getBufferInfo(attrib, vbo, size, type,
-			stride, offset, normalized);
-
-		if(!vbo.isCreated())
-		{
-			continue;
-		}
-
-		vbo.bindVertexBuffer(vertexJobs, size, type, normalized, stride,
-			offset, static_cast<U>(attrib));
-
-		++count;
-	}
-
-	if(count < 1)
-	{
-		ANKI_LOGE("The mesh doesn't have any attributes");
-		return ErrorCode::USER_DATA;
-	}
-
-	// The indices VBO
-	mesh.getBufferInfo(VertexAttribute::INDICES, vbo, size, type,
-		stride, offset, normalized);
-
-	ANKI_ASSERT(vbo.isCreated());
-	vbo.bindIndexBuffer(vertexJobs);
-
-	return ErrorCode::NONE;
-}
+ModelPatch::~ModelPatch()
+{}
 
 //==============================================================================
-Error ModelPatchBase::getRenderingDataSub(
+void ModelPatch::getRenderingDataSub(
 	const RenderingKey& key,
-	CommandBufferPtr& vertJobs,
+	SArray<U8> subMeshIndicesArray,
+	BufferPtr& vertBuff,
+	BufferPtr& indexBuff,
 	PipelinePtr& ppline,
-	const U8* subMeshIndexArray,
-	U32 subMeshIndexCount,
 	Array<U32, ANKI_GL_MAX_SUB_DRAWCALLS>& indicesCountArray,
 	Array<PtrSize, ANKI_GL_MAX_SUB_DRAWCALLS>& indicesOffsetArray,
 	U32& drawcallCount) const
 {
-	// Vertex descr
-	vertJobs = m_vertJobs[getVertexDescIdx(key)];
+	// Get the buffers
+	RenderingKey meshKey = key;
+	meshKey.m_lod = min<U>(key.m_lod, m_meshCount - 1);
+	const Mesh& mesh = getMesh(meshKey);
+	vertBuff = mesh.getVertexBuffer();
+	indexBuff = mesh.getIndexBuffer();
 
-	// Prog
+	// Get ppline
 	RenderingKey mtlKey = key;
-	mtlKey.m_lod =
-		std::min(key.m_lod, (U8)(getMaterial().getLevelsOfDetail() - 1));
+	mtlKey.m_lod = min<U>(key.m_lod, m_mtl->getLodCount() - 1);
 
-	ANKI_CHECK(m_mtl->getProgramPipeline(mtlKey, ppline));
-
-	// Mesh and indices
-	RenderingKey meshKey = key;
-	meshKey.m_lod = std::min(key.m_lod, (U8)(getMeshesCount() - 1));
-
-	const Mesh& mesh = getMesh(meshKey);
+	ppline = getPipeline(mtlKey);
 
-	if(subMeshIndexCount == 0 || subMeshIndexArray == nullptr
-		|| mesh.getSubMeshesCount() == 0)
+	if(subMeshIndicesArray.getSize() == 0 || mesh.getSubMeshesCount() == 0)
 	{
 		drawcallCount = 1;
 		indicesOffsetArray[0] = 0;
@@ -107,138 +57,173 @@ Error ModelPatchBase::getRenderingDataSub(
 	}
 	else
 	{
-		ANKI_ASSERT(subMeshIndexCount <= mesh.getSubMeshesCount());
-
-		drawcallCount = 0;
-		I prevIndex = -1;
-		for(U i = 0; i < subMeshIndexCount; i++)
-		{
-			I index = (subMeshIndexArray == nullptr)
-				? (I)i
-				: (I)subMeshIndexArray[i];
-
-			// Check if we can merge with the previous submesh
-			if(index > 0 && (index - 1) == prevIndex)
-			{
-				ANKI_ASSERT(drawcallCount > 0);
-
-				// increase the indices count, leave offset alone
-				U32 offset;
-				indicesCountArray[drawcallCount - 1] +=
-					mesh.getIndicesCountSub((U)index, offset);
-			}
-			else
-			{
-				U32 offset;
-				indicesCountArray[drawcallCount] =
-					mesh.getIndicesCountSub((U)index, offset);
-
-				indicesOffsetArray[drawcallCount] = (PtrSize)offset;
-
-				++drawcallCount;
-			}
-
-			prevIndex = index;
-		}
+		ANKI_ASSERT(0 && "TODO");
 	}
-
-	return ErrorCode::NONE;
 }
 
 //==============================================================================
-Error ModelPatchBase::create(GrManager* gl)
+U ModelPatch::getLodCount() const
 {
-	const Material& mtl = getMaterial();
-	U lodsCount = getLodsCount();
+	return max<U>(m_meshCount, getMaterial().getLodCount());
+}
 
-	m_vertJobs.create(m_alloc, lodsCount * mtl.getPassesCount());
+//==============================================================================
+Error ModelPatch::create(
+	SArray<CString> meshFNames,
+	const CString& mtlFName,
+	ResourceManager* manager)
+{
+	ANKI_ASSERT(meshFNames.getSize() > 0);
 
-	for(U lod = 0; lod < lodsCount; ++lod)
+	// Load meshes
+	m_meshCount = 0;
+	for(U i = 0; i < meshFNames.getSize(); i++)
 	{
-		for(U pass = 0; pass < mtl.getPassesCount(); ++pass)
-		{
-			RenderingKey key((Pass)pass, lod, false);
-			const Mesh* mesh;
-
-			// Get mesh
-			ANKI_ASSERT(getMeshesCount() > 0);
-			RenderingKey meshKey = key;
-			meshKey.m_lod = std::min(key.m_lod, (U8)(getMeshesCount() - 1));
-			mesh = &getMesh(meshKey);
+		ANKI_CHECK(m_meshes[i].load(meshFNames[i], manager));
 
-			// Create vert descriptor
-			CommandBufferPtr vertJobs;
-			vertJobs.create(gl);
-			ANKI_CHECK(createVertexDesc(*mesh, vertJobs));
-
-			m_vertJobs[getVertexDescIdx(key)] = vertJobs;
+		// Sanity check
+		if(i > 0 && !m_meshes[i]->isCompatible(*m_meshes[i - 1]))
+		{
+			ANKI_LOGE("Meshes not compatible");
+			return ErrorCode::USER_DATA;
 		}
+
+		++m_meshCount;
 	}
 
-	return ErrorCode::NONE;
-}
+	// Load material
+	ANKI_CHECK(m_mtl.load(mtlFName, manager));
 
-//==============================================================================
-U ModelPatchBase::getLodsCount() const
-{
-	U meshLods = getMeshesCount();
-	U mtlLods = getMaterial().getLevelsOfDetail();
-	return std::max(meshLods, mtlLods);
+	return ErrorCode::NONE;
 }
 
 //==============================================================================
-U ModelPatchBase::getVertexDescIdx(const RenderingKey& key) const
+PipelinePtr ModelPatch::getPipeline(const RenderingKey& key) const
 {
-	U passesCount = getMaterial().getPassesCount();
-	ANKI_ASSERT((U)key.m_pass < passesCount);
+	// Preconditions
+	ANKI_ASSERT(key.m_lod < m_mtl->getLodCount());
 
-	// Sanitize LOD
-	U lod = std::min((U)key.m_lod, getLodsCount() - 1);
-
-	U idx = lod * passesCount + (U)key.m_pass;
-	ANKI_ASSERT(idx < m_vertJobs.getSize());
-	return idx;
-}
-
-//==============================================================================
-// ModelPatch                                                                  =
-//==============================================================================
+	if(key.m_tessellation && !m_mtl->getTessellationEnabled())
+	{
+		ANKI_ASSERT(0);
+	}
 
-//==============================================================================
-template<typename MeshResourcePtrType>
-Error ModelPatch<MeshResourcePtrType>::create(
-	CString meshFNames[],
-	U32 meshesCount,
-	const CString& mtlFName,
-	ResourceManager* resources)
-{
-	ANKI_ASSERT(meshesCount > 0);
+	if(key.m_pass == Pass::SM && !m_mtl->getShadowEnabled())
+	{
+		ANKI_ASSERT(0);
+	}
 
-	m_meshes.create(m_alloc, meshesCount);
-	m_meshResources.create(m_alloc, meshesCount);
+	PipelinePtr& ppline =
+		m_pplines[U(key.m_pass)][key.m_lod][key.m_tessellation];
 
-	// Load meshes
-	for(U i = 0; i < meshesCount; i++)
+	// Lazily create it
+	if(ANKI_UNLIKELY(!ppline.isCreated()))
 	{
-		ANKI_CHECK(m_meshResources[i].load(meshFNames[i], resources));
-		m_meshes[i] = &m_meshResources[i].get();
+		PipelinePtr::Initializer pplineInit;
+		computePipelineInitializer(key, pplineInit);
 
-		// Sanity check
-		if(i > 0 && !m_meshResources[i]->isCompatible(*m_meshResources[i - 1]))
+		pplineInit.m_shaders[U(ShaderType::VERTEX)] =
+			m_mtl->getShader(key, ShaderType::VERTEX);
+
+		if(key.m_tessellation)
 		{
-			ANKI_LOGE("Meshes not compatible");
-			return ErrorCode::USER_DATA;
+			pplineInit.m_shaders[U(ShaderType::TESSELLATION_CONTROL)] =
+				m_mtl->getShader(key, ShaderType::TESSELLATION_CONTROL);
+
+			pplineInit.m_shaders[U(ShaderType::TESSELLATION_EVALUATION)] =
+				m_mtl->getShader(key, ShaderType::TESSELLATION_EVALUATION);
 		}
+
+		pplineInit.m_shaders[U(ShaderType::FRAGMENT)] =
+			m_mtl->getShader(key, ShaderType::FRAGMENT);
+
+		// Create
+		ppline.create(&m_model->getManager().getGrManager(), pplineInit);
 	}
 
-	// Load material
-	ANKI_CHECK(m_mtlResource.load(mtlFName, resources));
-	m_mtl = &m_mtlResource.get();
+	return ppline;
+}
 
-	// Create VAOs
-	ANKI_CHECK(Base::create(&resources->getGrManager()));
+//==============================================================================
+void ModelPatch::computePipelineInitializer(
+	const RenderingKey& key, PipelineInitializer& pinit) const
+{
+	//
+	// Vertex state
+	//
+	VertexStateInfo& vert = pinit.m_vertex;
+	if(m_meshes[0]->hasBoneWeights())
+	{
+		ANKI_ASSERT(0 && "TODO");
+	}
+	else
+	{
+		vert.m_bindingCount = 1;
+		vert.m_attributeCount = 4;
+		vert.m_bindings[0].m_stride =
+			sizeof(Vec3) + 2 * sizeof(U32) + sizeof(HVec2);
+
+		vert.m_attributes[0].m_format = PixelFormat(
+			ComponentFormat::R32G32B32, TransformFormat::FLOAT);
+		vert.m_attributes[0].m_offset = 0;
+
+		vert.m_attributes[1].m_format = PixelFormat(
+			ComponentFormat::R10G10B10A2, TransformFormat::SNORM);
+		vert.m_attributes[1].m_offset = sizeof(Vec3);
+
+		vert.m_attributes[2].m_format = PixelFormat(
+			ComponentFormat::R10G10B10A2, TransformFormat::SNORM);
+		vert.m_attributes[2].m_offset = sizeof(Vec3) + sizeof(U32);
+
+		vert.m_attributes[3].m_format = PixelFormat(
+			ComponentFormat::R16G16, TransformFormat::FLOAT);
+		vert.m_attributes[3].m_offset = sizeof(Vec3) + 2 * sizeof(U32);
+	}
 
-	return ErrorCode::NONE;
+	//
+	// Depth/stencil state
+	//
+	DepthStencilStateInfo& ds = pinit.m_depthStencil;
+	if(key.m_pass == Pass::SM)
+	{
+		ds.m_format = Sm::DEPTH_RT_PIXEL_FORMAT;
+		ds.m_polygonOffsetFactor = 7.0;
+		ds.m_polygonOffsetUnits = 5.0;
+	}
+	else if(m_mtl->getForwardShading())
+	{
+		ds.m_format = Ms::DEPTH_RT_PIXEL_FORMAT;
+		ds.m_depthWriteEnabled = false;
+	}
+	else
+	{
+		ds.m_format = Ms::DEPTH_RT_PIXEL_FORMAT;
+	}
+
+	//
+	// Color state
+	//
+	ColorStateInfo& color = pinit.m_color;
+	if(key.m_pass == Pass::SM)
+	{
+		// Default
+	}
+	else if(m_mtl->getForwardShading())
+	{
+		color.m_attachmentCount = 1;
+		color.m_attachments[0].m_format = Is::RT_PIXEL_FORMAT;
+		color.m_attachments[0].m_srcBlendMethod = BlendMethod::SRC_ALPHA;
+		color.m_attachments[0].m_dstBlendMethod =
+			BlendMethod::ONE_MINUS_SRC_ALPHA;
+	}
+	else
+	{
+		color.m_attachmentCount = Ms::ATTACHMENT_COUNT;
+		ANKI_ASSERT(Ms::ATTACHMENT_COUNT == 3);
+		color.m_attachments[0].m_format = Ms::RT_PIXEL_FORMATS[0];
+		color.m_attachments[1].m_format = Ms::RT_PIXEL_FORMATS[1];
+		color.m_attachments[2].m_format = Ms::RT_PIXEL_FORMATS[2];
+	}
 }
 
 //==============================================================================
@@ -250,7 +235,7 @@ Model::~Model()
 {
 	auto alloc = getAllocator();
 
-	for(ModelPatchBase* patch : m_modelPatches)
+	for(ModelPatch* patch : m_modelPatches)
 	{
 		alloc.deleteInstance(patch);
 	}
@@ -307,94 +292,45 @@ Error Model::load(const ResourceFilename& filename)
 
 		Array<CString, 3> meshesFnames;
 		U meshesCount = 1;
-		ModelPatchBase* patch;
 
-		// Try mesh
+		// Get mesh
 		XmlElement meshEl;
-		ANKI_CHECK(modelPatchEl.getChildElementOptional("mesh", meshEl));
-		if(meshEl)
-		{
-			XmlElement meshEl1;
-			ANKI_CHECK(modelPatchEl.getChildElementOptional("mesh1", meshEl1));
-
-			XmlElement meshEl2;
-			ANKI_CHECK(modelPatchEl.getChildElementOptional("mesh2", meshEl2));
-
-			ANKI_CHECK(meshEl.getText(meshesFnames[0]));
+		ANKI_CHECK(modelPatchEl.getChildElement("mesh", meshEl));
 
-			if(meshEl1)
-			{
-				++meshesCount;
-				ANKI_CHECK(meshEl1.getText(meshesFnames[1]));
-			}
+		XmlElement meshEl1;
+		ANKI_CHECK(modelPatchEl.getChildElementOptional("mesh1", meshEl1));
 
-			if(meshEl2)
-			{
-				++meshesCount;
-				ANKI_CHECK(meshEl2.getText(meshesFnames[2]));
-			}
+		XmlElement meshEl2;
+		ANKI_CHECK(modelPatchEl.getChildElementOptional("mesh2", meshEl2));
 
-			CString cstr;
-			ANKI_CHECK(materialEl.getText(cstr));
-			ModelPatch<MeshResourcePtr>* mpatch = alloc.newInstance<
-				ModelPatch<MeshResourcePtr>>(alloc);
+		ANKI_CHECK(meshEl.getText(meshesFnames[0]));
 
-			if(mpatch == nullptr)
-			{
-				return ErrorCode::OUT_OF_MEMORY;
-			}
-
-			ANKI_CHECK(mpatch->create(&meshesFnames[0], meshesCount, cstr,
-				&getManager()));
-
-			patch = mpatch;
-		}
-		else
+		if(meshEl1)
 		{
-			XmlElement bmeshEl;
-			ANKI_CHECK(modelPatchEl.getChildElement("bucketMesh", bmeshEl));
-
-			XmlElement bmeshEl1;
-			ANKI_CHECK(
-				modelPatchEl.getChildElementOptional("bucketMesh1", bmeshEl1));
-
-			XmlElement bmeshEl2;
-			ANKI_CHECK(
-				modelPatchEl.getChildElementOptional("bucketMesh2", bmeshEl2));
-
-			ANKI_CHECK(bmeshEl.getText(meshesFnames[0]));
-
-			if(bmeshEl1)
-			{
-				++meshesCount;
-				ANKI_CHECK(bmeshEl1.getText(meshesFnames[1]));
-			}
-
-			if(bmeshEl2)
-			{
-				++meshesCount;
-				ANKI_CHECK(bmeshEl2.getText(meshesFnames[2]));
-			}
-
-			CString cstr;
-			ANKI_CHECK(materialEl.getText(cstr));
-
-			ModelPatch<BucketMeshResourcePtr>* mpatch =
-				alloc.newInstance<
-				ModelPatch<BucketMeshResourcePtr>>(alloc);
+			++meshesCount;
+			ANKI_CHECK(meshEl1.getText(meshesFnames[1]));
+		}
 
-			if(mpatch == nullptr)
-			{
-				return ErrorCode::OUT_OF_MEMORY;
-			}
+		if(meshEl2)
+		{
+			++meshesCount;
+			ANKI_CHECK(meshEl2.getText(meshesFnames[2]));
+		}
 
-			ANKI_CHECK(mpatch->create(&meshesFnames[0], meshesCount, cstr,
-				&getManager()));
+		CString cstr;
+		ANKI_CHECK(materialEl.getText(cstr));
+		ModelPatch* mpatch = alloc.newInstance<ModelPatch>(this);
 
-			patch  = mpatch;
+		if(mpatch == nullptr)
+		{
+			return ErrorCode::OUT_OF_MEMORY;
 		}
 
-		m_modelPatches[count++] = patch;
+		ANKI_CHECK(mpatch->create(
+			SArray<CString>(&meshesFnames[0], meshesCount), cstr,
+			&getManager()));
+
+		m_modelPatches[count++] = mpatch;
 
 		// Move to next
 		ANKI_CHECK(

+ 41 - 0
src/resource/ParticleEmitterResource.cpp

@@ -8,6 +8,8 @@
 #include "anki/resource/Model.h"
 #include "anki/util/StringList.h"
 #include "anki/misc/Xml.h"
+#include "anki/renderer/Ms.h"
+#include "anki/renderer/Is.h"
 #include <cstring>
 
 namespace anki {
@@ -215,6 +217,45 @@ Error ParticleEmitterResource::load(const ResourceFilename& filename)
 	//
 	updateFlags();
 
+	// Create ppline
+	//
+	PipelineInitializer pinit;
+
+	pinit.m_vertex.m_bindingCount = 1;
+	pinit.m_vertex.m_bindings[0].m_stride = VERTEX_SIZE;
+	pinit.m_vertex.m_attributeCount = 3;
+	pinit.m_vertex.m_attributes[0].m_format =
+		PixelFormat(ComponentFormat::R32G32B32, TransformFormat::FLOAT);
+	pinit.m_vertex.m_attributes[0].m_offset = 0;
+	pinit.m_vertex.m_attributes[0].m_binding = 0;
+	pinit.m_vertex.m_attributes[1].m_format =
+		PixelFormat(ComponentFormat::R32, TransformFormat::FLOAT);
+	pinit.m_vertex.m_attributes[1].m_offset = sizeof(Vec3);
+	pinit.m_vertex.m_attributes[1].m_binding = 0;
+	pinit.m_vertex.m_attributes[2].m_format =
+		PixelFormat(ComponentFormat::R32, TransformFormat::FLOAT);
+	pinit.m_vertex.m_attributes[2].m_offset = sizeof(Vec3) + sizeof(F32);
+	pinit.m_vertex.m_attributes[2].m_binding = 0;
+
+	pinit.m_depthStencil.m_depthWriteEnabled = false;
+	pinit.m_depthStencil.m_format = Ms::DEPTH_RT_PIXEL_FORMAT;
+
+	pinit.m_color.m_attachmentCount = 1;
+	pinit.m_color.m_attachments[0].m_format = Is::RT_PIXEL_FORMAT;
+	pinit.m_color.m_attachments[0].m_srcBlendMethod = BlendMethod::SRC_ALPHA;
+	pinit.m_color.m_attachments[0].m_dstBlendMethod =
+		BlendMethod::ONE_MINUS_SRC_ALPHA;
+
+	pinit.m_shaders[U(ShaderType::VERTEX)] = m_material->getShader(
+		RenderingKey(Pass::MS_FS, 0, false), ShaderType::VERTEX);
+
+	pinit.m_shaders[U(ShaderType::FRAGMENT)] = m_material->getShader(
+		RenderingKey(Pass::MS_FS, 0, false), ShaderType::FRAGMENT);
+
+	pinit.m_inputAssembler.m_topology = PrimitiveTopology::POINTS;
+
+	m_ppline.create(&getManager().getGrManager(), pinit);
+
 	return ErrorCode::NONE;
 }
 

+ 1 - 0
src/resource/ResourceFilesystem.cpp

@@ -213,6 +213,7 @@ Error ResourceFilesystem::init(const ConfigSet& config, const CString& cacheDir)
 	for(auto& path : paths)
 	{
 		ANKI_CHECK(addNewPath(path.toCString()));
+		ANKI_LOGI("Adding new data path \"%s\"", &path[0]);
 	}
 
 	addCachePath(cacheDir);

+ 36 - 33
src/scene/ModelNode.cpp

@@ -25,8 +25,8 @@ public:
 	ModelPatchNode* m_node;
 
 	ModelPatchRenderComponent(ModelPatchNode* node)
-	:	RenderComponent(node),
-		m_node(node)
+		: RenderComponent(node)
+		, m_node(node)
 	{}
 
 	ANKI_USE_RESULT Error buildRendering(RenderingBuildData& data) override
@@ -56,7 +56,7 @@ public:
 
 //==============================================================================
 ModelPatchNode::ModelPatchNode(SceneGraph* scene)
-:	SceneNode(scene)
+	: SceneNode(scene)
 {}
 
 //==============================================================================
@@ -67,7 +67,7 @@ ModelPatchNode::~ModelPatchNode()
 
 //==============================================================================
 Error ModelPatchNode::create(const CString& name,
-	const ModelPatchBase* modelPatch)
+	const ModelPatch* modelPatch)
 {
 	ANKI_ASSERT(modelPatch);
 	ANKI_CHECK(SceneNode::create(name));
@@ -104,34 +104,37 @@ Error ModelPatchNode::buildRendering(RenderingBuildData& data)
 	Array<PtrSize, ANKI_GL_MAX_SUB_DRAWCALLS> indicesOffsetArray;
 	U32 drawcallCount;
 
-	CommandBufferPtr vertJobs;
 	PipelinePtr ppline;
+	BufferPtr vertBuff, indexBuff;
+
+	m_modelPatch->getRenderingDataSub(
+		data.m_key,
+		SArray<U8>(),
+		vertBuff,
+		indexBuff,
+		ppline,
+		indicesCountArray,
+		indicesOffsetArray,
+		drawcallCount);
+
+	// Cannot accept multi-draw
+	ANKI_ASSERT(drawcallCount == 1);
+
+	// Set jobs
+	ppline.bind(data.m_cmdb);
+	data.m_cmdb.bindVertexBuffer(0, vertBuff, 0);
+	data.m_cmdb.bindIndexBuffer(indexBuff, sizeof(U16));
+
+	// Drawcall
+	U32 offset = indicesOffsetArray[0] / sizeof(U16);
+	data.m_cmdb.drawElements(
+		data.m_key.m_tessellation ? GL_PATCHES : GL_TRIANGLES,
+		sizeof(U16),
+		indicesCountArray[0],
+		instancesCount,
+		offset);
 
-	Error err = m_modelPatch->getRenderingDataSub(
-		data.m_key, vertJobs, ppline,
-		nullptr, 0,
-		indicesCountArray, indicesOffsetArray, drawcallCount);
-
-	if(!err)
-	{
-		// Cannot accept multi-draw
-		ANKI_ASSERT(drawcallCount == 1);
-
-		// Set jobs
-		ppline.bind(data.m_jobs);
-		data.m_jobs.pushBackOtherCommandBuffer(vertJobs);
-
-		// Drawcall
-		U32 offset = indicesOffsetArray[0] / sizeof(U16);
-		data.m_jobs.drawElements(
-			data.m_key.m_tessellation ? GL_PATCHES : GL_TRIANGLES,
-			sizeof(U16),
-			indicesCountArray[0],
-			instancesCount,
-			offset);
-	}
-
-	return err;
+	return ErrorCode::NONE;
 }
 
 //==============================================================================
@@ -225,7 +228,7 @@ class ModelMoveFeedbackComponent: public SceneComponent
 {
 public:
 	ModelMoveFeedbackComponent(SceneNode* node)
-	:	SceneComponent(SceneComponent::Type::NONE, node)
+		: SceneComponent(SceneComponent::Type::NONE, node)
 	{}
 
 	ANKI_USE_RESULT Error update(
@@ -250,8 +253,8 @@ public:
 
 //==============================================================================
 ModelNode::ModelNode(SceneGraph* scene)
-: 	SceneNode(scene),
-	m_transformsTimestamp(0)
+	: SceneNode(scene)
+	, m_transformsTimestamp(0)
 {}
 
 //==============================================================================

+ 17 - 40
src/scene/ParticleEmitter.cpp

@@ -18,9 +18,6 @@ namespace anki {
 // Misc                                                                        =
 //==============================================================================
 
-const U COMPONENTS = 3 + 1 + 1; // 3 position, 1 size, 1 alpha
-const PtrSize VERT_SIZE = COMPONENTS * sizeof(F32);
-
 //==============================================================================
 static F32 getRandom(F32 initial, F32 deviation)
 {
@@ -206,8 +203,8 @@ public:
 	ParticleEmitter* m_node;
 
 	ParticleEmitterRenderComponent(ParticleEmitter* node)
-	:	RenderComponent(node),
-		m_node(node)
+		: RenderComponent(node)
+		, m_node(node)
 	{}
 
 	ANKI_USE_RESULT Error buildRendering(RenderingBuildData& data) override
@@ -240,7 +237,7 @@ class MoveFeedbackComponent: public SceneComponent
 {
 public:
 	MoveFeedbackComponent(ParticleEmitter* node)
-	:	SceneComponent(SceneComponent::Type::NONE, node)
+		: SceneComponent(SceneComponent::Type::NONE, node)
 	{}
 
 	ANKI_USE_RESULT Error update(
@@ -264,7 +261,7 @@ public:
 
 //==============================================================================
 ParticleEmitter::ParticleEmitter(SceneGraph* scene)
-:	SceneNode(scene)
+	: SceneNode(scene)
 {}
 
 //==============================================================================
@@ -336,7 +333,8 @@ Error ParticleEmitter::create(
 	}
 
 	// Create the vertex buffer and object
-	PtrSize buffSize = m_maxNumOfParticles * VERT_SIZE * 3;
+	PtrSize buffSize = m_maxNumOfParticles
+		* ParticleEmitterResource::VERTEX_SIZE * 3;
 	m_vertBuff.create(&getSceneGraph().getGrManager(),
 		GL_ARRAY_BUFFER, nullptr, buffSize,
 		GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
@@ -352,45 +350,24 @@ Error ParticleEmitter::buildRendering(RenderingBuildData& data)
 {
 	ANKI_ASSERT(data.m_subMeshIndicesCount <= m_transforms.getSize() + 1);
 
-	Error err = ErrorCode::NONE;
-
 	if(m_aliveParticlesCount == 0)
 	{
 		return ErrorCode::NONE;
 	}
 
-	RenderingKey key = data.m_key;
-	key.m_lod = 0;
-
-	PipelinePtr ppline;
-	err = m_particleEmitterResource->getMaterial().getProgramPipeline(
-		key, ppline);
-
-	if(!err)
-	{
-		ppline.bind(data.m_jobs);
+	PipelinePtr ppline = m_particleEmitterResource->getPipeline();
+	ppline.bind(data.m_cmdb);
 
-		PtrSize offset =
-			(getGlobalTimestamp() % 3) * (m_vertBuff.getSize() / 3);
+	PtrSize offset =
+		(getGlobalTimestamp() % 3) * (m_vertBuff.getSize() / 3);
 
-		// Position
-		m_vertBuff.bindVertexBuffer(data.m_jobs,
-			3, GL_FLOAT, false, VERT_SIZE, offset + 0, 0);
+	data.m_cmdb.bindVertexBuffer(0, m_vertBuff, offset);
 
-		// Scale
-		m_vertBuff.bindVertexBuffer(data.m_jobs,
-			1, GL_FLOAT, false, VERT_SIZE, offset + sizeof(F32) * 3, 6);
+	data.m_cmdb.drawArrays(GL_POINTS,
+		m_aliveParticlesCount,
+		data.m_subMeshIndicesCount);
 
-		// Alpha
-		m_vertBuff.bindVertexBuffer(data.m_jobs,
-			1, GL_FLOAT, false, VERT_SIZE, offset + sizeof(F32) * 4, 7);
-
-		data.m_jobs.drawArrays(GL_POINTS,
-			m_aliveParticlesCount,
-			data.m_subMeshIndicesCount);
-	}
-
-	return err;
+	return ErrorCode::NONE;
 }
 
 //==============================================================================
@@ -486,8 +463,8 @@ Error ParticleEmitter::frameUpdate(F32 prevUpdateTime, F32 crntTime)
 			// It's alive
 
 			// Do checks
-			ANKI_ASSERT(((PtrSize)verts + VERT_SIZE
-				- (PtrSize)m_vertBuffMapping) <= m_vertBuff.getSize());
+			ANKI_ASSERT((PtrSize(verts) + ParticleEmitterResource::VERTEX_SIZE
+				- PtrSize(m_vertBuffMapping)) <= m_vertBuff.getSize());
 
 			// This will calculate a new world transformation
 			p->simulate(*this, prevUpdateTime, crntTime);

+ 41 - 50
src/scene/StaticGeometryNode.cpp

@@ -19,8 +19,8 @@ public:
 	StaticGeometryPatchNode* m_node;
 
 	StaticGeometryRenderComponent(StaticGeometryPatchNode* node)
-	:	RenderComponent(node),
-		m_node(node)
+		: RenderComponent(node)
+		, m_node(node)
 	{}
 
 	Error buildRendering(RenderingBuildData& data) override
@@ -40,12 +40,12 @@ public:
 
 //==============================================================================
 StaticGeometryPatchNode::StaticGeometryPatchNode(SceneGraph* scene)
-:	SceneNode(scene)
+	: SceneNode(scene)
 {}
 
 //==============================================================================
 Error StaticGeometryPatchNode::create(
-	const CString& name, const ModelPatchBase* modelPatch)
+	const CString& name, const ModelPatch* modelPatch)
 {
 	ANKI_ASSERT(modelPatch);
 
@@ -67,7 +67,7 @@ Error StaticGeometryPatchNode::create(
 	}
 
 	// Create render component
-	RenderComponent* rcomp = 
+	RenderComponent* rcomp =
 		getSceneAllocator().newInstance<StaticGeometryRenderComponent>(this);
 	addComponent(rcomp);
 
@@ -81,29 +81,31 @@ StaticGeometryPatchNode::~StaticGeometryPatchNode()
 //==============================================================================
 Error StaticGeometryPatchNode::buildRendering(RenderingBuildData& data)
 {
-	Error err = ErrorCode::NONE;
-
 	Array<U32, ANKI_GL_MAX_SUB_DRAWCALLS> indicesCountArray;
 	Array<PtrSize, ANKI_GL_MAX_SUB_DRAWCALLS> indicesOffsetArray;
 	U32 drawCount;
-	CommandBufferPtr vertJobs;
+	BufferPtr vertBuff, indexBuff;
 	PipelinePtr ppline;
 
-	err = m_modelPatch->getRenderingDataSub(
-		data.m_key, vertJobs, ppline, 
-		data.m_subMeshIndicesArray, data.m_subMeshIndicesCount, 
-		indicesCountArray, indicesOffsetArray, drawCount);
-	if(err)
-	{
-		return err;
-	}
+	m_modelPatch->getRenderingDataSub(
+		data.m_key,
+		SArray<U8>(const_cast<U8*>(data.m_subMeshIndicesArray),
+			data.m_subMeshIndicesCount),
+		vertBuff,
+		indexBuff,
+		ppline,
+		indicesCountArray,
+		indicesOffsetArray,
+		drawCount);
 
-	ppline.bind(data.m_jobs);
-	data.m_jobs.pushBackOtherCommandBuffer(vertJobs);
+	ppline.bind(data.m_cmdb);
 
 	if(drawCount == 1)
 	{
-		data.m_jobs.drawElements(
+		data.m_cmdb.bindVertexBuffer(0, vertBuff, 0);
+		data.m_cmdb.bindIndexBuffer(indexBuff, 0);
+
+		data.m_cmdb.drawElements(
 			data.m_key.m_tessellation ? GL_PATCHES : GL_TRIANGLES,
 			sizeof(U16),
 			indicesCountArray[0],
@@ -120,7 +122,7 @@ Error StaticGeometryPatchNode::buildRendering(RenderingBuildData& data)
 		ANKI_ASSERT(0 && "TODO");
 	}
 
-	return err;
+	return ErrorCode::NONE;
 }
 
 //==============================================================================
@@ -129,46 +131,35 @@ Error StaticGeometryPatchNode::buildRendering(RenderingBuildData& data)
 
 //==============================================================================
 StaticGeometryNode::StaticGeometryNode(SceneGraph* scene)
-:	SceneNode(scene)
+	: SceneNode(scene)
+{}
+
+//==============================================================================
+StaticGeometryNode::~StaticGeometryNode()
 {}
 
 //==============================================================================
 Error StaticGeometryNode::create(const CString& name, const CString& filename)
 {
-	Error err = SceneNode::create(name);
+	ANKI_CHECK(SceneNode::create(name));
 
-	if(!err)
-	{
-		err = m_model.load(filename, &getResourceManager());
-	}
+	ANKI_CHECK(m_model.load(filename, &getResourceManager()));
 
-	if(!err)
+	U i = 0;
+	for(const ModelPatch* patch : m_model->getModelPatches())
 	{
-		U i = 0;
-		for(const ModelPatchBase* patch : m_model->getModelPatches())
-		{
-			StringAuto newname(getSceneAllocator());
-			
-			newname.sprintf("%s_%u", &name[0], i);
-
-			StaticGeometryPatchNode* node;
-			err = getSceneGraph().newSceneNode<StaticGeometryPatchNode>(
-				newname.toCString(), node, patch);
-
-			if(err)
-			{
-				break;
-			}
-
-			++i;
-		}
+		StringAuto newname(getFrameAllocator());
+
+		newname.sprintf("%s_%u", &name[0], i);
+
+		StaticGeometryPatchNode* node;
+		ANKI_CHECK(getSceneGraph().newSceneNode<StaticGeometryPatchNode>(
+			newname.toCString(), node, patch));
+
+		++i;
 	}
 
-	return err;
+	return ErrorCode::NONE;
 }
 
-//==============================================================================
-StaticGeometryNode::~StaticGeometryNode()
-{}
-
 } // end namespace anki

+ 0 - 3
src/util/Assert.cpp

@@ -31,9 +31,6 @@ void akassert(const char* exprTxt, const char* file, int line,
 		file, line , func, exprTxt);
 #endif
 
-#if ANKI_CPU_ARCH == ANKI_CPU_ARCH_INTEL
-	asm("int $3");
-#endif
 	printBacktrace();
 	abort();
 }