Bladeren bron

Merge pull request #24 from godlikepanos/gr_init_refactoring

remove PIMPL from GR
Panagiotis Christopoulos Charitos 8 jaren geleden
bovenliggende
commit
21f29cc998
100 gewijzigde bestanden met toevoegingen van 1661 en 1459 verwijderingen
  1. 2 4
      src/anki/core/App.cpp
  2. 1 2
      src/anki/core/StagingGpuMemoryManager.cpp
  3. 37 9
      src/anki/gr/Buffer.h
  4. 13 9
      src/anki/gr/CommandBuffer.h
  5. 3 0
      src/anki/gr/Common.h
  6. 2 1
      src/anki/gr/Enums.h
  7. 16 9
      src/anki/gr/Fence.h
  8. 12 8
      src/anki/gr/Framebuffer.h
  9. 23 28
      src/anki/gr/GrManager.h
  10. 13 8
      src/anki/gr/OcclusionQuery.h
  11. 9 4
      src/anki/gr/RenderGraph.cpp
  12. 6 15
      src/anki/gr/RenderGraph.h
  13. 13 8
      src/anki/gr/Sampler.h
  14. 37 10
      src/anki/gr/Shader.h
  15. 21 14
      src/anki/gr/ShaderProgram.h
  16. 70 12
      src/anki/gr/Texture.h
  17. 24 0
      src/anki/gr/common/InstantiationMacros.h
  18. 42 69
      src/anki/gr/gl/Buffer.cpp
  19. 41 12
      src/anki/gr/gl/BufferImpl.h
  20. 205 157
      src/anki/gr/gl/CommandBuffer.cpp
  21. 12 7
      src/anki/gr/gl/CommandBufferImpl.cpp
  22. 2 11
      src/anki/gr/gl/CommandBufferImpl.h
  23. 3 0
      src/anki/gr/gl/Common.h
  24. 18 24
      src/anki/gr/gl/Fence.cpp
  25. 5 5
      src/anki/gr/gl/FenceImpl.cpp
  26. 3 2
      src/anki/gr/gl/FenceImpl.h
  27. 7 15
      src/anki/gr/gl/Framebuffer.cpp
  28. 16 16
      src/anki/gr/gl/FramebufferImpl.cpp
  29. 5 5
      src/anki/gr/gl/FramebufferImpl.h
  30. 25 32
      src/anki/gr/gl/GlObject.cpp
  31. 3 17
      src/anki/gr/gl/GlObject.h
  32. 100 20
      src/anki/gr/gl/GrManager.cpp
  33. 8 10
      src/anki/gr/gl/GrManagerImpl.cpp
  34. 4 8
      src/anki/gr/gl/GrManagerImpl.h
  35. 7 15
      src/anki/gr/gl/OcclusionQuery.cpp
  36. 4 3
      src/anki/gr/gl/OcclusionQueryImpl.h
  37. 22 22
      src/anki/gr/gl/RenderingThread.cpp
  38. 2 2
      src/anki/gr/gl/RenderingThread.h
  39. 7 16
      src/anki/gr/gl/Sampler.cpp
  40. 4 3
      src/anki/gr/gl/SamplerImpl.h
  41. 33 45
      src/anki/gr/gl/Shader.cpp
  42. 4 4
      src/anki/gr/gl/ShaderImpl.cpp
  43. 2 2
      src/anki/gr/gl/ShaderImpl.h
  44. 30 75
      src/anki/gr/gl/ShaderProgram.cpp
  45. 8 13
      src/anki/gr/gl/ShaderProgramImpl.cpp
  46. 6 2
      src/anki/gr/gl/ShaderProgramImpl.h
  47. 19 12
      src/anki/gr/gl/StateTracker.h
  48. 28 38
      src/anki/gr/gl/Texture.cpp
  49. 36 32
      src/anki/gr/gl/TextureImpl.cpp
  50. 9 15
      src/anki/gr/gl/TextureImpl.h
  51. 7 18
      src/anki/gr/vulkan/Buffer.cpp
  52. 3 5
      src/anki/gr/vulkan/BufferImpl.h
  53. 108 71
      src/anki/gr/vulkan/CommandBuffer.cpp
  54. 60 46
      src/anki/gr/vulkan/CommandBufferImpl.cpp
  55. 18 10
      src/anki/gr/vulkan/CommandBufferImpl.h
  56. 34 29
      src/anki/gr/vulkan/CommandBufferImpl.inl.h
  57. 3 0
      src/anki/gr/vulkan/Common.h
  58. 17 16
      src/anki/gr/vulkan/DescriptorSet.h
  59. 5 8
      src/anki/gr/vulkan/Fence.cpp
  60. 1 1
      src/anki/gr/vulkan/FenceFactory.h
  61. 1 1
      src/anki/gr/vulkan/FenceFactory.inl.h
  62. 3 2
      src/anki/gr/vulkan/FenceImpl.h
  63. 3 15
      src/anki/gr/vulkan/Framebuffer.cpp
  64. 8 8
      src/anki/gr/vulkan/FramebufferImpl.cpp
  65. 4 3
      src/anki/gr/vulkan/FramebufferImpl.h
  66. 95 17
      src/anki/gr/vulkan/GrManager.cpp
  67. 3 9
      src/anki/gr/vulkan/GrManagerImpl.cpp
  68. 3 8
      src/anki/gr/vulkan/GrManagerImpl.h
  69. 3 16
      src/anki/gr/vulkan/OcclusionQuery.cpp
  70. 4 3
      src/anki/gr/vulkan/OcclusionQueryImpl.h
  71. 2 2
      src/anki/gr/vulkan/Pipeline.cpp
  72. 5 4
      src/anki/gr/vulkan/Pipeline.h
  73. 3 16
      src/anki/gr/vulkan/Sampler.cpp
  74. 3 2
      src/anki/gr/vulkan/SamplerImpl.h
  75. 3 18
      src/anki/gr/vulkan/Shader.cpp
  76. 7 6
      src/anki/gr/vulkan/ShaderImpl.cpp
  77. 4 4
      src/anki/gr/vulkan/ShaderImpl.h
  78. 3 56
      src/anki/gr/vulkan/ShaderProgram.cpp
  79. 10 14
      src/anki/gr/vulkan/ShaderProgramImpl.cpp
  80. 8 3
      src/anki/gr/vulkan/ShaderProgramImpl.h
  81. 3 16
      src/anki/gr/vulkan/Texture.cpp
  82. 14 20
      src/anki/gr/vulkan/TextureImpl.cpp
  83. 15 21
      src/anki/gr/vulkan/TextureImpl.h
  84. 3 3
      src/anki/gr/vulkan/TextureImpl.inl.h
  85. 30 18
      src/anki/gr/vulkan/VulkanObject.cpp
  86. 20 21
      src/anki/gr/vulkan/VulkanObject.h
  87. 27 0
      src/anki/gr/vulkan/VulkanObject.inl.h
  88. 1 1
      src/anki/renderer/DebugDrawer.cpp
  89. 4 6
      src/anki/renderer/Indirect.cpp
  90. 1 1
      src/anki/renderer/LensFlare.cpp
  91. 1 1
      src/anki/renderer/MainRenderer.cpp
  92. 7 8
      src/anki/renderer/Renderer.cpp
  93. 2 2
      src/anki/renderer/Tonemapping.cpp
  94. 4 4
      src/anki/resource/Mesh.cpp
  95. 8 8
      src/anki/resource/ShaderProgramResource.cpp
  96. 2 3
      src/anki/resource/TextureResource.cpp
  97. 1 1
      src/anki/resource/TransferGpuAllocator.cpp
  98. 3 4
      src/anki/ui/Font.cpp
  99. 2 3
      tests/framework/Framework.cpp
  100. 60 57
      tests/gr/Gr.cpp

+ 2 - 4
src/anki/core/App.cpp

@@ -91,7 +91,7 @@ void App::cleanup()
 
 	if(m_gr)
 	{
-		m_heapAlloc.deleteInstance(m_gr);
+		GrManager::deleteInstance(m_gr);
 		m_gr = nullptr;
 	}
 
@@ -225,8 +225,6 @@ Error App::initInternal(const ConfigSet& config_, AllocAlignedCallback allocCb,
 	//
 	// Graphics API
 	//
-	m_gr = m_heapAlloc.newInstance<GrManager>();
-
 	GrManagerInitInfo grInit;
 	grInit.m_allocCallback = m_allocCb;
 	grInit.m_allocCallbackUserData = m_allocCbData;
@@ -234,7 +232,7 @@ Error App::initInternal(const ConfigSet& config_, AllocAlignedCallback allocCb,
 	grInit.m_config = &config;
 	grInit.m_window = m_window;
 
-	ANKI_CHECK(m_gr->init(grInit));
+	ANKI_CHECK(GrManager::newInstance(grInit, m_gr));
 
 	//
 	// Staging mem

+ 1 - 2
src/anki/core/StagingGpuMemoryManager.cpp

@@ -53,8 +53,7 @@ void StagingGpuMemoryManager::initBuffer(
 {
 	auto& perframe = m_perFrameBuffers[type];
 
-	perframe.m_buff =
-		gr.newInstance<Buffer>(BufferInitInfo(perframe.m_size, usage, BufferMapAccessBit::WRITE, "Staging"));
+	perframe.m_buff = gr.newBuffer(BufferInitInfo(perframe.m_size, usage, BufferMapAccessBit::WRITE, "Staging"));
 	perframe.m_alloc.init(perframe.m_size, alignment, maxAllocSize);
 	perframe.m_mappedMem = static_cast<U8*>(perframe.m_buff->map(0, perframe.m_size, BufferMapAccessBit::WRITE));
 }

+ 37 - 9
src/anki/gr/Buffer.h

@@ -38,30 +38,58 @@ public:
 };
 
 /// GPU buffer.
-class Buffer final : public GrObject
+class Buffer : public GrObject
 {
 	ANKI_GR_OBJECT
 
 public:
+	static const GrObjectType CLASS_TYPE = GrObjectType::BUFFER;
+
+	/// Return the size of the buffer.
+	PtrSize getSize() const
+	{
+		ANKI_ASSERT(m_size > 0);
+		return m_size;
+	}
+
+	/// Return the BufferUsageBit of the Buffer.
+	BufferUsageBit getBufferUsage() const
+	{
+		ANKI_ASSERT(!!m_usage);
+		return m_usage;
+	}
+
+	/// Return the BufferMapAccessBit of the Buffer.
+	BufferMapAccessBit getMapAccess() const
+	{
+		return m_access;
+	}
+
 	/// Map the buffer.
 	void* map(PtrSize offset, PtrSize range, BufferMapAccessBit access);
 
 	/// Unmap the buffer.
 	void unmap();
 
-anki_internal:
-	static const GrObjectType CLASS_TYPE = GrObjectType::BUFFER;
-
-	UniquePtr<BufferImpl> m_impl;
+protected:
+	PtrSize m_size = 0;
+	BufferUsageBit m_usage = BufferUsageBit::NONE;
+	BufferMapAccessBit m_access = BufferMapAccessBit::NONE;
 
 	/// Construct.
-	Buffer(GrManager* manager);
+	Buffer(GrManager* manager)
+		: GrObject(manager, CLASS_TYPE)
+	{
+	}
 
 	/// Destroy.
-	~Buffer();
+	~Buffer()
+	{
+	}
 
-	/// Allocate the buffer.
-	void init(const BufferInitInfo& init);
+private:
+	/// Allocate and initialize new instance.
+	static ANKI_USE_RESULT Buffer* newInstance(GrManager* manager, const BufferInitInfo& init);
 };
 /// @}
 

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

@@ -131,6 +131,8 @@ class CommandBuffer : public GrObject
 	ANKI_GR_OBJECT
 
 public:
+	static const GrObjectType CLASS_TYPE = GrObjectType::COMMAND_BUFFER;
+
 	/// Compute initialization hints.
 	CommandBufferInitHints computeInitHints() const;
 
@@ -404,19 +406,21 @@ public:
 	Bool isEmpty() const;
 	/// @}
 
-anki_internal:
-	UniquePtr<CommandBufferImpl> m_impl;
-
-	static const GrObjectType CLASS_TYPE = GrObjectType::COMMAND_BUFFER;
-
+protected:
 	/// Construct.
-	CommandBuffer(GrManager* manager);
+	CommandBuffer(GrManager* manager)
+		: GrObject(manager, CLASS_TYPE)
+	{
+	}
 
 	/// Destroy.
-	~CommandBuffer();
+	~CommandBuffer()
+	{
+	}
 
-	/// Init the command buffer.
-	void init(CommandBufferInitInfo& inf);
+private:
+	/// Allocate and initialize new instance.
+	static ANKI_USE_RESULT CommandBuffer* newInstance(GrManager* manager, const CommandBufferInitInfo& init);
 };
 /// @}
 

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

@@ -23,6 +23,9 @@ class SamplerInitInfo;
 class GrManagerInitInfo;
 class FramebufferInitInfo;
 class BufferInitInfo;
+class ShaderInitInfo;
+class ShaderProgramInitInfo;
+class CommandBufferInitInfo;
 
 /// @addtogroup graphics
 /// @{

+ 2 - 1
src/anki/gr/Enums.h

@@ -179,7 +179,8 @@ enum class TextureType : U8
 	_3D,
 	_2D_ARRAY,
 	CUBE,
-	CUBE_ARRAY
+	CUBE_ARRAY,
+	COUNT
 };
 
 /// Texture usage hints. They are very important.

+ 16 - 9
src/anki/gr/Fence.h

@@ -14,26 +14,33 @@ namespace anki
 /// @{
 
 /// GPU fence.
-class Fence final : public GrObject
+class Fence : public GrObject
 {
 	ANKI_GR_OBJECT
 
 public:
+	static const GrObjectType CLASS_TYPE = GrObjectType::FENCE;
+
 	/// Wait for the fence.
 	/// @param seconds The time to wait in seconds. If it's zero then just return the status.
 	/// @return True if is signaled (signaled == GPU work is done).
-	Bool clientWait(F64 seconds);
-
-anki_internal:
-	static const GrObjectType CLASS_TYPE = GrObjectType::FENCE;
-
-	UniquePtr<FenceImpl> m_impl;
+	Bool clientWait(Second seconds);
 
+protected:
 	/// Construct.
-	Fence(GrManager* manager);
+	Fence(GrManager* manager)
+		: GrObject(manager, CLASS_TYPE)
+	{
+	}
 
 	/// Destroy.
-	~Fence();
+	~Fence()
+	{
+	}
+
+private:
+	/// Allocate and initialize new instance.
+	static ANKI_USE_RESULT Fence* newInstance(GrManager* manager);
 };
 /// @}
 

+ 12 - 8
src/anki/gr/Framebuffer.h

@@ -79,23 +79,27 @@ public:
 };
 
 /// GPU framebuffer.
-class Framebuffer final : public GrObject
+class Framebuffer : public GrObject
 {
 	ANKI_GR_OBJECT
 
-anki_internal:
-	UniquePtr<FramebufferImpl> m_impl;
-
+public:
 	static const GrObjectType CLASS_TYPE = GrObjectType::FRAMEBUFFER;
 
+protected:
 	/// Construct.
-	Framebuffer(GrManager* manager);
+	Framebuffer(GrManager* manager)
+		: GrObject(manager, CLASS_TYPE)
+	{
+	}
 
 	/// Destroy.
-	~Framebuffer();
+	~Framebuffer()
+	{
+	}
 
-	/// Create.
-	void init(const FramebufferInitInfo& init);
+private:
+	static ANKI_USE_RESULT Framebuffer* newInstance(GrManager* manager, const FramebufferInitInfo& init);
 };
 /// @}
 

+ 23 - 28
src/anki/gr/GrManager.h

@@ -35,19 +35,12 @@ public:
 /// The graphics manager, owner of all graphics objects.
 class GrManager
 {
-	friend class GrManagerImpl;
-
-	template<typename>
-	friend class GrObjectPtrDeleter;
-
 public:
-	/// Default constructor
-	GrManager();
-
-	~GrManager();
-
 	/// Create.
-	ANKI_USE_RESULT Error init(GrManagerInitInfo& init);
+	static ANKI_USE_RESULT Error newInstance(GrManagerInitInfo& init, GrManager*& gr);
+
+	/// Destroy.
+	static void deleteInstance(GrManager* gr);
 
 	/// Begin frame.
 	void beginFrame();
@@ -58,14 +51,18 @@ public:
 	/// Wait for all work to finish.
 	void finish();
 
-	/// Create a new graphics object.
-	template<typename T, typename... Args>
-	ANKI_USE_RESULT GrObjectPtr<T> newInstance(Args&&... args)
-	{
-		GrObjectPtr<T> ptr(m_alloc.newInstance<T>(this));
-		ptr->init(args...);
-		return ptr;
-	}
+	/// @name Object creation methods. They are thread-safe.
+	/// @{
+	ANKI_USE_RESULT BufferPtr newBuffer(const BufferInitInfo& init);
+	ANKI_USE_RESULT TexturePtr newTexture(const TextureInitInfo& init);
+	ANKI_USE_RESULT SamplerPtr newSampler(const SamplerInitInfo& init);
+	ANKI_USE_RESULT ShaderPtr newShader(const ShaderInitInfo& init);
+	ANKI_USE_RESULT ShaderProgramPtr newShaderProgram(const ShaderProgramInitInfo& init);
+	ANKI_USE_RESULT CommandBufferPtr newCommandBuffer(const CommandBufferInitInfo& init);
+	ANKI_USE_RESULT FramebufferPtr newFramebuffer(const FramebufferInitInfo& init);
+	ANKI_USE_RESULT OcclusionQueryPtr newOcclusionQuery();
+	ANKI_USE_RESULT RenderGraphPtr newRenderGraph();
+	/// @}
 
 	/// Call this before calling allocateFrameTransientMemory or tryAllocateFrameTransientMemory to get the exact memory
 	/// that will be required for the CommandBuffer::uploadTextureSurface.
@@ -95,14 +92,9 @@ anki_internal:
 		return m_alloc;
 	}
 
-	GrManagerImpl& getImplementation()
+	GrAllocator<U8> getAllocator() const
 	{
-		return *m_impl;
-	}
-
-	const GrManagerImpl& getImplementation() const
-	{
-		return *m_impl;
+		return m_alloc;
 	}
 
 	CString getCacheDirectory() const
@@ -115,11 +107,14 @@ anki_internal:
 		return m_uuidIndex;
 	}
 
-private:
+protected:
 	GrAllocator<U8> m_alloc; ///< Keep it first to get deleted last
 	String m_cacheDir;
-	UniquePtr<GrManagerImpl> m_impl;
 	U64 m_uuidIndex = 1;
+
+	GrManager();
+
+	virtual ~GrManager();
 };
 /// @}
 

+ 13 - 8
src/anki/gr/OcclusionQuery.h

@@ -14,23 +14,28 @@ namespace anki
 /// @{
 
 /// Occlusion query.
-class OcclusionQuery final : public GrObject
+class OcclusionQuery : public GrObject
 {
 	ANKI_GR_OBJECT
 
-anki_internal:
-	UniquePtr<OcclusionQueryImpl> m_impl;
-
+public:
 	static const GrObjectType CLASS_TYPE = GrObjectType::OCCLUSION_QUERY;
 
+protected:
 	/// Construct.
-	OcclusionQuery(GrManager* manager);
+	OcclusionQuery(GrManager* manager)
+		: GrObject(manager, CLASS_TYPE)
+	{
+	}
 
 	/// Destroy.
-	~OcclusionQuery();
+	~OcclusionQuery()
+	{
+	}
 
-	/// Create a query.
-	void init();
+private:
+	/// Allocate and initialize new instance.
+	static ANKI_USE_RESULT OcclusionQuery* newInstance(GrManager* manager);
 };
 /// @}
 

+ 9 - 4
src/anki/gr/RenderGraph.cpp

@@ -263,6 +263,11 @@ RenderGraph::~RenderGraph()
 	m_fbCache.destroy(getAllocator());
 }
 
+RenderGraph* RenderGraph::newInstance(GrManager* manager)
+{
+	return manager->getAllocator().newInstance<RenderGraph>(manager);
+}
+
 void RenderGraph::reset()
 {
 	if(!m_ctx)
@@ -332,7 +337,7 @@ TexturePtr RenderGraph::getOrCreateRenderTarget(const TextureInitInfo& initInf,
 	{
 		// Create it
 
-		tex = getManager().newInstance<Texture>(initInf);
+		tex = getManager().newTexture(initInf);
 
 		ANKI_ASSERT(entry->m_texturesInUse == entry->m_textures.getSize());
 		entry->m_textures.resize(alloc, entry->m_textures.getSize() + 1);
@@ -395,7 +400,7 @@ FramebufferPtr RenderGraph::getOrCreateFramebuffer(
 			}
 		}
 
-		fb = getManager().newInstance<Framebuffer>(fbInit);
+		fb = getManager().newFramebuffer(fbInit);
 
 		// TODO: Check why the hell it compiles if you remove the parameter "hash"
 		m_fbCache.emplace(getAllocator(), hash, fb);
@@ -629,7 +634,7 @@ void RenderGraph::initRenderPassesAndSetDeps(const RenderGraphDescription& descr
 					cmdbInit.m_depthStencilAttachmentUsage = outPass.m_dsUsage;
 					for(U cmdbIdx = 0; cmdbIdx < inPass.m_secondLevelCmdbsCount; ++cmdbIdx)
 					{
-						outPass.m_secondLevelCmdbs[cmdbIdx] = getManager().newInstance<CommandBuffer>(cmdbInit);
+						outPass.m_secondLevelCmdbs[cmdbIdx] = getManager().newCommandBuffer(cmdbInit);
 					}
 				}
 			}
@@ -887,7 +892,7 @@ void RenderGraph::compileNewGraph(const RenderGraphDescription& descr, StackAllo
 	// Create main command buffer
 	CommandBufferInitInfo cmdbInit;
 	cmdbInit.m_flags = CommandBufferFlag::GRAPHICS_WORK | CommandBufferFlag::COMPUTE_WORK;
-	m_ctx->m_cmdb = getManager().newInstance<CommandBuffer>(cmdbInit);
+	m_ctx->m_cmdb = getManager().newCommandBuffer(cmdbInit);
 
 #if ANKI_DBG_RENDER_GRAPH
 	if(dumpDependencyDotFile(descr, ctx, "./"))

+ 6 - 15
src/anki/gr/RenderGraph.h

@@ -600,21 +600,6 @@ class RenderGraph final : public GrObject
 public:
 	static const GrObjectType CLASS_TYPE = GrObjectType::RENDER_GRAPH;
 
-	RenderGraph(GrManager* manager);
-
-	// Non-copyable
-	RenderGraph(const RenderGraph&) = delete;
-
-	~RenderGraph();
-
-	// Non-copyable
-	RenderGraph& operator=(const RenderGraph&) = delete;
-
-	void init()
-	{
-		// Do nothing, implement the method to align with the general interface
-	}
-
 	/// @name 1st step methods
 	/// @{
 	void compileNewGraph(const RenderGraphDescription& descr, StackAllocator<U8>& alloc);
@@ -670,6 +655,12 @@ private:
 	BakeContext* m_ctx = nullptr;
 	U64 m_version = 0;
 
+	RenderGraph(GrManager* manager);
+
+	~RenderGraph();
+
+	static ANKI_USE_RESULT RenderGraph* newInstance(GrManager* manager);
+
 	BakeContext* newContext(const RenderGraphDescription& descr, StackAllocator<U8>& alloc);
 	void initRenderPassesAndSetDeps(const RenderGraphDescription& descr, StackAllocator<U8>& alloc);
 	void initBatches();

+ 13 - 8
src/anki/gr/Sampler.h

@@ -15,23 +15,28 @@ namespace anki
 /// @{
 
 /// GPU sampler.
-class Sampler final : public GrObject
+class Sampler : public GrObject
 {
 	ANKI_GR_OBJECT
 
-anki_internal:
-	UniquePtr<SamplerImpl> m_impl;
-
+public:
 	static const GrObjectType CLASS_TYPE = GrObjectType::SAMPLER;
 
+protected:
 	/// Construct.
-	Sampler(GrManager* manager);
+	Sampler(GrManager* manager)
+		: GrObject(manager, CLASS_TYPE)
+	{
+	}
 
 	/// Destroy.
-	~Sampler();
+	~Sampler()
+	{
+	}
 
-	/// Initialize it.
-	void init(const SamplerInitInfo& init);
+private:
+	/// Allocate and initialize new instance.
+	static ANKI_USE_RESULT Sampler* newInstance(GrManager* manager, const SamplerInitInfo& init);
 };
 /// @}
 

+ 37 - 10
src/anki/gr/Shader.h

@@ -65,26 +65,53 @@ void writeShaderBlockMemory(ShaderVariableDataType type,
 	void* buffBegin,
 	const void* buffEnd);
 
+/// Shader init info.
+class ShaderInitInfo : public GrBaseInitInfo
+{
+public:
+	ShaderType m_shaderType = ShaderType::COUNT;
+	CString m_source = {};
+
+	ShaderInitInfo()
+	{
+	}
+
+	ShaderInitInfo(CString name)
+		: GrBaseInitInfo(name)
+	{
+	}
+
+	ShaderInitInfo(ShaderType type, CString source, CString name = {})
+		: GrBaseInitInfo(name)
+		, m_shaderType(type)
+		, m_source(source)
+	{
+	}
+};
+
 /// GPU shader.
-class Shader final : public GrObject
+class Shader : public GrObject
 {
 	ANKI_GR_OBJECT
 
-anki_internal:
-	UniquePtr<ShaderImpl> m_impl;
-
+public:
 	static const GrObjectType CLASS_TYPE = GrObjectType::SHADER;
 
+protected:
 	/// Construct.
-	Shader(GrManager* manager);
+	Shader(GrManager* manager)
+		: GrObject(manager, CLASS_TYPE)
+	{
+	}
 
 	/// Destroy.
-	~Shader();
+	~Shader()
+	{
+	}
 
-	/// Create shader.
-	/// @param shaderType The type of the shader.
-	/// @param source The GLSL code of the shader.
-	void init(ShaderType shaderType, const CString& source);
+private:
+	/// Allocate and initialize new instance.
+	static ANKI_USE_RESULT Shader* newInstance(GrManager* manager, const ShaderInitInfo& init);
 };
 /// @}
 

+ 21 - 14
src/anki/gr/ShaderProgram.h

@@ -6,6 +6,7 @@
 #pragma once
 
 #include <anki/gr/GrObject.h>
+#include <anki/gr/Shader.h>
 
 namespace anki
 {
@@ -13,30 +14,36 @@ namespace anki
 /// @addtogroup graphics
 /// @{
 
+/// ShaderProgram init info.
+class ShaderProgramInitInfo : GrBaseInitInfo
+{
+public:
+	Array<ShaderPtr, U(ShaderType::COUNT)> m_shaders = {};
+};
+
 /// GPU program.
-class ShaderProgram final : public GrObject
+class ShaderProgram : public GrObject
 {
 	ANKI_GR_OBJECT
 
-anki_internal:
-	UniquePtr<ShaderProgramImpl> m_impl;
-
+public:
 	static const GrObjectType CLASS_TYPE = GrObjectType::SHADER_PROGRAM;
 
+protected:
 	/// Construct.
-	ShaderProgram(GrManager* manager);
+	ShaderProgram(GrManager* manager)
+		: GrObject(manager, CLASS_TYPE)
+	{
+	}
 
 	/// Destroy.
-	~ShaderProgram();
-
-	/// Create vertex+fragment.
-	void init(ShaderPtr vert, ShaderPtr frag);
-
-	/// Create compute.
-	void init(ShaderPtr comp);
+	~ShaderProgram()
+	{
+	}
 
-	/// Create with all.
-	void init(ShaderPtr vert, ShaderPtr tessc, ShaderPtr tesse, ShaderPtr geom, ShaderPtr frag);
+private:
+	/// Allocate and initialize new instance.
+	static ANKI_USE_RESULT ShaderProgram* newInstance(GrManager* manager, const ShaderProgramInitInfo& init);
 };
 /// @}
 

+ 70 - 12
src/anki/gr/Texture.h

@@ -53,9 +53,6 @@ public:
 	TextureUsageBit m_usage = TextureUsageBit::NONE; ///< How the texture will be used.
 	TextureUsageBit m_initialUsage = TextureUsageBit::NONE; ///< It's initial usage.
 
-	/// It's usual usage. That way you won't need to call CommandBuffer::informTextureXXXCurrentUsage() all the time.
-	TextureUsageBit m_usageWhenEncountered = TextureUsageBit::NONE;
-
 	TextureType m_type = TextureType::_2D;
 
 	U8 m_mipmapsCount = 1;
@@ -83,24 +80,85 @@ public:
 static_assert(sizeof(TextureInitInfo) == sizeof(GrBaseInitInfo) + 28 + sizeof(SamplerInitInfo),
 	"Class needs to be tightly packed since we hash it");
 
-/// GPU texture
-class Texture final : public GrObject
+/// GPU texture.
+class Texture : public GrObject
 {
 	ANKI_GR_OBJECT
 
-anki_internal:
-	UniquePtr<TextureImpl> m_impl;
-
+public:
 	static const GrObjectType CLASS_TYPE = GrObjectType::TEXTURE;
 
+	U32 getWidth() const
+	{
+		ANKI_ASSERT(m_width);
+		return m_width;
+	}
+
+	U32 getHeight() const
+	{
+		ANKI_ASSERT(m_height);
+		return m_height;
+	}
+
+	U32 getDepth() const
+	{
+		ANKI_ASSERT(m_depth);
+		return m_depth;
+	}
+
+	U32 getLayercount() const
+	{
+		ANKI_ASSERT(m_layerCount);
+		return m_layerCount;
+	}
+
+	U32 getMipmapCount() const
+	{
+		ANKI_ASSERT(m_mipCount);
+		return m_mipCount;
+	}
+
+	TextureType getTextureType() const
+	{
+		ANKI_ASSERT(m_texType != TextureType::COUNT);
+		return m_texType;
+	}
+
+	TextureUsageBit getTextureUsage() const
+	{
+		ANKI_ASSERT(!!m_usage);
+		return m_usage;
+	}
+
+	const PixelFormat& getPixelFormat() const
+	{
+		return m_format;
+	}
+
+protected:
+	U32 m_width = 0;
+	U32 m_height = 0;
+	U32 m_depth = 0;
+	U32 m_layerCount = 0;
+	U32 m_mipCount = 0;
+	TextureType m_texType = TextureType::COUNT;
+	TextureUsageBit m_usage = TextureUsageBit::NONE;
+	PixelFormat m_format;
+
 	/// Construct.
-	Texture(GrManager* manager);
+	Texture(GrManager* manager)
+		: GrObject(manager, CLASS_TYPE)
+	{
+	}
 
 	/// Destroy.
-	~Texture();
+	~Texture()
+	{
+	}
 
-	/// Create it.
-	void init(const TextureInitInfo& init);
+private:
+	/// Allocate and initialize new instance.
+	static ANKI_USE_RESULT Texture* newInstance(GrManager* manager, const TextureInitInfo& init);
 };
 /// @}
 

+ 24 - 0
src/anki/gr/common/InstantiationMacros.h

@@ -0,0 +1,24 @@
+// Copyright (C) 2009-2017, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+// An awful trick to instantiate stuff with the graphics object type
+
+ANKI_INSTANTIATE_GR_OBJECT(Buffer)
+ANKI_INSTANTIATE_GR_OBJECT_DELIMITER()
+ANKI_INSTANTIATE_GR_OBJECT(CommandBuffer)
+ANKI_INSTANTIATE_GR_OBJECT_DELIMITER()
+ANKI_INSTANTIATE_GR_OBJECT(Fence)
+ANKI_INSTANTIATE_GR_OBJECT_DELIMITER()
+ANKI_INSTANTIATE_GR_OBJECT(Framebuffer)
+ANKI_INSTANTIATE_GR_OBJECT_DELIMITER()
+ANKI_INSTANTIATE_GR_OBJECT(OcclusionQuery)
+ANKI_INSTANTIATE_GR_OBJECT_DELIMITER()
+ANKI_INSTANTIATE_GR_OBJECT(Sampler)
+ANKI_INSTANTIATE_GR_OBJECT_DELIMITER()
+ANKI_INSTANTIATE_GR_OBJECT(Shader)
+ANKI_INSTANTIATE_GR_OBJECT_DELIMITER()
+ANKI_INSTANTIATE_GR_OBJECT(ShaderProgram)
+ANKI_INSTANTIATE_GR_OBJECT_DELIMITER()
+ANKI_INSTANTIATE_GR_OBJECT(Texture)

+ 42 - 69
src/anki/gr/gl/Buffer.cpp

@@ -11,85 +11,58 @@
 namespace anki
 {
 
-Buffer::Buffer(GrManager* manager)
-	: GrObject(manager, CLASS_TYPE)
+Buffer* Buffer::newInstance(GrManager* manager, const BufferInitInfo& inf)
 {
-}
-
-Buffer::~Buffer()
-{
-}
-
-class BufferCreateCommand final : public GlCommand
-{
-public:
-	BufferPtr m_buff;
-	PtrSize m_size;
-	BufferUsageBit m_usage;
-	BufferMapAccessBit m_access;
-
-	BufferCreateCommand(Buffer* buff, PtrSize size, BufferUsageBit usage, BufferMapAccessBit access)
-		: m_buff(buff)
-		, m_size(size)
-		, m_usage(usage)
-		, m_access(access)
-	{
-	}
-
-	Error operator()(GlState&)
+	class BufferCreateCommand final : public GlCommand
 	{
-		BufferImpl& impl = *m_buff->m_impl;
-
-		impl.init(m_size, m_usage, m_access);
-
-		GlObject::State oldState = impl.setStateAtomically(GlObject::State::CREATED);
-
-		(void)oldState;
-		ANKI_ASSERT(oldState == GlObject::State::TO_BE_CREATED);
-
-		return Error::NONE;
-	}
-};
-
-void Buffer::init(const BufferInitInfo& inf)
-{
-	m_impl.reset(getAllocator().newInstance<BufferImpl>(&getManager()));
-
-	CommandBufferPtr cmdb = getManager().newInstance<CommandBuffer>(CommandBufferInitInfo());
-
-	cmdb->m_impl->pushBackNewCommand<BufferCreateCommand>(this, inf.m_size, inf.m_usage, inf.m_access);
-	cmdb->flush();
+	public:
+		BufferPtr m_buff;
+		PtrSize m_size;
+		BufferUsageBit m_usage;
+		BufferMapAccessBit m_access;
+
+		BufferCreateCommand(Buffer* buff, PtrSize size, BufferUsageBit usage, BufferMapAccessBit access)
+			: m_buff(buff)
+			, m_size(size)
+			, m_usage(usage)
+			, m_access(access)
+		{
+		}
+
+		Error operator()(GlState&)
+		{
+			BufferImpl& impl = static_cast<BufferImpl&>(*m_buff);
+
+			impl.init(m_size, m_usage, m_access);
+
+			GlObject::State oldState = impl.setStateAtomically(GlObject::State::CREATED);
+			(void)oldState;
+			ANKI_ASSERT(oldState == GlObject::State::TO_BE_CREATED);
+
+			return Error::NONE;
+		}
+	};
+
+	BufferImpl* impl = manager->getAllocator().newInstance<BufferImpl>(manager);
+
+	CommandBufferPtr cmdb = manager->newCommandBuffer(CommandBufferInitInfo());
+	static_cast<CommandBufferImpl&>(*cmdb).pushBackNewCommand<BufferCreateCommand>(
+		impl, inf.m_size, inf.m_usage, inf.m_access);
+	static_cast<CommandBufferImpl&>(*cmdb).flush();
+
+	return impl;
 }
 
 void* Buffer::map(PtrSize offset, PtrSize range, BufferMapAccessBit access)
 {
-	// Wait for its creation
-	if(m_impl->serializeRenderingThread())
-	{
-		return nullptr;
-	}
-
-	// Sanity checks
-	ANKI_ASSERT(offset + range <= m_impl->m_size);
-	ANKI_ASSERT(m_impl->m_persistentMapping);
-
-	U8* ptr = static_cast<U8*>(m_impl->m_persistentMapping);
-	ptr += offset;
-
-#if ANKI_EXTRA_CHECKS
-	ANKI_ASSERT(!m_impl->m_mapped);
-	m_impl->m_mapped = true;
-#endif
-
-	return static_cast<void*>(ptr);
+	ANKI_GL_SELF(BufferImpl);
+	return self.map(offset, range, access);
 }
 
 void Buffer::unmap()
 {
-#if ANKI_EXTRA_CHECKS
-	ANKI_ASSERT(m_impl->m_mapped);
-	m_impl->m_mapped = false;
-#endif
+	ANKI_GL_SELF(BufferImpl);
+	self.unmap();
 }
 
 } // end namespace anki

+ 41 - 12
src/anki/gr/gl/BufferImpl.h

@@ -5,6 +5,7 @@
 
 #pragma once
 
+#include <anki/gr/Buffer.h>
 #include <anki/gr/gl/GlObject.h>
 
 namespace anki
@@ -14,26 +15,17 @@ namespace anki
 /// @{
 
 /// Buffer implementation
-class BufferImpl : public GlObject
+class BufferImpl final : public Buffer, public GlObject
 {
 public:
-	U32 m_size = 0; ///< The size of the buffer
-	void* m_persistentMapping = nullptr;
-	BufferUsageBit m_usage = BufferUsageBit::NONE;
-	BufferMapAccessBit m_access = BufferMapAccessBit::NONE;
-	GLenum m_target = GL_NONE; ///< A guess
-#if ANKI_EXTRA_CHECKS
-	Bool m_mapped = false;
-#endif
-
 	BufferImpl(GrManager* manager)
-		: GlObject(manager)
+		: Buffer(manager)
 	{
 	}
 
 	~BufferImpl()
 	{
-		destroyDeferred(glDeleteBuffers);
+		destroyDeferred(getManager(), glDeleteBuffers);
 	}
 
 	void init(PtrSize size, BufferUsageBit usage, BufferMapAccessBit access);
@@ -74,6 +66,43 @@ public:
 
 		glClearNamedBufferSubData(m_glName, GL_R32UI, offset, size, GL_RED_INTEGER, GL_UNSIGNED_INT, &value);
 	}
+
+	void* map(PtrSize offset, PtrSize range, BufferMapAccessBit access)
+	{
+		// Wait for its creation
+		if(serializeRenderingThread(getManager()))
+		{
+			return nullptr;
+		}
+
+		// Sanity checks
+		ANKI_ASSERT(offset + range <= m_size);
+		ANKI_ASSERT(m_persistentMapping);
+
+		U8* ptr = static_cast<U8*>(m_persistentMapping);
+		ptr += offset;
+
+#if ANKI_EXTRA_CHECKS
+		ANKI_ASSERT(!m_mapped);
+		m_mapped = true;
+#endif
+		return static_cast<void*>(ptr);
+	}
+
+	void unmap()
+	{
+#if ANKI_EXTRA_CHECKS
+		ANKI_ASSERT(m_mapped);
+		m_mapped = false;
+#endif
+	}
+
+private:
+	void* m_persistentMapping = nullptr;
+	GLenum m_target = GL_NONE; ///< A guess
+#if ANKI_EXTRA_CHECKS
+	Bool m_mapped = false;
+#endif
 };
 /// @}
 

+ 205 - 157
src/anki/gr/gl/CommandBuffer.cpp

@@ -28,55 +28,44 @@
 namespace anki
 {
 
-CommandBuffer::CommandBuffer(GrManager* manager)
-	: GrObject(manager, CLASS_TYPE)
+CommandBuffer* CommandBuffer::newInstance(GrManager* manager, const CommandBufferInitInfo& inf)
 {
-}
-
-CommandBuffer::~CommandBuffer()
-{
-}
-
-void CommandBuffer::init(CommandBufferInitInfo& inf)
-{
-	m_impl.reset(getAllocator().newInstance<CommandBufferImpl>(&getManager()));
-	m_impl->init(inf);
-
-#if ANKI_EXTRA_CHECKS
-	m_impl->m_state.m_secondLevel = !!(inf.m_flags & CommandBufferFlag::SECOND_LEVEL);
-#endif
-
-	if(!!(inf.m_flags & CommandBufferFlag::SECOND_LEVEL))
-	{
-		m_impl->m_state.m_fb = inf.m_framebuffer->m_impl.get();
-	}
+	CommandBufferImpl* impl = manager->getAllocator().newInstance<CommandBufferImpl>(manager);
+	impl->init(inf);
+	return impl;
 }
 
 void CommandBuffer::flush(FencePtr* fence)
 {
-	if(!m_impl->isSecondLevel())
+	ANKI_GL_SELF(CommandBufferImpl);
+
+	if(!self.isSecondLevel())
 	{
-		ANKI_ASSERT(!m_impl->m_state.insideRenderPass());
+		ANKI_ASSERT(!self.m_state.insideRenderPass());
 	}
 	else
 	{
 		ANKI_ASSERT(fence == nullptr);
 	}
 
-	if(!m_impl->isSecondLevel())
+	if(!self.isSecondLevel())
 	{
-		getManager().getImplementation().getRenderingThread().flushCommandBuffer(CommandBufferPtr(this), fence);
+		static_cast<GrManagerImpl&>(getManager())
+			.getRenderingThread()
+			.flushCommandBuffer(CommandBufferPtr(this), fence);
 	}
 }
 
 void CommandBuffer::finish()
 {
-	if(!m_impl->isSecondLevel())
+	ANKI_GL_SELF(CommandBufferImpl);
+
+	if(!self.isSecondLevel())
 	{
-		ANKI_ASSERT(!m_impl->m_state.insideRenderPass());
+		ANKI_ASSERT(!self.m_state.insideRenderPass());
 	}
 
-	getManager().getImplementation().getRenderingThread().finishCommandBuffer(CommandBufferPtr(this));
+	static_cast<GrManagerImpl&>(getManager()).getRenderingThread().finishCommandBuffer(CommandBufferPtr(this));
 }
 
 void CommandBuffer::bindVertexBuffer(
@@ -102,7 +91,7 @@ void CommandBuffer::bindVertexBuffer(
 
 		Error operator()(GlState& state)
 		{
-			glBindVertexBuffer(m_binding, m_buff->m_impl->getGlName(), m_offset, m_stride);
+			glBindVertexBuffer(m_binding, static_cast<const BufferImpl&>(*m_buff).getGlName(), m_offset, m_stride);
 			glVertexBindingDivisor(m_binding, (m_instanced) ? 1 : 0);
 			return Error::NONE;
 		}
@@ -110,10 +99,11 @@ void CommandBuffer::bindVertexBuffer(
 
 	ANKI_ASSERT(buff);
 	ANKI_ASSERT(stride > 0);
+	ANKI_GL_SELF(CommandBufferImpl);
 
-	if(m_impl->m_state.bindVertexBuffer(binding, buff, offset, stride, stepRate))
+	if(self.m_state.bindVertexBuffer(binding, buff, offset, stride, stepRate))
 	{
-		m_impl->pushBackNewCommand<Cmd>(binding, buff, offset, stride, stepRate == VertexStepRate::INSTANCE);
+		self.pushBackNewCommand<Cmd>(binding, buff, offset, stride, stepRate == VertexStepRate::INSTANCE);
 	}
 }
 
@@ -147,7 +137,9 @@ void CommandBuffer::setVertexAttribute(U32 location, U32 buffBinding, const Pixe
 		}
 	};
 
-	if(m_impl->m_state.setVertexAttribute(location, buffBinding, fmt, relativeOffset))
+	ANKI_GL_SELF(CommandBufferImpl);
+
+	if(self.m_state.setVertexAttribute(location, buffBinding, fmt, relativeOffset))
 	{
 		U compCount;
 		GLenum type;
@@ -155,7 +147,7 @@ void CommandBuffer::setVertexAttribute(U32 location, U32 buffBinding, const Pixe
 
 		convertVertexFormat(fmt, compCount, type, normalized);
 
-		m_impl->pushBackNewCommand<Cmd>(location, buffBinding, compCount, type, normalized, relativeOffset);
+		self.pushBackNewCommand<Cmd>(location, buffBinding, compCount, type, normalized, relativeOffset);
 	}
 }
 
@@ -173,16 +165,17 @@ void CommandBuffer::bindIndexBuffer(BufferPtr buff, PtrSize offset, IndexType ty
 
 		Error operator()(GlState& state)
 		{
-			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buff->m_impl->getGlName());
+			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, static_cast<const BufferImpl&>(*m_buff).getGlName());
 			return Error::NONE;
 		}
 	};
 
 	ANKI_ASSERT(buff);
+	ANKI_GL_SELF(CommandBufferImpl);
 
-	if(m_impl->m_state.bindIndexBuffer(buff, offset, type))
+	if(self.m_state.bindIndexBuffer(buff, offset, type))
 	{
-		m_impl->pushBackNewCommand<Cmd>(buff);
+		self.pushBackNewCommand<Cmd>(buff);
 	}
 }
 
@@ -213,9 +206,10 @@ void CommandBuffer::setPrimitiveRestart(Bool enable)
 		}
 	};
 
-	if(m_impl->m_state.setPrimitiveRestart(enable))
+	ANKI_GL_SELF(CommandBufferImpl);
+	if(self.m_state.setPrimitiveRestart(enable))
 	{
-		m_impl->pushBackNewCommand<Cmd>(enable);
+		self.pushBackNewCommand<Cmd>(enable);
 	}
 }
 
@@ -238,9 +232,10 @@ void CommandBuffer::setViewport(U32 minx, U32 miny, U32 width, U32 height)
 		}
 	};
 
-	if(m_impl->m_state.setViewport(minx, miny, width, height))
+	ANKI_GL_SELF(CommandBufferImpl);
+	if(self.m_state.setViewport(minx, miny, width, height))
 	{
-		m_impl->pushBackNewCommand<ViewportCommand>(minx, miny, width, height);
+		self.pushBackNewCommand<ViewportCommand>(minx, miny, width, height);
 	}
 }
 
@@ -277,9 +272,10 @@ void CommandBuffer::setScissor(U32 minx, U32 miny, U32 width, U32 height)
 	const GLsizei iminx = minx;
 	const GLsizei iminy = miny;
 
-	if(m_impl->m_state.setScissor(iminx, iminy, iwidth, iheight))
+	ANKI_GL_SELF(CommandBufferImpl);
+	if(self.m_state.setScissor(iminx, iminy, iwidth, iheight))
 	{
-		m_impl->pushBackNewCommand<ScissorCommand>(iminx, iminy, iwidth, iheight);
+		self.pushBackNewCommand<ScissorCommand>(iminx, iminy, iwidth, iheight);
 	}
 }
 
@@ -302,9 +298,10 @@ void CommandBuffer::setFillMode(FillMode mode)
 		}
 	};
 
-	if(m_impl->m_state.setFillMode(mode))
+	ANKI_GL_SELF(CommandBufferImpl);
+	if(self.m_state.setFillMode(mode))
 	{
-		m_impl->pushBackNewCommand<Cmd>(convertFillMode(mode));
+		self.pushBackNewCommand<Cmd>(convertFillMode(mode));
 	}
 }
 
@@ -327,9 +324,10 @@ void CommandBuffer::setCullMode(FaceSelectionBit mode)
 		}
 	};
 
-	if(m_impl->m_state.setCullMode(mode))
+	ANKI_GL_SELF(CommandBufferImpl);
+	if(self.m_state.setCullMode(mode))
 	{
-		m_impl->pushBackNewCommand<Cmd>(convertFaceMode(mode));
+		self.pushBackNewCommand<Cmd>(convertFaceMode(mode));
 	}
 }
 
@@ -363,9 +361,10 @@ void CommandBuffer::setPolygonOffset(F32 factor, F32 units)
 		}
 	};
 
-	if(m_impl->m_state.setPolygonOffset(factor, units))
+	ANKI_GL_SELF(CommandBufferImpl);
+	if(self.m_state.setPolygonOffset(factor, units))
 	{
-		m_impl->pushBackNewCommand<Cmd>(factor, units);
+		self.pushBackNewCommand<Cmd>(factor, units);
 	}
 }
 
@@ -397,9 +396,10 @@ void CommandBuffer::setStencilOperations(FaceSelectionBit face,
 		}
 	};
 
-	if(m_impl->m_state.setStencilOperations(face, stencilFail, stencilPassDepthFail, stencilPassDepthPass))
+	ANKI_GL_SELF(CommandBufferImpl);
+	if(self.m_state.setStencilOperations(face, stencilFail, stencilPassDepthFail, stencilPassDepthPass))
 	{
-		m_impl->pushBackNewCommand<Cmd>(convertFaceMode(face),
+		self.pushBackNewCommand<Cmd>(convertFaceMode(face),
 			convertStencilOperation(stencilFail),
 			convertStencilOperation(stencilPassDepthFail),
 			convertStencilOperation(stencilPassDepthPass));
@@ -408,12 +408,14 @@ void CommandBuffer::setStencilOperations(FaceSelectionBit face,
 
 void CommandBuffer::setStencilCompareOperation(FaceSelectionBit face, CompareOperation comp)
 {
-	m_impl->m_state.setStencilCompareOperation(face, comp);
+	ANKI_GL_SELF(CommandBufferImpl);
+	self.m_state.setStencilCompareOperation(face, comp);
 }
 
 void CommandBuffer::setStencilCompareMask(FaceSelectionBit face, U32 mask)
 {
-	m_impl->m_state.setStencilCompareMask(face, mask);
+	ANKI_GL_SELF(CommandBufferImpl);
+	self.m_state.setStencilCompareMask(face, mask);
 }
 
 void CommandBuffer::setStencilWriteMask(FaceSelectionBit face, U32 mask)
@@ -452,15 +454,17 @@ void CommandBuffer::setStencilWriteMask(FaceSelectionBit face, U32 mask)
 		}
 	};
 
-	if(m_impl->m_state.setStencilWriteMask(face, mask))
+	ANKI_GL_SELF(CommandBufferImpl);
+	if(self.m_state.setStencilWriteMask(face, mask))
 	{
-		m_impl->pushBackNewCommand<Cmd>(convertFaceMode(face), mask);
+		self.pushBackNewCommand<Cmd>(convertFaceMode(face), mask);
 	}
 }
 
 void CommandBuffer::setStencilReference(FaceSelectionBit face, U32 ref)
 {
-	m_impl->m_state.setStencilReference(face, ref);
+	ANKI_GL_SELF(CommandBufferImpl);
+	self.m_state.setStencilReference(face, ref);
 }
 
 void CommandBuffer::setDepthWrite(Bool enable)
@@ -483,9 +487,10 @@ void CommandBuffer::setDepthWrite(Bool enable)
 		}
 	};
 
-	if(m_impl->m_state.setDepthWrite(enable))
+	ANKI_GL_SELF(CommandBufferImpl);
+	if(self.m_state.setDepthWrite(enable))
 	{
-		m_impl->pushBackNewCommand<Cmd>(enable);
+		self.pushBackNewCommand<Cmd>(enable);
 	}
 }
 
@@ -508,9 +513,10 @@ void CommandBuffer::setDepthCompareOperation(CompareOperation op)
 		}
 	};
 
-	if(m_impl->m_state.setDepthCompareOperation(op))
+	ANKI_GL_SELF(CommandBufferImpl);
+	if(self.m_state.setDepthCompareOperation(op))
 	{
-		m_impl->pushBackNewCommand<Cmd>(convertCompareOperation(op));
+		self.pushBackNewCommand<Cmd>(convertCompareOperation(op));
 	}
 }
 
@@ -548,9 +554,10 @@ void CommandBuffer::setColorChannelWriteMask(U32 attachment, ColorBit mask)
 		}
 	};
 
-	if(m_impl->m_state.setColorChannelWriteMask(attachment, mask))
+	ANKI_GL_SELF(CommandBufferImpl);
+	if(self.m_state.setColorChannelWriteMask(attachment, mask))
 	{
-		m_impl->pushBackNewCommand<Cmd>(attachment, mask);
+		self.pushBackNewCommand<Cmd>(attachment, mask);
 	}
 }
 
@@ -582,9 +589,10 @@ void CommandBuffer::setBlendFactors(
 		}
 	};
 
-	if(m_impl->m_state.setBlendFactors(attachment, srcRgb, dstRgb, srcA, dstA))
+	ANKI_GL_SELF(CommandBufferImpl);
+	if(self.m_state.setBlendFactors(attachment, srcRgb, dstRgb, srcA, dstA))
 	{
-		m_impl->pushBackNewCommand<Cmd>(attachment,
+		self.pushBackNewCommand<Cmd>(attachment,
 			convertBlendFactor(srcRgb),
 			convertBlendFactor(dstRgb),
 			convertBlendFactor(srcA),
@@ -615,9 +623,10 @@ void CommandBuffer::setBlendOperation(U32 attachment, BlendOperation funcRgb, Bl
 		}
 	};
 
-	if(m_impl->m_state.setBlendOperation(attachment, funcRgb, funcA))
+	ANKI_GL_SELF(CommandBufferImpl);
+	if(self.m_state.setBlendOperation(attachment, funcRgb, funcA))
 	{
-		m_impl->pushBackNewCommand<Cmd>(attachment, convertBlendOperation(funcRgb), convertBlendOperation(funcA));
+		self.pushBackNewCommand<Cmd>(attachment, convertBlendOperation(funcRgb), convertBlendOperation(funcA));
 	}
 }
 
@@ -642,7 +651,7 @@ void CommandBuffer::bindTexture(
 		{
 			if(m_tex)
 			{
-				glBindTextureUnit(m_unit, m_tex->m_impl->getGlName());
+				glBindTextureUnit(m_unit, static_cast<const TextureImpl&>(*m_tex).getGlName());
 			}
 
 			if(m_samplerChanged)
@@ -653,11 +662,12 @@ void CommandBuffer::bindTexture(
 		}
 	};
 
+	ANKI_GL_SELF(CommandBufferImpl);
 	Bool texChanged, samplerChanged;
-	if(m_impl->m_state.bindTexture(set, binding, tex, aspect, texChanged, samplerChanged))
+	if(self.m_state.bindTexture(set, binding, tex, aspect, texChanged, samplerChanged))
 	{
 		U unit = binding + MAX_TEXTURE_BINDINGS * set;
-		m_impl->pushBackNewCommand<Cmd>(unit, (texChanged) ? tex : TexturePtr(), samplerChanged);
+		self.pushBackNewCommand<Cmd>(unit, (texChanged) ? tex : TexturePtr(), samplerChanged);
 	}
 }
 
@@ -680,16 +690,17 @@ void CommandBuffer::bindTextureAndSampler(
 
 		Error operator()(GlState&)
 		{
-			glBindTextureUnit(m_unit, m_tex->m_impl->getGlName());
-			glBindSampler(m_unit, m_sampler->m_impl->getGlName());
+			glBindTextureUnit(m_unit, static_cast<const TextureImpl&>(*m_tex).getGlName());
+			glBindSampler(m_unit, static_cast<const SamplerImpl&>(*m_sampler).getGlName());
 			return Error::NONE;
 		}
 	};
 
-	if(m_impl->m_state.bindTextureAndSampler(set, binding, tex, sampler, aspect))
+	ANKI_GL_SELF(CommandBufferImpl);
+	if(self.m_state.bindTextureAndSampler(set, binding, tex, sampler, aspect))
 	{
 		U unit = binding + MAX_TEXTURE_BINDINGS * set;
-		m_impl->pushBackNewCommand<Cmd>(unit, tex, sampler);
+		self.pushBackNewCommand<Cmd>(unit, tex, sampler);
 	}
 }
 
@@ -713,18 +724,19 @@ void CommandBuffer::bindUniformBuffer(U32 set, U32 binding, BufferPtr buff, PtrS
 
 		Error operator()(GlState&)
 		{
-			m_buff->m_impl->bind(GL_UNIFORM_BUFFER, m_binding, m_offset, m_range);
+			static_cast<const BufferImpl&>(*m_buff).bind(GL_UNIFORM_BUFFER, m_binding, m_offset, m_range);
 			return Error::NONE;
 		}
 	};
 
 	ANKI_ASSERT(buff);
 	ANKI_ASSERT(range > 0);
+	ANKI_GL_SELF(CommandBufferImpl);
 
-	if(m_impl->m_state.bindUniformBuffer(set, binding, buff, offset, range))
+	if(self.m_state.bindUniformBuffer(set, binding, buff, offset, range))
 	{
 		binding = binding + MAX_UNIFORM_BUFFER_BINDINGS * set;
-		m_impl->pushBackNewCommand<Cmd>(binding, buff, offset, range);
+		self.pushBackNewCommand<Cmd>(binding, buff, offset, range);
 	}
 }
 
@@ -748,18 +760,19 @@ void CommandBuffer::bindStorageBuffer(U32 set, U32 binding, BufferPtr buff, PtrS
 
 		Error operator()(GlState&)
 		{
-			m_buff->m_impl->bind(GL_SHADER_STORAGE_BUFFER, m_binding, m_offset, m_range);
+			static_cast<const BufferImpl&>(*m_buff).bind(GL_SHADER_STORAGE_BUFFER, m_binding, m_offset, m_range);
 			return Error::NONE;
 		}
 	};
 
 	ANKI_ASSERT(buff);
 	ANKI_ASSERT(range > 0);
+	ANKI_GL_SELF(CommandBufferImpl);
 
-	if(m_impl->m_state.bindStorageBuffer(set, binding, buff, offset, range))
+	if(self.m_state.bindStorageBuffer(set, binding, buff, offset, range))
 	{
 		binding = binding + MAX_STORAGE_BUFFER_BINDINGS * set;
-		m_impl->pushBackNewCommand<Cmd>(binding, buff, offset, range);
+		self.pushBackNewCommand<Cmd>(binding, buff, offset, range);
 	}
 }
 
@@ -782,22 +795,23 @@ void CommandBuffer::bindImage(U32 set, U32 binding, TexturePtr img, U32 level)
 		Error operator()(GlState&)
 		{
 			glBindImageTexture(m_unit,
-				m_img->m_impl->getGlName(),
+				static_cast<const TextureImpl&>(*m_img).getGlName(),
 				m_level,
 				GL_TRUE,
 				0,
 				GL_READ_WRITE,
-				m_img->m_impl->m_internalFormat);
+				static_cast<const TextureImpl&>(*m_img).m_internalFormat);
 			return Error::NONE;
 		}
 	};
 
 	ANKI_ASSERT(img);
+	ANKI_GL_SELF(CommandBufferImpl);
 
-	if(m_impl->m_state.bindImage(set, binding, img, level))
+	if(self.m_state.bindImage(set, binding, img, level))
 	{
 		binding = binding + set * MAX_IMAGE_BINDINGS;
-		m_impl->pushBackNewCommand<Cmd>(binding, img, level);
+		self.pushBackNewCommand<Cmd>(binding, img, level);
 	}
 }
 
@@ -826,10 +840,10 @@ void CommandBuffer::bindTextureBuffer(
 
 		Error operator()(GlState& state)
 		{
-			ANKI_ASSERT(m_offset + m_range <= m_buff->m_impl->m_size);
+			ANKI_ASSERT(m_offset + m_range <= m_buff->getSize());
 
 			const GLuint tex = state.m_texBuffTextures[m_set][m_binding];
-			glTextureBufferRange(tex, m_fmt, m_buff->m_impl->getGlName(), m_offset, m_range);
+			glTextureBufferRange(tex, m_fmt, static_cast<const BufferImpl&>(*m_buff).getGlName(), m_offset, m_range);
 
 			return Error::NONE;
 		}
@@ -846,7 +860,8 @@ void CommandBuffer::bindTextureBuffer(
 	(void)type;
 	(void)dsAspect;
 
-	m_impl->pushBackNewCommand<Cmd>(set, binding, buff, offset, range, internalFormat);
+	ANKI_GL_SELF(CommandBufferImpl);
+	self.pushBackNewCommand<Cmd>(set, binding, buff, offset, range, internalFormat);
 }
 
 void CommandBuffer::bindShaderProgram(ShaderProgramPtr prog)
@@ -863,16 +878,17 @@ void CommandBuffer::bindShaderProgram(ShaderProgramPtr prog)
 
 		Error operator()(GlState&)
 		{
-			glUseProgram(m_prog->m_impl->getGlName());
+			glUseProgram(static_cast<const ShaderProgramImpl&>(*m_prog).getGlName());
 			return Error::NONE;
 		}
 	};
 
 	ANKI_ASSERT(prog);
+	ANKI_GL_SELF(CommandBufferImpl);
 
-	if(m_impl->m_state.bindShaderProgram(prog))
+	if(self.m_state.bindShaderProgram(prog))
 	{
-		m_impl->pushBackNewCommand<Cmd>(prog);
+		self.pushBackNewCommand<Cmd>(prog);
 	}
 	else
 	{
@@ -902,14 +918,16 @@ void CommandBuffer::beginRenderPass(FramebufferPtr fb,
 
 		Error operator()(GlState& state)
 		{
-			m_fb->m_impl->bind(state, m_renderArea[0], m_renderArea[1], m_renderArea[2], m_renderArea[3]);
+			static_cast<const FramebufferImpl&>(*m_fb).bind(
+				state, m_renderArea[0], m_renderArea[1], m_renderArea[2], m_renderArea[3]);
 			return Error::NONE;
 		}
 	};
 
-	if(m_impl->m_state.beginRenderPass(fb))
+	ANKI_GL_SELF(CommandBufferImpl);
+	if(self.m_state.beginRenderPass(fb))
 	{
-		m_impl->pushBackNewCommand<BindFramebufferCommand>(fb, minx, miny, width, height);
+		self.pushBackNewCommand<BindFramebufferCommand>(fb, minx, miny, width, height);
 	}
 }
 
@@ -918,9 +936,9 @@ void CommandBuffer::endRenderPass()
 	class Command final : public GlCommand
 	{
 	public:
-		FramebufferImpl* m_fb;
+		const FramebufferImpl* m_fb;
 
-		Command(FramebufferImpl* fb)
+		Command(const FramebufferImpl* fb)
 			: m_fb(fb)
 		{
 			ANKI_ASSERT(fb);
@@ -933,8 +951,9 @@ void CommandBuffer::endRenderPass()
 		}
 	};
 
-	m_impl->pushBackNewCommand<Command>(m_impl->m_state.m_fb);
-	m_impl->m_state.endRenderPass();
+	ANKI_GL_SELF(CommandBufferImpl);
+	self.pushBackNewCommand<Command>(self.m_state.m_fb);
+	self.m_state.endRenderPass();
 }
 
 void CommandBuffer::drawElements(
@@ -970,24 +989,26 @@ void CommandBuffer::drawElements(
 		}
 	};
 
-	m_impl->m_state.checkIndexedDracall();
-	m_impl->flushDrawcall(*this);
+	ANKI_GL_SELF(CommandBufferImpl);
+
+	self.m_state.checkIndexedDracall();
+	self.flushDrawcall(*this);
 
 	U idxBytes;
-	if(m_impl->m_state.m_idx.m_indexType == GL_UNSIGNED_SHORT)
+	if(self.m_state.m_idx.m_indexType == GL_UNSIGNED_SHORT)
 	{
 		idxBytes = sizeof(U16);
 	}
 	else
 	{
-		ANKI_ASSERT(m_impl->m_state.m_idx.m_indexType == GL_UNSIGNED_INT);
+		ANKI_ASSERT(self.m_state.m_idx.m_indexType == GL_UNSIGNED_INT);
 		idxBytes = sizeof(U32);
 	}
 
-	firstIndex = firstIndex * idxBytes + m_impl->m_state.m_idx.m_offset;
+	firstIndex = firstIndex * idxBytes + self.m_state.m_idx.m_offset;
 
 	DrawElementsIndirectInfo info(count, instanceCount, firstIndex, baseVertex, baseInstance);
-	m_impl->pushBackNewCommand<Cmd>(convertPrimitiveTopology(topology), m_impl->m_state.m_idx.m_indexType, info);
+	self.pushBackNewCommand<Cmd>(convertPrimitiveTopology(topology), self.m_state.m_idx.m_indexType, info);
 }
 
 void CommandBuffer::drawArrays(PrimitiveTopology topology, U32 count, U32 instanceCount, U32 first, U32 baseInstance)
@@ -1015,11 +1036,13 @@ void CommandBuffer::drawArrays(PrimitiveTopology topology, U32 count, U32 instan
 		}
 	};
 
-	m_impl->m_state.checkNonIndexedDrawcall();
-	m_impl->flushDrawcall(*this);
+	ANKI_GL_SELF(CommandBufferImpl);
+
+	self.m_state.checkNonIndexedDrawcall();
+	self.flushDrawcall(*this);
 
 	DrawArraysIndirectInfo info(count, instanceCount, first, baseInstance);
-	m_impl->pushBackNewCommand<DrawArraysCommand>(convertPrimitiveTopology(topology), info);
+	self.pushBackNewCommand<DrawArraysCommand>(convertPrimitiveTopology(topology), info);
 }
 
 void CommandBuffer::drawElementsIndirect(
@@ -1047,9 +1070,9 @@ void CommandBuffer::drawElementsIndirect(
 
 		Error operator()(GlState&)
 		{
-			const BufferImpl& buff = *m_buff->m_impl;
+			const BufferImpl& buff = static_cast<const BufferImpl&>(*m_buff);
 
-			ANKI_ASSERT(m_offset + sizeof(DrawElementsIndirectInfo) * m_drawCount <= buff.m_size);
+			ANKI_ASSERT(m_offset + sizeof(DrawElementsIndirectInfo) * m_drawCount <= buff.getSize());
 
 			glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buff.getGlName());
 
@@ -1061,10 +1084,12 @@ void CommandBuffer::drawElementsIndirect(
 		}
 	};
 
-	m_impl->m_state.checkIndexedDracall();
-	m_impl->flushDrawcall(*this);
-	m_impl->pushBackNewCommand<DrawElementsIndirectCommand>(
-		convertPrimitiveTopology(topology), m_impl->m_state.m_idx.m_indexType, drawCount, offset, indirectBuff);
+	ANKI_GL_SELF(CommandBufferImpl);
+
+	self.m_state.checkIndexedDracall();
+	self.flushDrawcall(*this);
+	self.pushBackNewCommand<DrawElementsIndirectCommand>(
+		convertPrimitiveTopology(topology), self.m_state.m_idx.m_indexType, drawCount, offset, indirectBuff);
 }
 
 void CommandBuffer::drawArraysIndirect(
@@ -1090,9 +1115,9 @@ void CommandBuffer::drawArraysIndirect(
 
 		Error operator()(GlState& state)
 		{
-			const BufferImpl& buff = *m_buff->m_impl;
+			const BufferImpl& buff = static_cast<const BufferImpl&>(*m_buff);
 
-			ANKI_ASSERT(m_offset + sizeof(DrawArraysIndirectInfo) * m_drawCount <= buff.m_size);
+			ANKI_ASSERT(m_offset + sizeof(DrawArraysIndirectInfo) * m_drawCount <= buff.getSize());
 
 			glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buff.getGlName());
 
@@ -1104,9 +1129,10 @@ void CommandBuffer::drawArraysIndirect(
 		}
 	};
 
-	m_impl->m_state.checkNonIndexedDrawcall();
-	m_impl->flushDrawcall(*this);
-	m_impl->pushBackNewCommand<DrawArraysIndirectCommand>(
+	ANKI_GL_SELF(CommandBufferImpl);
+	self.m_state.checkNonIndexedDrawcall();
+	self.flushDrawcall(*this);
+	self.pushBackNewCommand<DrawArraysIndirectCommand>(
 		convertPrimitiveTopology(topology), drawCount, offset, indirectBuff);
 }
 
@@ -1129,9 +1155,11 @@ void CommandBuffer::dispatchCompute(U32 groupCountX, U32 groupCountY, U32 groupC
 		}
 	};
 
-	ANKI_ASSERT(!!(m_impl->m_flags & CommandBufferFlag::COMPUTE_WORK));
-	m_impl->m_state.checkDispatch();
-	m_impl->pushBackNewCommand<DispatchCommand>(groupCountX, groupCountY, groupCountZ);
+	ANKI_GL_SELF(CommandBufferImpl);
+
+	ANKI_ASSERT(!!(self.m_flags & CommandBufferFlag::COMPUTE_WORK));
+	self.m_state.checkDispatch();
+	self.pushBackNewCommand<DispatchCommand>(groupCountX, groupCountY, groupCountZ);
 }
 
 void CommandBuffer::resetOcclusionQuery(OcclusionQueryPtr query)
@@ -1153,12 +1181,13 @@ void CommandBuffer::beginOcclusionQuery(OcclusionQueryPtr query)
 
 		Error operator()(GlState&)
 		{
-			m_handle->m_impl->begin();
+			static_cast<OcclusionQueryImpl&>(*m_handle).begin();
 			return Error::NONE;
 		}
 	};
 
-	m_impl->pushBackNewCommand<OqBeginCommand>(query);
+	ANKI_GL_SELF(CommandBufferImpl);
+	self.pushBackNewCommand<OqBeginCommand>(query);
 }
 
 void CommandBuffer::endOcclusionQuery(OcclusionQueryPtr query)
@@ -1175,12 +1204,13 @@ void CommandBuffer::endOcclusionQuery(OcclusionQueryPtr query)
 
 		Error operator()(GlState&)
 		{
-			m_handle->m_impl->end();
+			static_cast<OcclusionQueryImpl&>(*m_handle).end();
 			return Error::NONE;
 		}
 	};
 
-	m_impl->pushBackNewCommand<OqEndCommand>(query);
+	ANKI_GL_SELF(CommandBufferImpl);
+	self.pushBackNewCommand<OqEndCommand>(query);
 }
 
 void CommandBuffer::copyBufferToTextureSurface(
@@ -1207,7 +1237,8 @@ void CommandBuffer::copyBufferToTextureSurface(
 
 		Error operator()(GlState& state)
 		{
-			m_tex->m_impl->writeSurface(m_surf, m_buff->m_impl->getGlName(), m_offset, m_range);
+			static_cast<TextureImpl&>(*m_tex).writeSurface(
+				m_surf, static_cast<const BufferImpl&>(*m_buff).getGlName(), m_offset, m_range);
 			return Error::NONE;
 		}
 	};
@@ -1215,9 +1246,10 @@ void CommandBuffer::copyBufferToTextureSurface(
 	ANKI_ASSERT(tex);
 	ANKI_ASSERT(buff);
 	ANKI_ASSERT(range > 0);
-	ANKI_ASSERT(!m_impl->m_state.insideRenderPass());
+	ANKI_GL_SELF(CommandBufferImpl);
+	ANKI_ASSERT(!self.m_state.insideRenderPass());
 
-	m_impl->pushBackNewCommand<TexSurfUploadCommand>(buff, offset, range, tex, surf);
+	self.pushBackNewCommand<TexSurfUploadCommand>(buff, offset, range, tex, surf);
 }
 
 void CommandBuffer::copyBufferToTextureVolume(
@@ -1243,7 +1275,8 @@ void CommandBuffer::copyBufferToTextureVolume(
 
 		Error operator()(GlState& state)
 		{
-			m_tex->m_impl->writeVolume(m_vol, m_buff->m_impl->getGlName(), m_offset, m_range);
+			static_cast<const TextureImpl&>(*m_tex).writeVolume(
+				m_vol, static_cast<const BufferImpl&>(*m_buff).getGlName(), m_offset, m_range);
 			return Error::NONE;
 		}
 	};
@@ -1251,9 +1284,10 @@ void CommandBuffer::copyBufferToTextureVolume(
 	ANKI_ASSERT(tex);
 	ANKI_ASSERT(buff);
 	ANKI_ASSERT(range > 0);
-	ANKI_ASSERT(!m_impl->m_state.insideRenderPass());
+	ANKI_GL_SELF(CommandBufferImpl);
+	ANKI_ASSERT(!self.m_state.insideRenderPass());
 
-	m_impl->pushBackNewCommand<TexVolUploadCommand>(buff, offset, range, tex, vol);
+	self.pushBackNewCommand<TexVolUploadCommand>(buff, offset, range, tex, vol);
 }
 
 void CommandBuffer::copyBufferToBuffer(
@@ -1279,7 +1313,8 @@ void CommandBuffer::copyBufferToBuffer(
 
 		Error operator()(GlState& state)
 		{
-			m_dst->m_impl->write(m_src->m_impl->getGlName(), m_srcOffset, m_dstOffset, m_range);
+			static_cast<BufferImpl&>(*m_dst).write(
+				static_cast<const BufferImpl&>(*m_src).getGlName(), m_srcOffset, m_dstOffset, m_range);
 			return Error::NONE;
 		}
 	};
@@ -1287,9 +1322,10 @@ void CommandBuffer::copyBufferToBuffer(
 	ANKI_ASSERT(src);
 	ANKI_ASSERT(dst);
 	ANKI_ASSERT(range > 0);
-	ANKI_ASSERT(!m_impl->m_state.insideRenderPass());
+	ANKI_GL_SELF(CommandBufferImpl);
+	ANKI_ASSERT(!self.m_state.insideRenderPass());
 
-	m_impl->pushBackNewCommand<Cmd>(src, srcOffset, dst, dstOffset, range);
+	self.pushBackNewCommand<Cmd>(src, srcOffset, dst, dstOffset, range);
 }
 
 void CommandBuffer::generateMipmaps2d(TexturePtr tex, U face, U layer)
@@ -1310,13 +1346,14 @@ void CommandBuffer::generateMipmaps2d(TexturePtr tex, U face, U layer)
 
 		Error operator()(GlState&)
 		{
-			m_tex->m_impl->generateMipmaps2d(m_face, m_layer);
+			static_cast<TextureImpl&>(*m_tex).generateMipmaps2d(m_face, m_layer);
 			return Error::NONE;
 		}
 	};
 
-	ANKI_ASSERT(!m_impl->m_state.insideRenderPass());
-	m_impl->pushBackNewCommand<GenMipsCommand>(tex, face, layer);
+	ANKI_GL_SELF(CommandBufferImpl);
+	ANKI_ASSERT(!self.m_state.insideRenderPass());
+	self.pushBackNewCommand<GenMipsCommand>(tex, face, layer);
 }
 
 void CommandBuffer::generateMipmaps3d(TexturePtr tex)
@@ -1326,7 +1363,8 @@ void CommandBuffer::generateMipmaps3d(TexturePtr tex)
 
 CommandBufferInitHints CommandBuffer::computeInitHints() const
 {
-	return m_impl->computeInitHints();
+	ANKI_GL_SELF_CONST(CommandBufferImpl);
+	return self.computeInitHints();
 }
 
 void CommandBuffer::pushSecondLevelCommandBuffer(CommandBufferPtr cmdb)
@@ -1343,20 +1381,20 @@ void CommandBuffer::pushSecondLevelCommandBuffer(CommandBufferPtr cmdb)
 
 		Error operator()(GlState&)
 		{
-			ANKI_TRACE_START_EVENT(GL_2ND_LEVEL_CMD_BUFFER);
-			Error err = m_cmdb->m_impl->executeAllCommands();
-			ANKI_TRACE_STOP_EVENT(GL_2ND_LEVEL_CMD_BUFFER);
-			return err;
+			ANKI_TRACE_SCOPED_EVENT(GL_2ND_LEVEL_CMD_BUFFER);
+			return static_cast<CommandBufferImpl&>(*m_cmdb).executeAllCommands();
 		}
 	};
 
-	m_impl->m_state.m_lastSecondLevelCmdb = cmdb->m_impl.get();
-	m_impl->pushBackNewCommand<ExecCmdbCommand>(cmdb);
+	ANKI_GL_SELF(CommandBufferImpl);
+	self.m_state.m_lastSecondLevelCmdb = static_cast<CommandBufferImpl*>(cmdb.get());
+	self.pushBackNewCommand<ExecCmdbCommand>(cmdb);
 }
 
 Bool CommandBuffer::isEmpty() const
 {
-	return m_impl->isEmpty();
+	ANKI_GL_SELF_CONST(CommandBufferImpl);
+	return self.isEmpty();
 }
 
 void CommandBuffer::copyTextureSurfaceToTextureSurface(
@@ -1381,13 +1419,17 @@ void CommandBuffer::copyTextureSurfaceToTextureSurface(
 
 		Error operator()(GlState&)
 		{
-			TextureImpl::copy(*m_src->m_impl, m_srcSurf, *m_dest->m_impl, m_destSurf);
+			TextureImpl::copy(static_cast<const TextureImpl&>(*m_src),
+				m_srcSurf,
+				static_cast<const TextureImpl&>(*m_dest),
+				m_destSurf);
 			return Error::NONE;
 		}
 	};
 
-	ANKI_ASSERT(!m_impl->m_state.insideRenderPass());
-	m_impl->pushBackNewCommand<CopyTexCommand>(src, srcSurf, dest, destSurf);
+	ANKI_GL_SELF(CommandBufferImpl);
+	ANKI_ASSERT(!self.m_state.insideRenderPass());
+	self.pushBackNewCommand<CopyTexCommand>(src, srcSurf, dest, destSurf);
 }
 
 void CommandBuffer::setBufferBarrier(
@@ -1450,7 +1492,8 @@ void CommandBuffer::setBufferBarrier(
 	}
 
 	ANKI_ASSERT(d);
-	m_impl->pushBackNewCommand<SetBufferMemBarrierCommand>(d);
+	ANKI_GL_SELF(CommandBufferImpl);
+	self.pushBackNewCommand<SetBufferMemBarrierCommand>(d);
 }
 
 void CommandBuffer::setTextureSurfaceBarrier(
@@ -1487,13 +1530,14 @@ void CommandBuffer::clearTextureSurface(
 
 		Error operator()(GlState&)
 		{
-			m_tex->m_impl->clear(m_surf, m_val, m_aspect);
+			static_cast<TextureImpl&>(*m_tex).clear(m_surf, m_val, m_aspect);
 			return Error::NONE;
 		}
 	};
 
-	ANKI_ASSERT(!m_impl->m_state.insideRenderPass());
-	m_impl->pushBackNewCommand<ClearTextCommand>(tex, surf, clearValue, aspect);
+	ANKI_GL_SELF(CommandBufferImpl);
+	ANKI_ASSERT(!self.m_state.insideRenderPass());
+	self.pushBackNewCommand<ClearTextCommand>(tex, surf, clearValue, aspect);
 }
 
 void CommandBuffer::fillBuffer(BufferPtr buff, PtrSize offset, PtrSize size, U32 value)
@@ -1516,13 +1560,14 @@ void CommandBuffer::fillBuffer(BufferPtr buff, PtrSize offset, PtrSize size, U32
 
 		Error operator()(GlState&)
 		{
-			m_buff->m_impl->fill(m_offset, m_size, m_value);
+			static_cast<BufferImpl&>(*m_buff).fill(m_offset, m_size, m_value);
 			return Error::NONE;
 		}
 	};
 
-	ANKI_ASSERT(!m_impl->m_state.insideRenderPass());
-	m_impl->pushBackNewCommand<FillBufferCommand>(buff, offset, size, value);
+	ANKI_GL_SELF(CommandBufferImpl);
+	ANKI_ASSERT(!self.m_state.insideRenderPass());
+	self.pushBackNewCommand<FillBufferCommand>(buff, offset, size, value);
 }
 
 void CommandBuffer::writeOcclusionQueryResultToBuffer(OcclusionQueryPtr query, PtrSize offset, BufferPtr buff)
@@ -1544,19 +1589,22 @@ void CommandBuffer::writeOcclusionQueryResultToBuffer(OcclusionQueryPtr query, P
 
 		Error operator()(GlState&)
 		{
-			const BufferImpl& buff = *m_buff->m_impl;
-			ANKI_ASSERT(m_offset + 4 <= buff.m_size);
+			const BufferImpl& buff = static_cast<const BufferImpl&>(*m_buff);
+			ANKI_ASSERT(m_offset + 4 <= buff.getSize());
 
 			glBindBuffer(GL_QUERY_BUFFER, buff.getGlName());
-			glGetQueryObjectuiv(m_query->m_impl->getGlName(), GL_QUERY_RESULT, numberToPtr<GLuint*>(m_offset));
+			glGetQueryObjectuiv(static_cast<const OcclusionQueryImpl&>(*m_query).getGlName(),
+				GL_QUERY_RESULT,
+				numberToPtr<GLuint*>(m_offset));
 			glBindBuffer(GL_QUERY_BUFFER, 0);
 
 			return Error::NONE;
 		}
 	};
 
-	ANKI_ASSERT(!m_impl->m_state.insideRenderPass());
-	m_impl->pushBackNewCommand<WriteOcclResultToBuff>(query, offset, buff);
+	ANKI_GL_SELF(CommandBufferImpl);
+	ANKI_ASSERT(!self.m_state.insideRenderPass());
+	self.pushBackNewCommand<WriteOcclResultToBuff>(query, offset, buff);
 }
 
 } // end namespace anki

+ 12 - 7
src/anki/gr/gl/CommandBufferImpl.cpp

@@ -23,12 +23,22 @@ namespace anki
 
 void CommandBufferImpl::init(const CommandBufferInitInfo& init)
 {
-	auto& pool = m_manager->getAllocator().getMemoryPool();
+	auto& pool = getManager().getAllocator().getMemoryPool();
 
 	m_alloc = CommandBufferAllocator<GlCommand*>(
 		pool.getAllocationCallback(), pool.getAllocationCallbackUserData(), init.m_hints.m_chunkSize, 1.0, 0, false);
 
 	m_flags = init.m_flags;
+
+#if ANKI_EXTRA_CHECKS
+	m_state.m_secondLevel = !!(init.m_flags & CommandBufferFlag::SECOND_LEVEL);
+#endif
+
+	if(!!(init.m_flags & CommandBufferFlag::SECOND_LEVEL))
+	{
+		// TODO Need to hold a ref
+		m_state.m_fb = static_cast<const FramebufferImpl*>(init.m_framebuffer.get());
+	}
 }
 
 void CommandBufferImpl::destroy()
@@ -67,7 +77,7 @@ Error CommandBufferImpl::executeAllCommands()
 #endif
 
 	Error err = Error::NONE;
-	GlState& state = m_manager->getImplementation().getState();
+	GlState& state = static_cast<GrManagerImpl&>(getManager()).getState();
 
 	GlCommand* command = m_firstCommand;
 
@@ -90,11 +100,6 @@ CommandBufferImpl::InitHints CommandBufferImpl::computeInitHints() const
 	return out;
 }
 
-GrAllocator<U8> CommandBufferImpl::getAllocator() const
-{
-	return m_manager->getAllocator();
-}
-
 void CommandBufferImpl::flushDrawcall(CommandBuffer& cmdb)
 {
 	ANKI_ASSERT(!!(m_flags & CommandBufferFlag::GRAPHICS_WORK));

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

@@ -37,12 +37,11 @@ public:
 };
 
 /// A number of GL commands organized in a chain
-class CommandBufferImpl
+class CommandBufferImpl final : public CommandBuffer
 {
 public:
 	using InitHints = CommandBufferInitHints;
 
-	GrManager* m_manager = nullptr;
 	GlCommand* m_firstCommand = nullptr;
 	GlCommand* m_lastCommand = nullptr;
 	CommandBufferAllocator<U8> m_alloc;
@@ -57,7 +56,7 @@ public:
 
 	/// Default constructor
 	CommandBufferImpl(GrManager* manager)
-		: m_manager(manager)
+		: CommandBuffer(manager)
 	{
 	}
 
@@ -75,9 +74,6 @@ public:
 		return m_alloc;
 	}
 
-	/// For the UniquePtr destructor.
-	GrAllocator<U8> getAllocator() const;
-
 	/// Compute initialization hints.
 	InitHints computeInitHints() const;
 
@@ -102,11 +98,6 @@ public:
 		m_immutable = true;
 	}
 
-	GrManager& getManager()
-	{
-		return *m_manager;
-	}
-
 	Bool isEmpty() const
 	{
 		return m_firstCommand == nullptr;

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

@@ -36,6 +36,9 @@ class RenderingThread;
 #define ANKI_GL_LOGW(...) ANKI_LOG("GL  ", WARNING, __VA_ARGS__)
 #define ANKI_GL_LOGF(...) ANKI_LOG("GL  ", FATAL, __VA_ARGS__)
 
+#define ANKI_GL_SELF(class_) class_& self = *static_cast<class_*>(this)
+#define ANKI_GL_SELF_CONST(class_) const class_& self = *static_cast<const class_*>(this)
+
 enum class GlExtensions : U16
 {
 	NONE = 0,

+ 18 - 24
src/anki/gr/gl/Fence.cpp

@@ -13,18 +13,9 @@
 namespace anki
 {
 
-Fence::Fence(GrManager* manager)
-	: GrObject(manager, CLASS_TYPE)
+Bool Fence::clientWait(Second seconds)
 {
-}
-
-Fence::~Fence()
-{
-}
-
-Bool Fence::clientWait(F64 seconds)
-{
-	if(m_impl->m_signaled.load())
+	if(static_cast<FenceImpl&>(*this).m_signaled.load())
 	{
 		return true;
 	}
@@ -33,11 +24,11 @@ Bool Fence::clientWait(F64 seconds)
 	{
 	public:
 		FencePtr m_fence;
-		F64 m_timeout;
-		F64 m_flushTime;
+		Second m_timeout;
+		Second m_flushTime;
 		Barrier* m_barrier;
 
-		CheckFenceCommand(FencePtr fence, F64 timeout, F64 flushTime, Barrier* barrier)
+		CheckFenceCommand(FencePtr fence, Second timeout, Second flushTime, Barrier* barrier)
 			: m_fence(fence)
 			, m_timeout(timeout)
 			, m_flushTime(flushTime)
@@ -49,7 +40,7 @@ Bool Fence::clientWait(F64 seconds)
 		{
 			// Since there is a delay between flushing the cmdb and returning this result try to adjust the time we
 			// wait
-			F64 timeToWait;
+			Second timeToWait;
 			if(m_timeout != 0.0)
 			{
 				timeToWait = m_timeout - (HighRezTimer::getCurrentTime() - m_flushTime);
@@ -60,11 +51,12 @@ Bool Fence::clientWait(F64 seconds)
 				timeToWait = 0.0;
 			}
 
-			GLenum out = glClientWaitSync(m_fence->m_impl->m_fence, GL_SYNC_FLUSH_COMMANDS_BIT, timeToWait * 1e+9);
+			FenceImpl& impl = static_cast<FenceImpl&>(*m_fence);
+			GLenum out = glClientWaitSync(impl.m_fence, GL_SYNC_FLUSH_COMMANDS_BIT, timeToWait * 1e+9);
 
 			if(out == GL_ALREADY_SIGNALED || out == GL_CONDITION_SATISFIED)
 			{
-				m_fence->m_impl->m_signaled.store(true);
+				impl.m_signaled.store(true);
 			}
 			else if(out == GL_TIMEOUT_EXPIRED)
 			{
@@ -85,14 +77,15 @@ Bool Fence::clientWait(F64 seconds)
 		}
 	};
 
-	CommandBufferPtr cmdb = getManager().newInstance<CommandBuffer>(CommandBufferInitInfo());
+	CommandBufferPtr cmdb = getManager().newCommandBuffer(CommandBufferInitInfo());
 
 	if(seconds == 0.0)
 	{
 		// Send a cmd that will update the fence's status in case someone calls clientWait with seconds==0.0 all the
 		// time
-		cmdb->m_impl->pushBackNewCommand<CheckFenceCommand>(FencePtr(this), seconds, 0.0, nullptr);
-		cmdb->flush();
+		static_cast<CommandBufferImpl&>(*cmdb).pushBackNewCommand<CheckFenceCommand>(
+			FencePtr(this), seconds, 0.0, nullptr);
+		static_cast<CommandBufferImpl&>(*cmdb).flush();
 
 		return false;
 	}
@@ -100,14 +93,15 @@ Bool Fence::clientWait(F64 seconds)
 	{
 		Barrier barrier(2);
 
-		F64 flushTime = HighRezTimer::getCurrentTime();
+		Second flushTime = HighRezTimer::getCurrentTime();
 
-		cmdb->m_impl->pushBackNewCommand<CheckFenceCommand>(FencePtr(this), seconds, flushTime, &barrier);
-		cmdb->flush();
+		static_cast<CommandBufferImpl&>(*cmdb).pushBackNewCommand<CheckFenceCommand>(
+			FencePtr(this), seconds, flushTime, &barrier);
+		static_cast<CommandBufferImpl&>(*cmdb).flush();
 
 		barrier.wait();
 
-		return m_impl->m_signaled.load();
+		return static_cast<FenceImpl&>(*this).m_signaled.load();
 	}
 }
 

+ 5 - 5
src/anki/gr/gl/FenceImpl.cpp

@@ -34,16 +34,16 @@ FenceImpl::~FenceImpl()
 
 	if(m_fence)
 	{
-		GrManager& manager = getManager();
-		RenderingThread& thread = manager.getImplementation().getRenderingThread();
+		GrManagerImpl& manager = static_cast<GrManagerImpl&>(getManager());
+		RenderingThread& thread = manager.getRenderingThread();
 
 		if(!thread.isServerThread())
 		{
 			CommandBufferPtr commands;
 
-			commands = manager.newInstance<CommandBuffer>(CommandBufferInitInfo());
-			commands->m_impl->pushBackNewCommand<DeleteFenceCommand>(m_fence);
-			commands->flush();
+			commands = manager.newCommandBuffer(CommandBufferInitInfo());
+			static_cast<CommandBufferImpl&>(*commands).pushBackNewCommand<DeleteFenceCommand>(m_fence);
+			static_cast<CommandBufferImpl&>(*commands).flush();
 		}
 		else
 		{

+ 3 - 2
src/anki/gr/gl/FenceImpl.h

@@ -5,6 +5,7 @@
 
 #pragma once
 
+#include <anki/gr/Fence.h>
 #include <anki/gr/gl/GlObject.h>
 
 namespace anki
@@ -14,14 +15,14 @@ namespace anki
 /// @{
 
 /// Fence implementation.
-class FenceImpl : public GlObject
+class FenceImpl final : public Fence, public GlObject
 {
 public:
 	GLsync m_fence = nullptr;
 	Atomic<Bool> m_signaled = {false};
 
 	FenceImpl(GrManager* gr)
-		: GlObject(gr)
+		: Fence(gr)
 	{
 	}
 

+ 7 - 15
src/anki/gr/gl/Framebuffer.cpp

@@ -11,16 +11,7 @@
 namespace anki
 {
 
-Framebuffer::Framebuffer(GrManager* manager)
-	: GrObject(manager, CLASS_TYPE)
-{
-}
-
-Framebuffer::~Framebuffer()
-{
-}
-
-void Framebuffer::init(const FramebufferInitInfo& init)
+Framebuffer* Framebuffer::newInstance(GrManager* manager, const FramebufferInitInfo& init)
 {
 	class CreateFramebufferCommand final : public GlCommand
 	{
@@ -36,7 +27,7 @@ void Framebuffer::init(const FramebufferInitInfo& init)
 
 		Error operator()(GlState&)
 		{
-			FramebufferImpl& impl = *m_fb->m_impl;
+			FramebufferImpl& impl = static_cast<FramebufferImpl&>(*m_fb);
 			Error err = impl.init(m_init);
 
 			GlObject::State oldState =
@@ -48,12 +39,13 @@ void Framebuffer::init(const FramebufferInitInfo& init)
 		}
 	};
 
-	m_impl.reset(getAllocator().newInstance<FramebufferImpl>(&getManager()));
+	FramebufferImpl* impl = manager->getAllocator().newInstance<FramebufferImpl>(manager);
 
-	CommandBufferPtr cmdb = getManager().newInstance<CommandBuffer>(CommandBufferInitInfo());
+	CommandBufferPtr cmdb = manager->newCommandBuffer(CommandBufferInitInfo());
+	static_cast<CommandBufferImpl&>(*cmdb).pushBackNewCommand<CreateFramebufferCommand>(impl, init);
+	static_cast<CommandBufferImpl&>(*cmdb).flush();
 
-	cmdb->m_impl->pushBackNewCommand<CreateFramebufferCommand>(this, init);
-	cmdb->flush();
+	return impl;
 }
 
 } // end namespace anki

+ 16 - 16
src/anki/gr/gl/FramebufferImpl.cpp

@@ -40,7 +40,7 @@ Error FramebufferImpl::init(const FramebufferInitInfo& init)
 		const FramebufferAttachmentInfo& att = m_in.m_colorAttachments[i];
 		const GLenum binding = GL_COLOR_ATTACHMENT0 + i;
 
-		attachTextureInternal(binding, *att.m_texture->m_impl, att);
+		attachTextureInternal(binding, static_cast<const TextureImpl&>(*att.m_texture), att);
 
 		m_drawBuffers[i] = binding;
 
@@ -51,13 +51,13 @@ Error FramebufferImpl::init(const FramebufferInitInfo& init)
 
 		if(m_fbSize[0] == 0)
 		{
-			m_fbSize[0] = att.m_texture->m_impl->m_width;
-			m_fbSize[1] = att.m_texture->m_impl->m_height;
+			m_fbSize[0] = att.m_texture->getWidth();
+			m_fbSize[1] = att.m_texture->getHeight();
 		}
 		else
 		{
-			ANKI_ASSERT(m_fbSize[0] == att.m_texture->m_impl->m_width);
-			ANKI_ASSERT(m_fbSize[1] == att.m_texture->m_impl->m_height);
+			ANKI_ASSERT(m_fbSize[0] == att.m_texture->getWidth());
+			ANKI_ASSERT(m_fbSize[1] == att.m_texture->getHeight());
 		}
 	}
 
@@ -65,22 +65,22 @@ Error FramebufferImpl::init(const FramebufferInitInfo& init)
 	if(m_in.m_depthStencilAttachment.m_texture.isCreated())
 	{
 		const FramebufferAttachmentInfo& att = m_in.m_depthStencilAttachment;
-		const TextureImpl& tex = *att.m_texture->m_impl;
+		const TextureImpl& tex = static_cast<const TextureImpl&>(*att.m_texture);
 
 		GLenum binding;
-		if(tex.m_format == GL_DEPTH_COMPONENT)
+		if(tex.m_glFormat == GL_DEPTH_COMPONENT)
 		{
 			binding = GL_DEPTH_ATTACHMENT;
 			m_dsAspect = DepthStencilAspectBit::DEPTH;
 		}
-		else if(tex.m_format == GL_STENCIL_INDEX)
+		else if(tex.m_glFormat == GL_STENCIL_INDEX)
 		{
 			binding = GL_STENCIL_ATTACHMENT;
 			m_dsAspect = DepthStencilAspectBit::STENCIL;
 		}
 		else
 		{
-			ANKI_ASSERT(tex.m_format == GL_DEPTH_STENCIL);
+			ANKI_ASSERT(tex.m_glFormat == GL_DEPTH_STENCIL);
 
 			if(att.m_aspect == DepthStencilAspectBit::DEPTH)
 			{
@@ -112,13 +112,13 @@ Error FramebufferImpl::init(const FramebufferInitInfo& init)
 
 		if(m_fbSize[0] == 0)
 		{
-			m_fbSize[0] = att.m_texture->m_impl->m_width;
-			m_fbSize[1] = att.m_texture->m_impl->m_height;
+			m_fbSize[0] = att.m_texture->getWidth();
+			m_fbSize[1] = att.m_texture->getHeight();
 		}
 		else
 		{
-			ANKI_ASSERT(m_fbSize[0] == att.m_texture->m_impl->m_width);
-			ANKI_ASSERT(m_fbSize[1] == att.m_texture->m_impl->m_height);
+			ANKI_ASSERT(m_fbSize[0] == att.m_texture->getWidth());
+			ANKI_ASSERT(m_fbSize[1] == att.m_texture->getHeight());
 		}
 	}
 
@@ -174,11 +174,11 @@ void FramebufferImpl::attachTextureInternal(
 	}
 }
 
-void FramebufferImpl::bind(const GlState& state, U32 minx, U32 miny, U32 width, U32 height)
+void FramebufferImpl::bind(const GlState& state, U32 minx, U32 miny, U32 width, U32 height) const
 {
 	ANKI_ASSERT(width > 0 && height > 0);
 
-	if(m_in.getName() && getManager().getImplementation().debugMarkersEnabled())
+	if(m_in.getName() && static_cast<const GrManagerImpl&>(getManager()).debugMarkersEnabled())
 	{
 		glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, m_glName, 0, &m_in.getName()[0]);
 	}
@@ -302,7 +302,7 @@ void FramebufferImpl::bind(const GlState& state, U32 minx, U32 miny, U32 width,
 
 void FramebufferImpl::endRenderPass() const
 {
-	if(m_in.getName() && getManager().getImplementation().debugMarkersEnabled())
+	if(m_in.getName() && static_cast<const GrManagerImpl&>(getManager()).debugMarkersEnabled())
 	{
 		glPopDebugGroup();
 	}

+ 5 - 5
src/anki/gr/gl/FramebufferImpl.h

@@ -5,8 +5,8 @@
 
 #pragma once
 
-#include <anki/gr/gl/GlObject.h>
 #include <anki/gr/Framebuffer.h>
+#include <anki/gr/gl/GlObject.h>
 
 namespace anki
 {
@@ -15,17 +15,17 @@ namespace anki
 /// @{
 
 /// Framebuffer implementation.
-class FramebufferImpl : public GlObject
+class FramebufferImpl final : public Framebuffer, public GlObject
 {
 public:
 	FramebufferImpl(GrManager* manager)
-		: GlObject(manager)
+		: Framebuffer(manager)
 	{
 	}
 
 	~FramebufferImpl()
 	{
-		destroyDeferred(glDeleteFramebuffers);
+		destroyDeferred(getManager(), glDeleteFramebuffers);
 	}
 
 	/// Set all the attachments. It will overwrite the previous state. If the initalizer list is empty the it will bind
@@ -33,7 +33,7 @@ public:
 	ANKI_USE_RESULT Error init(const FramebufferInitInfo& init);
 
 	/// Bind it to the state. Call it in rendering thread
-	void bind(const GlState& state, U32 minx, U32 miny, U32 width, U32 height);
+	void bind(const GlState& state, U32 minx, U32 miny, U32 width, U32 height) const;
 
 	void endRenderPass() const;
 

+ 25 - 32
src/anki/gr/gl/GlObject.cpp

@@ -13,14 +13,13 @@
 namespace anki
 {
 
-GlObject::GlObject(GrManager* manager)
-	: m_manager(manager)
-	, m_glName(0)
+GlObject::GlObject()
+	: m_glName(0)
 	, m_state(I32(State::TO_BE_CREATED))
 {
 }
 
-Error GlObject::serializeRenderingThread()
+Error GlObject::serializeRenderingThread(GrManager& manager)
 {
 	Error err = Error::NONE;
 	State state = State(m_state.load());
@@ -28,7 +27,7 @@ Error GlObject::serializeRenderingThread()
 
 	if(state == State::TO_BE_CREATED)
 	{
-		RenderingThread& thread = m_manager->getImplementation().getRenderingThread();
+		RenderingThread& thread = static_cast<GrManagerImpl&>(manager).getRenderingThread();
 		thread.syncClientServer();
 
 		state = State(m_state.load());
@@ -44,42 +43,41 @@ Error GlObject::serializeRenderingThread()
 	return err;
 }
 
-class DeleteGlObjectCommand final : public GlCommand
+void GlObject::destroyDeferred(GrManager& manager, GlDeleteFunction deleteCallback)
 {
-public:
-	GlObject::GlDeleteFunction m_callback;
-	GLuint m_glName;
-
-	DeleteGlObjectCommand(GlObject::GlDeleteFunction callback, GLuint name)
-		: m_callback(callback)
-		, m_glName(name)
+	class DeleteGlObjectCommand final : public GlCommand
 	{
-	}
+	public:
+		GlObject::GlDeleteFunction m_callback;
+		GLuint m_glName;
 
-	Error operator()(GlState&)
-	{
-		m_callback(1, &m_glName);
-		return Error::NONE;
-	}
-};
+		DeleteGlObjectCommand(GlObject::GlDeleteFunction callback, GLuint name)
+			: m_callback(callback)
+			, m_glName(name)
+		{
+		}
+
+		Error operator()(GlState&)
+		{
+			m_callback(1, &m_glName);
+			return Error::NONE;
+		}
+	};
 
-void GlObject::destroyDeferred(GlDeleteFunction deleteCallback)
-{
 	if(m_glName == 0)
 	{
 		return;
 	}
 
-	GrManager& manager = getManager();
-	RenderingThread& thread = manager.getImplementation().getRenderingThread();
+	RenderingThread& thread = static_cast<GrManagerImpl&>(manager).getRenderingThread();
 
 	if(!thread.isServerThread())
 	{
 		CommandBufferPtr commands;
 
-		commands = manager.newInstance<CommandBuffer>(CommandBufferInitInfo());
-		commands->m_impl->pushBackNewCommand<DeleteGlObjectCommand>(deleteCallback, m_glName);
-		commands->flush();
+		commands = manager.newCommandBuffer(CommandBufferInitInfo());
+		static_cast<CommandBufferImpl&>(*commands).pushBackNewCommand<DeleteGlObjectCommand>(deleteCallback, m_glName);
+		static_cast<CommandBufferImpl&>(*commands).flush();
 	}
 	else
 	{
@@ -89,9 +87,4 @@ void GlObject::destroyDeferred(GlDeleteFunction deleteCallback)
 	m_glName = 0;
 }
 
-GrAllocator<U8> GlObject::getAllocator() const
-{
-	return m_manager->getAllocator();
-}
-
 } // end namespace anki

+ 3 - 17
src/anki/gr/gl/GlObject.h

@@ -32,7 +32,7 @@ public:
 	using GlDeleteFunction = void (*)(GLsizei, const GLuint*);
 
 	/// Default
-	GlObject(GrManager* manager);
+	GlObject();
 
 	~GlObject()
 	{
@@ -59,26 +59,12 @@ public:
 	}
 
 	/// Check if the object has been created and if not serialize the thread.
-	ANKI_USE_RESULT Error serializeRenderingThread();
+	ANKI_USE_RESULT Error serializeRenderingThread(GrManager& manager);
 
 	/// Should be called from GL objects for deferred deletion.
-	void destroyDeferred(GlDeleteFunction deleteCallback);
-
-	/// Get the allocator.
-	GrAllocator<U8> getAllocator() const;
-
-	GrManager& getManager()
-	{
-		return *m_manager;
-	}
-
-	const GrManager& getManager() const
-	{
-		return *m_manager;
-	}
+	void destroyDeferred(GrManager& manager, GlDeleteFunction deleteCallback);
 
 protected:
-	GrManager* m_manager = nullptr;
 	GLuint m_glName = 0; ///< OpenGL name
 	mutable Atomic<I32> m_state;
 };

+ 100 - 20
src/anki/gr/gl/GrManager.cpp

@@ -9,6 +9,17 @@
 #include <anki/gr/gl/TextureImpl.h>
 #include <anki/gr/gl/GlState.h>
 #include <anki/core/Timestamp.h>
+
+#include <anki/gr/Buffer.h>
+#include <anki/gr/Texture.h>
+#include <anki/gr/Sampler.h>
+#include <anki/gr/Shader.h>
+#include <anki/gr/ShaderProgram.h>
+#include <anki/gr/CommandBuffer.h>
+#include <anki/gr/Framebuffer.h>
+#include <anki/gr/OcclusionQuery.h>
+#include <anki/gr/RenderGraph.h>
+
 #include <cstring>
 
 namespace anki
@@ -21,20 +32,36 @@ GrManager::GrManager()
 GrManager::~GrManager()
 {
 	// Destroy in reverse order
-	m_impl.reset(nullptr);
 	m_cacheDir.destroy(m_alloc);
 }
 
-Error GrManager::init(GrManagerInitInfo& init)
+Error GrManager::newInstance(GrManagerInitInfo& init, GrManager*& gr)
 {
-	m_alloc = HeapAllocator<U8>(init.m_allocCallback, init.m_allocCallbackUserData);
-
-	m_cacheDir.create(m_alloc, init.m_cacheDirectory);
+	auto alloc = GrAllocator<U8>(init.m_allocCallback, init.m_allocCallbackUserData);
+
+	GrManagerImpl* impl = alloc.newInstance<GrManagerImpl>();
+	Error err = impl->init(init, alloc);
+
+	if(err)
+	{
+		alloc.deleteInstance(impl);
+		gr = nullptr;
+	}
+	else
+	{
+		gr = impl;
+	}
+
+	return err;
+}
 
-	m_impl.reset(m_alloc.newInstance<GrManagerImpl>(this));
-	ANKI_CHECK(m_impl->init(init));
+void GrManager::deleteInstance(GrManager* gr)
+{
+	ANKI_ASSERT(gr);
 
-	return Error::NONE;
+	auto alloc = gr->m_alloc;
+	gr->~GrManager();
+	alloc.deallocate(gr, 1);
 }
 
 void GrManager::beginFrame()
@@ -44,55 +71,108 @@ void GrManager::beginFrame()
 
 void GrManager::swapBuffers()
 {
-	m_impl->getRenderingThread().swapBuffers();
+	ANKI_GL_SELF(GrManagerImpl);
+	self.getRenderingThread().swapBuffers();
 }
 
 void GrManager::finish()
 {
-	m_impl->getRenderingThread().syncClientServer();
+	ANKI_GL_SELF(GrManagerImpl);
+	self.getRenderingThread().syncClientServer();
+}
+
+BufferPtr GrManager::newBuffer(const BufferInitInfo& init)
+{
+	return BufferPtr(Buffer::newInstance(this, init));
+}
+
+TexturePtr GrManager::newTexture(const TextureInitInfo& init)
+{
+	return TexturePtr(Texture::newInstance(this, init));
+}
+
+SamplerPtr GrManager::newSampler(const SamplerInitInfo& init)
+{
+	return SamplerPtr(Sampler::newInstance(this, init));
+}
+
+ShaderPtr GrManager::newShader(const ShaderInitInfo& init)
+{
+	return ShaderPtr(Shader::newInstance(this, init));
+}
+
+ShaderProgramPtr GrManager::newShaderProgram(const ShaderProgramInitInfo& init)
+{
+	return ShaderProgramPtr(ShaderProgram::newInstance(this, init));
+}
+
+CommandBufferPtr GrManager::newCommandBuffer(const CommandBufferInitInfo& init)
+{
+	return CommandBufferPtr(CommandBuffer::newInstance(this, init));
+}
+
+FramebufferPtr GrManager::newFramebuffer(const FramebufferInitInfo& init)
+{
+	return FramebufferPtr(Framebuffer::newInstance(this, init));
+}
+
+OcclusionQueryPtr GrManager::newOcclusionQuery()
+{
+	return OcclusionQueryPtr(OcclusionQuery::newInstance(this));
+}
+
+RenderGraphPtr GrManager::newRenderGraph()
+{
+	return RenderGraphPtr(RenderGraph::newInstance(this));
 }
 
 void GrManager::getTextureSurfaceUploadInfo(TexturePtr tex, const TextureSurfaceInfo& surf, PtrSize& allocationSize)
 {
-	const TextureImpl& impl = *tex->m_impl;
+	const TextureImpl& impl = static_cast<const TextureImpl&>(*tex);
 	impl.checkSurfaceOrVolume(surf);
 
 	U width = impl.m_width >> surf.m_level;
 	U height = impl.m_height >> surf.m_level;
-	allocationSize = computeSurfaceSize(width, height, impl.m_pformat);
+	allocationSize = computeSurfaceSize(width, height, impl.m_format);
 }
 
 void GrManager::getTextureVolumeUploadInfo(TexturePtr tex, const TextureVolumeInfo& vol, PtrSize& allocationSize)
 {
-	const TextureImpl& impl = *tex->m_impl;
+	const TextureImpl& impl = static_cast<const TextureImpl&>(*tex);
 	impl.checkSurfaceOrVolume(vol);
 
 	U width = impl.m_width >> vol.m_level;
 	U height = impl.m_height >> vol.m_level;
 	U depth = impl.m_depth >> vol.m_level;
-	allocationSize = computeVolumeSize(width, height, depth, impl.m_pformat);
+	allocationSize = computeVolumeSize(width, height, depth, impl.m_format);
 }
 
 void GrManager::getUniformBufferInfo(U32& bindOffsetAlignment, PtrSize& maxUniformBlockSize) const
 {
-	bindOffsetAlignment = m_impl->getState().m_uboAlignment;
-	maxUniformBlockSize = m_impl->getState().m_uniBlockMaxSize;
+	ANKI_GL_SELF_CONST(GrManagerImpl);
+
+	bindOffsetAlignment = self.getState().m_uboAlignment;
+	maxUniformBlockSize = self.getState().m_uniBlockMaxSize;
 
 	ANKI_ASSERT(bindOffsetAlignment > 0 && maxUniformBlockSize > 0);
 }
 
 void GrManager::getStorageBufferInfo(U32& bindOffsetAlignment, PtrSize& maxStorageBlockSize) const
 {
-	bindOffsetAlignment = m_impl->getState().m_ssboAlignment;
-	maxStorageBlockSize = m_impl->getState().m_storageBlockMaxSize;
+	ANKI_GL_SELF_CONST(GrManagerImpl);
+
+	bindOffsetAlignment = self.getState().m_ssboAlignment;
+	maxStorageBlockSize = self.getState().m_storageBlockMaxSize;
 
 	ANKI_ASSERT(bindOffsetAlignment > 0 && maxStorageBlockSize > 0);
 }
 
 void GrManager::getTextureBufferInfo(U32& bindOffsetAlignment, PtrSize& maxRange) const
 {
-	bindOffsetAlignment = m_impl->getState().m_tboAlignment;
-	maxRange = m_impl->getState().m_tboMaxRange;
+	ANKI_GL_SELF_CONST(GrManagerImpl);
+
+	bindOffsetAlignment = self.getState().m_tboAlignment;
+	maxRange = self.getState().m_tboMaxRange;
 
 	ANKI_ASSERT(bindOffsetAlignment > 0 && maxRange > 0);
 }

+ 8 - 10
src/anki/gr/gl/GrManagerImpl.cpp

@@ -17,37 +17,35 @@ GrManagerImpl::~GrManagerImpl()
 	if(m_thread)
 	{
 		m_thread->stop();
-		m_manager->getAllocator().deleteInstance(m_thread);
+		m_alloc.deleteInstance(m_thread);
 		m_thread = nullptr;
 	}
 
 	if(m_state)
 	{
-		m_manager->getAllocator().deleteInstance(m_state);
+		m_alloc.deleteInstance(m_state);
 	}
 
 	destroyBackend();
-	m_manager = nullptr;
 }
 
-GrAllocator<U8> GrManagerImpl::getAllocator() const
+Error GrManagerImpl::init(GrManagerInitInfo& init, GrAllocator<U8> alloc)
 {
-	return m_manager->getAllocator();
-}
+	m_alloc = HeapAllocator<U8>(init.m_allocCallback, init.m_allocCallbackUserData);
+
+	m_cacheDir.create(m_alloc, init.m_cacheDirectory);
 
-Error GrManagerImpl::init(GrManagerInitInfo& init)
-{
 	m_debugMarkers = init.m_config->getNumber("window.debugMarkers");
 
 	// Init the backend of the backend
 	ANKI_CHECK(createBackend(init));
 
 	// First create the state
-	m_state = m_manager->getAllocator().newInstance<GlState>(m_manager);
+	m_state = m_alloc.newInstance<GlState>(this);
 	m_state->initMainThread(*init.m_config);
 
 	// Create thread
-	m_thread = m_manager->getAllocator().newInstance<RenderingThread>(m_manager);
+	m_thread = m_alloc.newInstance<RenderingThread>(this);
 
 	// Start it
 	m_thread->start();

+ 4 - 8
src/anki/gr/gl/GrManagerImpl.h

@@ -5,6 +5,7 @@
 
 #pragma once
 
+#include <anki/gr/GrManager.h>
 #include <anki/gr/gl/Common.h>
 
 namespace anki
@@ -19,18 +20,16 @@ class GlState;
 /// @{
 
 /// Graphics manager backend specific.
-class GrManagerImpl
+class GrManagerImpl final : public GrManager
 {
 public:
-	GrManagerImpl(GrManager* manager)
-		: m_manager(manager)
+	GrManagerImpl()
 	{
-		ANKI_ASSERT(manager);
 	}
 
 	~GrManagerImpl();
 
-	ANKI_USE_RESULT Error init(GrManagerInitInfo& init);
+	ANKI_USE_RESULT Error init(GrManagerInitInfo& init, GrAllocator<U8> alloc);
 
 	const RenderingThread& getRenderingThread() const
 	{
@@ -56,8 +55,6 @@ public:
 		return *m_state;
 	}
 
-	GrAllocator<U8> getAllocator() const;
-
 	void swapBuffers();
 
 	void pinContextToCurrentThread(Bool pin);
@@ -68,7 +65,6 @@ public:
 	}
 
 private:
-	GrManager* m_manager;
 	GlState* m_state = nullptr;
 	RenderingThread* m_thread = nullptr;
 	WindowingBackend* m_backend = nullptr; ///< The backend of the backend.

+ 7 - 15
src/anki/gr/gl/OcclusionQuery.cpp

@@ -11,16 +11,7 @@
 namespace anki
 {
 
-OcclusionQuery::OcclusionQuery(GrManager* manager)
-	: GrObject(manager, CLASS_TYPE)
-{
-}
-
-OcclusionQuery::~OcclusionQuery()
-{
-}
-
-void OcclusionQuery::init()
+OcclusionQuery* OcclusionQuery::newInstance(GrManager* manager)
 {
 	class CreateOqCommand final : public GlCommand
 	{
@@ -34,7 +25,7 @@ void OcclusionQuery::init()
 
 		Error operator()(GlState&)
 		{
-			OcclusionQueryImpl& impl = *m_q->m_impl;
+			OcclusionQueryImpl& impl = static_cast<OcclusionQueryImpl&>(*m_q);
 
 			impl.init();
 
@@ -47,12 +38,13 @@ void OcclusionQuery::init()
 		}
 	};
 
-	m_impl.reset(getAllocator().newInstance<OcclusionQueryImpl>(&getManager()));
+	OcclusionQueryImpl* impl = manager->getAllocator().newInstance<OcclusionQueryImpl>(manager);
 
-	CommandBufferPtr cmdb = getManager().newInstance<CommandBuffer>(CommandBufferInitInfo());
+	CommandBufferPtr cmdb = manager->newCommandBuffer(CommandBufferInitInfo());
+	static_cast<CommandBufferImpl&>(*cmdb).pushBackNewCommand<CreateOqCommand>(impl);
+	static_cast<CommandBufferImpl&>(*cmdb).flush();
 
-	cmdb->m_impl->pushBackNewCommand<CreateOqCommand>(this);
-	cmdb->flush();
+	return impl;
 }
 
 } // end namespace anki

+ 4 - 3
src/anki/gr/gl/OcclusionQueryImpl.h

@@ -5,6 +5,7 @@
 
 #pragma once
 
+#include <anki/gr/OcclusionQuery.h>
 #include <anki/gr/gl/GlObject.h>
 
 namespace anki
@@ -14,17 +15,17 @@ namespace anki
 /// @{
 
 /// Occlusion query.
-class OcclusionQueryImpl : public GlObject
+class OcclusionQueryImpl final : public OcclusionQuery, public GlObject
 {
 public:
 	OcclusionQueryImpl(GrManager* manager)
-		: GlObject(manager)
+		: OcclusionQuery(manager)
 	{
 	}
 
 	~OcclusionQueryImpl()
 	{
-		destroyDeferred(glDeleteQueries);
+		destroyDeferred(getManager(), glDeleteQueries);
 	}
 
 	/// Create the query.

+ 22 - 22
src/anki/gr/gl/RenderingThread.cpp

@@ -63,7 +63,7 @@ public:
 	}
 };
 
-RenderingThread::RenderingThread(GrManager* manager)
+RenderingThread::RenderingThread(GrManagerImpl* manager)
 	: m_manager(manager)
 	, m_tail(0)
 	, m_head(0)
@@ -84,9 +84,8 @@ void RenderingThread::flushCommandBuffer(CommandBufferPtr cmdb, FencePtr* fence)
 	if(fence)
 	{
 		FencePtr& f = *fence;
-
-		f.reset(m_manager->getImplementation().getAllocator().newInstance<Fence>(m_manager.get()));
-		f->m_impl.reset(m_manager->getAllocator().newInstance<FenceImpl>(m_manager.get()));
+		FenceImpl* fenceImpl = m_manager->getAllocator().newInstance<FenceImpl>(m_manager.get());
+		f.reset(fenceImpl);
 
 		class CreateFenceCmd final : public GlCommand
 		{
@@ -100,15 +99,15 @@ void RenderingThread::flushCommandBuffer(CommandBufferPtr cmdb, FencePtr* fence)
 
 			Error operator()(GlState&)
 			{
-				m_fence->m_impl->m_fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+				static_cast<FenceImpl&>(*m_fence).m_fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
 				return Error::NONE;
 			}
 		};
 
-		cmdb->m_impl->pushBackNewCommand<CreateFenceCmd>(f);
+		static_cast<CommandBufferImpl&>(*cmdb).pushBackNewCommand<CreateFenceCmd>(f);
 	}
 
-	cmdb->m_impl->makeImmutable();
+	static_cast<CommandBufferImpl&>(*cmdb).makeImmutable();
 
 	{
 		LockGuard<Mutex> lock(m_mtx);
@@ -145,22 +144,23 @@ void RenderingThread::start()
 	m_queue.create(m_manager->getAllocator(), QUEUE_SIZE);
 
 	// Swap buffers stuff
-	m_swapBuffersCommands = m_manager->newInstance<CommandBuffer>(CommandBufferInitInfo());
-	m_swapBuffersCommands->m_impl->pushBackNewCommand<SwapBuffersCommand>(this);
+	m_swapBuffersCommands = m_manager->newCommandBuffer(CommandBufferInitInfo());
+
+	static_cast<CommandBufferImpl&>(*m_swapBuffersCommands).pushBackNewCommand<SwapBuffersCommand>(this);
 	// Just in case noone swaps
-	m_swapBuffersCommands->m_impl->makeExecuted();
+	static_cast<CommandBufferImpl&>(*m_swapBuffersCommands).makeExecuted();
 
-	m_manager->getImplementation().pinContextToCurrentThread(false);
+	m_manager->pinContextToCurrentThread(false);
 
 	// Start thread
 	m_thread.start(this, threadCallback);
 
 	// Create sync command buffer
-	m_syncCommands = m_manager->newInstance<CommandBuffer>(CommandBufferInitInfo());
-	m_syncCommands->m_impl->pushBackNewCommand<SyncCommand>(this);
+	m_syncCommands = m_manager->newCommandBuffer(CommandBufferInitInfo());
+	static_cast<CommandBufferImpl&>(*m_syncCommands).pushBackNewCommand<SyncCommand>(this);
 
-	m_emptyCmdb = m_manager->newInstance<CommandBuffer>(CommandBufferInitInfo());
-	m_emptyCmdb->m_impl->pushBackNewCommand<EmptyCommand>();
+	m_emptyCmdb = m_manager->newCommandBuffer(CommandBufferInitInfo());
+	static_cast<CommandBufferImpl&>(*m_emptyCmdb).pushBackNewCommand<EmptyCommand>();
 }
 
 void RenderingThread::stop()
@@ -175,7 +175,7 @@ void RenderingThread::stop()
 
 void RenderingThread::prepare()
 {
-	m_manager->getImplementation().pinContextToCurrentThread(true);
+	m_manager->pinContextToCurrentThread(true);
 
 	// Ignore the first error
 	glGetError();
@@ -188,7 +188,7 @@ void RenderingThread::prepare()
 	m_serverThreadId = Thread::getCurrentThreadId();
 
 	// Init state
-	m_manager->getImplementation().getState().initRenderThread();
+	m_manager->getState().initRenderThread();
 }
 
 void RenderingThread::finish()
@@ -199,7 +199,7 @@ void RenderingThread::finish()
 		if(m_queue[i].isCreated())
 		{
 			// Fake that it's executed to avoid warnings
-			m_queue[i]->m_impl->makeExecuted();
+			static_cast<CommandBufferImpl&>(*m_queue[i]).makeExecuted();
 
 			// Release
 			m_queue[i] = CommandBufferPtr();
@@ -207,11 +207,11 @@ void RenderingThread::finish()
 	}
 
 	// Cleanup GL
-	m_manager->getImplementation().getState().destroy();
+	m_manager->getState().destroy();
 
 	// Cleanup
 	glFinish();
-	m_manager->getImplementation().pinContextToCurrentThread(false);
+	m_manager->pinContextToCurrentThread(false);
 }
 
 Error RenderingThread::threadCallback(ThreadCallbackInfo& info)
@@ -253,7 +253,7 @@ void RenderingThread::threadLoop()
 		}
 
 		ANKI_TRACE_START_EVENT(GL_THREAD);
-		Error err = cmd->m_impl->executeAllCommands();
+		Error err = static_cast<CommandBufferImpl&>(*cmd).executeAllCommands();
 		ANKI_TRACE_STOP_EVENT(GL_THREAD);
 
 		if(err)
@@ -281,7 +281,7 @@ void RenderingThread::swapBuffersInternal()
 	ANKI_TRACE_START_EVENT(SWAP_BUFFERS);
 
 	// Do the swap buffers
-	m_manager->getImplementation().swapBuffers();
+	m_manager->swapBuffers();
 
 	// Notify the main thread that we are done
 	{

+ 2 - 2
src/anki/gr/gl/RenderingThread.h

@@ -21,7 +21,7 @@ class RenderingThread
 	friend class SwapBuffersCommand;
 
 public:
-	RenderingThread(GrManager* device);
+	RenderingThread(GrManagerImpl* device);
 
 	~RenderingThread();
 
@@ -51,7 +51,7 @@ public:
 	void swapBuffers();
 
 private:
-	WeakPtr<GrManager> m_manager;
+	WeakPtr<GrManagerImpl> m_manager;
 
 	static const U QUEUE_SIZE = 1024 * 2;
 	DynamicArray<CommandBufferPtr> m_queue; ///< Command queue

+ 7 - 16
src/anki/gr/gl/Sampler.cpp

@@ -11,16 +11,7 @@
 namespace anki
 {
 
-Sampler::Sampler(GrManager* manager)
-	: GrObject(manager, CLASS_TYPE)
-{
-}
-
-Sampler::~Sampler()
-{
-}
-
-void Sampler::init(const SamplerInitInfo& init)
+Sampler* Sampler::newInstance(GrManager* manager, const SamplerInitInfo& init)
 {
 	class CreateSamplerCommand : public GlCommand
 	{
@@ -36,12 +27,11 @@ void Sampler::init(const SamplerInitInfo& init)
 
 		Error operator()(GlState&)
 		{
-			SamplerImpl& impl = *m_sampler->m_impl;
+			SamplerImpl& impl = static_cast<SamplerImpl&>(*m_sampler);
 
 			impl.init(m_init);
 
 			GlObject::State oldState = impl.setStateAtomically(GlObject::State::CREATED);
-
 			(void)oldState;
 			ANKI_ASSERT(oldState == GlObject::State::TO_BE_CREATED);
 
@@ -49,12 +39,13 @@ void Sampler::init(const SamplerInitInfo& init)
 		}
 	};
 
-	m_impl.reset(getAllocator().newInstance<SamplerImpl>(&getManager()));
+	SamplerImpl* impl = manager->getAllocator().newInstance<SamplerImpl>(manager);
 
-	CommandBufferPtr cmdb = getManager().newInstance<CommandBuffer>(CommandBufferInitInfo());
+	CommandBufferPtr cmdb = manager->newCommandBuffer(CommandBufferInitInfo());
+	static_cast<CommandBufferImpl&>(*cmdb).pushBackNewCommand<CreateSamplerCommand>(impl, init);
+	static_cast<CommandBufferImpl&>(*cmdb).flush();
 
-	cmdb->m_impl->pushBackNewCommand<CreateSamplerCommand>(this, init);
-	cmdb->flush();
+	return impl;
 }
 
 } // end namespace anki

+ 4 - 3
src/anki/gr/gl/SamplerImpl.h

@@ -5,6 +5,7 @@
 
 #pragma once
 
+#include <anki/gr/Sampler.h>
 #include <anki/gr/gl/GlObject.h>
 
 namespace anki
@@ -14,17 +15,17 @@ namespace anki
 /// @{
 
 /// Sampler GL object.
-class SamplerImpl : public GlObject
+class SamplerImpl final : public Sampler, public GlObject
 {
 public:
 	SamplerImpl(GrManager* manager)
-		: GlObject(manager)
+		: Sampler(manager)
 	{
 	}
 
 	~SamplerImpl()
 	{
-		destroyDeferred(glDeleteSamplers);
+		destroyDeferred(getManager(), glDeleteSamplers);
 	}
 
 	void init(const SamplerInitInfo& sinit);

+ 33 - 45
src/anki/gr/gl/Shader.cpp

@@ -11,63 +11,51 @@
 namespace anki
 {
 
-Shader::Shader(GrManager* manager)
-	: GrObject(manager, CLASS_TYPE)
+Shader* Shader::newInstance(GrManager* manager, const ShaderInitInfo& init)
 {
-}
-
-Shader::~Shader()
-{
-}
-
-class ShaderCreateCommand final : public GlCommand
-{
-public:
-	ShaderPtr m_shader;
-	ShaderType m_type;
-	char* m_source;
-	CommandBufferAllocator<char> m_alloc;
-
-	ShaderCreateCommand(Shader* shader, ShaderType type, char* source, const CommandBufferAllocator<char>& alloc)
-		: m_shader(shader)
-		, m_type(type)
-		, m_source(source)
-		, m_alloc(alloc)
+	class ShaderCreateCommand final : public GlCommand
 	{
-	}
+	public:
+		ShaderPtr m_shader;
+		ShaderType m_type;
+		StringAuto m_source;
 
-	Error operator()(GlState&)
-	{
-		ShaderImpl& impl = *m_shader->m_impl;
+		ShaderCreateCommand(Shader* shader, ShaderType type, CString source, const CommandBufferAllocator<U8>& alloc)
+			: m_shader(shader)
+			, m_type(type)
+			, m_source(alloc)
+		{
+			m_source.create(source);
+		}
 
-		Error err = impl.init(m_type, m_source);
+		Error operator()(GlState&)
+		{
+			ShaderImpl& impl = static_cast<ShaderImpl&>(*m_shader);
 
-		GlObject::State oldState = impl.setStateAtomically((err) ? GlObject::State::ERROR : GlObject::State::CREATED);
-		ANKI_ASSERT(oldState == GlObject::State::TO_BE_CREATED);
-		(void)oldState;
+			Error err = impl.init(m_type, m_source.toCString());
 
-		// Delete source
-		m_alloc.deallocate(m_source, 1);
+			GlObject::State oldState =
+				impl.setStateAtomically((err) ? GlObject::State::ERROR : GlObject::State::CREATED);
+			ANKI_ASSERT(oldState == GlObject::State::TO_BE_CREATED);
+			(void)oldState;
 
-		return err;
-	}
-};
+			return err;
+		}
+	};
 
-void Shader::init(ShaderType shaderType, const CString& source)
-{
-	ANKI_ASSERT(!source.isEmpty());
+	ANKI_ASSERT(!init.m_source.isEmpty() && init.m_source.getLength() > 0);
 
-	m_impl.reset(getAllocator().newInstance<ShaderImpl>(&getManager()));
-
-	CommandBufferPtr cmdb = getManager().newInstance<CommandBuffer>(CommandBufferInitInfo());
+	ShaderImpl* impl = manager->getAllocator().newInstance<ShaderImpl>(manager);
 
 	// Copy source to the command buffer
-	CommandBufferAllocator<char> alloc = cmdb->m_impl->getInternalAllocator();
-	char* src = alloc.allocate(source.getLength() + 1);
-	memcpy(src, &source[0], source.getLength() + 1);
+	CommandBufferPtr cmdb = manager->newCommandBuffer(CommandBufferInitInfo());
+	CommandBufferImpl& cmdbimpl = static_cast<CommandBufferImpl&>(*cmdb);
+	CommandBufferAllocator<U8> alloc = cmdbimpl.getInternalAllocator();
+
+	cmdbimpl.pushBackNewCommand<ShaderCreateCommand>(impl, init.m_shaderType, init.m_source, alloc);
+	cmdbimpl.flush();
 
-	cmdb->m_impl->pushBackNewCommand<ShaderCreateCommand>(this, shaderType, src, alloc);
-	cmdb->flush();
+	return impl;
 }
 
 } // end namespace anki

+ 4 - 4
src/anki/gr/gl/ShaderImpl.cpp

@@ -51,7 +51,7 @@ static const char* SHADER_HEADER = R"(#version %u %s
 
 ShaderImpl::~ShaderImpl()
 {
-	destroyDeferred(deleteShaders);
+	destroyDeferred(getManager(), deleteShaders);
 }
 
 Error ShaderImpl::init(ShaderType type, const CString& source)
@@ -97,7 +97,7 @@ Error ShaderImpl::init(ShaderType type, const CString& source)
 	fullSrc.sprintf(SHADER_HEADER,
 		version,
 		versionType,
-		&GPU_VENDOR_STR[getManager().getImplementation().getState().m_gpu][0],
+		&GPU_VENDOR_STR[static_cast<const GrManagerImpl&>(getManager()).getState().m_gpu][0],
 		shaderName[U(type)],
 		MAX_UNIFORM_BUFFER_BINDINGS,
 		MAX_STORAGE_BUFFER_BINDINGS,
@@ -105,7 +105,7 @@ Error ShaderImpl::init(ShaderType type, const CString& source)
 		MAX_IMAGE_BINDINGS,
 		MAX_TEXTURE_BINDINGS * MAX_DESCRIPTOR_SETS,
 		MAX_TEXTURE_BUFFER_BINDINGS,
-		!!(getManager().getImplementation().getState().m_extensions & GlExtensions::ARB_SHADER_BALLOT),
+		!!(static_cast<const GrManagerImpl&>(getManager()).getState().m_extensions & GlExtensions::ARB_SHADER_BALLOT),
 		&source[0]);
 
 	// 2) Gen name, create, compile and link
@@ -146,7 +146,7 @@ Error ShaderImpl::init(ShaderType type, const CString& source)
 		}
 
 		StringAuto fname(alloc);
-		CString cacheDir = m_manager->getCacheDirectory();
+		CString cacheDir = getManager().getCacheDirectory();
 		fname.sprintf("%s/%05u.%s", &cacheDir[0], static_cast<U32>(m_glName), ext);
 
 		File file;

+ 2 - 2
src/anki/gr/gl/ShaderImpl.h

@@ -19,14 +19,14 @@ class String;
 /// @{
 
 /// Shader program. It only contains a single shader and it can be combined with other programs in a program pipiline.
-class ShaderImpl : public GlObject
+class ShaderImpl final : public Shader, public GlObject
 {
 public:
 	GLenum m_glType = 0;
 	ShaderType m_type;
 
 	ShaderImpl(GrManager* manager)
-		: GlObject(manager)
+		: Shader(manager)
 	{
 	}
 

+ 30 - 75
src/anki/gr/gl/ShaderProgram.cpp

@@ -12,74 +12,7 @@
 namespace anki
 {
 
-ShaderProgram::ShaderProgram(GrManager* manager)
-	: GrObject(manager, CLASS_TYPE)
-{
-}
-
-ShaderProgram::~ShaderProgram()
-{
-}
-
-void ShaderProgram::init(ShaderPtr vert, ShaderPtr frag)
-{
-	class CreateCommand final : public GlCommand
-	{
-	public:
-		ShaderProgramPtr m_prog;
-		ShaderPtr m_vert;
-		ShaderPtr m_frag;
-
-		CreateCommand(ShaderProgram* prog, ShaderPtr vert, ShaderPtr frag)
-			: m_prog(prog)
-			, m_vert(vert)
-			, m_frag(frag)
-		{
-		}
-
-		Error operator()(GlState&)
-		{
-			ShaderPtr none;
-			return m_prog->m_impl->initGraphics(m_vert, none, none, none, m_frag);
-		}
-	};
-
-	m_impl.reset(getAllocator().newInstance<ShaderProgramImpl>(&getManager()));
-
-	CommandBufferPtr cmdb = getManager().newInstance<CommandBuffer>(CommandBufferInitInfo());
-	cmdb->m_impl->pushBackNewCommand<CreateCommand>(this, vert, frag);
-	cmdb->flush();
-}
-
-void ShaderProgram::init(ShaderPtr comp)
-{
-	class CreateCommand final : public GlCommand
-	{
-	public:
-		ShaderProgramPtr m_prog;
-		ShaderPtr m_comp;
-
-		CreateCommand(ShaderProgram* prog, ShaderPtr comp)
-			: m_prog(prog)
-			, m_comp(comp)
-		{
-		}
-
-		Error operator()(GlState&)
-		{
-			ShaderPtr none;
-			return m_prog->m_impl->initCompute(m_comp);
-		}
-	};
-
-	m_impl.reset(getAllocator().newInstance<ShaderProgramImpl>(&getManager()));
-
-	CommandBufferPtr cmdb = getManager().newInstance<CommandBuffer>(CommandBufferInitInfo());
-	cmdb->m_impl->pushBackNewCommand<CreateCommand>(this, comp);
-	cmdb->flush();
-}
-
-void ShaderProgram::init(ShaderPtr vert, ShaderPtr tessc, ShaderPtr tesse, ShaderPtr geom, ShaderPtr frag)
+ShaderProgram* ShaderProgram::newInstance(GrManager* manager, const ShaderProgramInitInfo& init)
 {
 	class CreateCommand final : public GlCommand
 	{
@@ -90,29 +23,51 @@ void ShaderProgram::init(ShaderPtr vert, ShaderPtr tessc, ShaderPtr tesse, Shade
 		ShaderPtr m_tesse;
 		ShaderPtr m_geom;
 		ShaderPtr m_frag;
+		ShaderPtr m_comp;
 
-		CreateCommand(
-			ShaderProgram* prog, ShaderPtr vert, ShaderPtr tessc, ShaderPtr tesse, ShaderPtr geom, ShaderPtr frag)
+		CreateCommand(ShaderProgram* prog,
+			ShaderPtr vert,
+			ShaderPtr tessc,
+			ShaderPtr tesse,
+			ShaderPtr geom,
+			ShaderPtr frag,
+			ShaderPtr comp)
 			: m_prog(prog)
 			, m_vert(vert)
 			, m_tessc(tesse)
 			, m_tesse(tesse)
 			, m_geom(geom)
 			, m_frag(frag)
+			, m_comp(comp)
 		{
 		}
 
 		Error operator()(GlState&)
 		{
-			return m_prog->m_impl->initGraphics(m_vert, m_tessc, m_tesse, m_geom, m_frag);
+			if(m_comp)
+			{
+				return static_cast<ShaderProgramImpl&>(*m_prog).initCompute(m_comp);
+			}
+			else
+			{
+				return static_cast<ShaderProgramImpl&>(*m_prog).initGraphics(m_vert, m_tessc, m_tesse, m_geom, m_frag);
+			}
 		}
 	};
 
-	m_impl.reset(getAllocator().newInstance<ShaderProgramImpl>(&getManager()));
+	ShaderProgramImpl* impl = manager->getAllocator().newInstance<ShaderProgramImpl>(manager);
+
+	CommandBufferPtr cmdb = manager->newCommandBuffer(CommandBufferInitInfo());
+	static_cast<CommandBufferImpl&>(*cmdb).pushBackNewCommand<CreateCommand>(impl,
+		init.m_shaders[ShaderType::VERTEX],
+		init.m_shaders[ShaderType::TESSELLATION_CONTROL],
+		init.m_shaders[ShaderType::TESSELLATION_EVALUATION],
+		init.m_shaders[ShaderType::GEOMETRY],
+		init.m_shaders[ShaderType::FRAGMENT],
+		init.m_shaders[ShaderType::COMPUTE]);
+	static_cast<CommandBufferImpl&>(*cmdb).flush();
 
-	CommandBufferPtr cmdb = getManager().newInstance<CommandBuffer>(CommandBufferInitInfo());
-	cmdb->m_impl->pushBackNewCommand<CreateCommand>(this, vert, tessc, tesse, geom, frag);
-	cmdb->flush();
+	return impl;
 }
 
 } // end namespace anki

+ 8 - 13
src/anki/gr/gl/ShaderProgramImpl.cpp

@@ -17,14 +17,9 @@ static void deletePrograms(GLsizei n, const GLuint* progs)
 	glDeleteProgram(*progs);
 }
 
-ShaderProgramImpl::ShaderProgramImpl(GrManager* manager)
-	: GlObject(manager)
-{
-}
-
 ShaderProgramImpl::~ShaderProgramImpl()
 {
-	destroyDeferred(deletePrograms);
+	destroyDeferred(getManager(), deletePrograms);
 }
 
 Error ShaderProgramImpl::initGraphics(ShaderPtr vert, ShaderPtr tessc, ShaderPtr tesse, ShaderPtr geom, ShaderPtr frag)
@@ -32,31 +27,31 @@ Error ShaderProgramImpl::initGraphics(ShaderPtr vert, ShaderPtr tessc, ShaderPtr
 	m_glName = glCreateProgram();
 	ANKI_ASSERT(m_glName != 0);
 
-	glAttachShader(m_glName, vert->m_impl->getGlName());
+	glAttachShader(m_glName, static_cast<const ShaderImpl&>(*vert).getGlName());
 	m_shaders[ShaderType::VERTEX] = vert;
 
 	if(tessc)
 	{
-		glAttachShader(m_glName, tessc->m_impl->getGlName());
+		glAttachShader(m_glName, static_cast<const ShaderImpl&>(*tessc).getGlName());
 		m_shaders[ShaderType::TESSELLATION_CONTROL] = tessc;
 	}
 
 	if(tesse)
 	{
-		glAttachShader(m_glName, tesse->m_impl->getGlName());
+		glAttachShader(m_glName, static_cast<const ShaderImpl&>(*tesse).getGlName());
 		m_shaders[ShaderType::TESSELLATION_EVALUATION] = tesse;
 	}
 
 	if(geom)
 	{
-		glAttachShader(m_glName, geom->m_impl->getGlName());
+		glAttachShader(m_glName, static_cast<const ShaderImpl&>(*geom).getGlName());
 		m_shaders[ShaderType::GEOMETRY] = geom;
 	}
 
-	glAttachShader(m_glName, frag->m_impl->getGlName());
+	glAttachShader(m_glName, static_cast<const ShaderImpl&>(*frag).getGlName());
 	m_shaders[ShaderType::FRAGMENT] = frag;
 
-	return link(vert->m_impl->getGlName(), frag->m_impl->getGlName());
+	return link(static_cast<const ShaderImpl&>(*vert).getGlName(), static_cast<const ShaderImpl&>(*frag).getGlName());
 }
 
 Error ShaderProgramImpl::initCompute(ShaderPtr comp)
@@ -64,7 +59,7 @@ Error ShaderProgramImpl::initCompute(ShaderPtr comp)
 	m_glName = glCreateProgram();
 	ANKI_ASSERT(m_glName != 0);
 
-	glAttachShader(m_glName, comp->m_impl->getGlName());
+	glAttachShader(m_glName, static_cast<const ShaderImpl&>(*comp).getGlName());
 	m_shaders[ShaderType::COMPUTE] = comp;
 
 	return link(0, 0);

+ 6 - 2
src/anki/gr/gl/ShaderProgramImpl.h

@@ -5,6 +5,7 @@
 
 #pragma once
 
+#include <anki/gr/ShaderProgram.h>
 #include <anki/gr/gl/GlObject.h>
 
 namespace anki
@@ -14,10 +15,13 @@ namespace anki
 /// @{
 
 /// Shader program implementation.
-class ShaderProgramImpl : public GlObject
+class ShaderProgramImpl final : public ShaderProgram, public GlObject
 {
 public:
-	ShaderProgramImpl(GrManager* manager);
+	ShaderProgramImpl(GrManager* manager)
+		: ShaderProgram(manager)
+	{
+	}
 
 	~ShaderProgramImpl();
 

+ 19 - 12
src/anki/gr/gl/StateTracker.h

@@ -11,8 +11,14 @@
 #include <anki/gr/gl/FramebufferImpl.h>
 #include <anki/gr/Buffer.h>
 #include <anki/gr/gl/BufferImpl.h>
+#include <anki/gr/Texture.h>
+#include <anki/gr/gl/TextureImpl.h>
 #include <anki/gr/Sampler.h>
 #include <anki/gr/gl/SamplerImpl.h>
+#include <anki/gr/ShaderProgram.h>
+#include <anki/gr/gl/ShaderProgramImpl.h>
+#include <anki/gr/Framebuffer.h>
+#include <anki/gr/gl/FramebufferImpl.h>
 #include <anki/gr/common/Misc.h>
 
 namespace anki
@@ -72,7 +78,7 @@ public:
 	Bool bindVertexBuffer(U32 binding, BufferPtr buff, PtrSize offset, PtrSize stride, VertexStepRate stepRate)
 	{
 		VertexBuffer& b = m_vertBuffs[binding];
-		b.m_buff = buff->m_impl.get();
+		b.m_buff = static_cast<BufferImpl*>(buff.get());
 		b.m_offset = offset;
 		b.m_stride = stride;
 		b.m_stepRate = stepRate;
@@ -89,7 +95,7 @@ public:
 
 	Bool bindIndexBuffer(BufferPtr buff, PtrSize offset, IndexType type)
 	{
-		m_idx.m_buff = buff->m_impl.get();
+		m_idx.m_buff = static_cast<BufferImpl*>(buff.get());
 		m_idx.m_offset = offset;
 		m_idx.m_indexType = convertIndexType(type);
 		return true;
@@ -452,7 +458,7 @@ public:
 		U32 set, U32 binding, TexturePtr tex, DepthStencilAspectBit aspect, Bool& texChanged, Bool& samplerChanged)
 	{
 		TextureBinding& b = m_textures[set][binding];
-		TextureImpl* texi = tex->m_impl.get();
+		TextureImpl* texi = static_cast<TextureImpl*>(tex.get());
 
 		texChanged = false;
 		samplerChanged = false;
@@ -476,8 +482,8 @@ public:
 	Bool bindTextureAndSampler(U32 set, U32 binding, TexturePtr tex, SamplerPtr sampler, DepthStencilAspectBit aspect)
 	{
 		TextureBinding& b = m_textures[set][binding];
-		b.m_tex = tex->m_impl.get();
-		b.m_sampler = sampler->m_impl.get();
+		b.m_tex = static_cast<TextureImpl*>(tex.get());
+		b.m_sampler = static_cast<SamplerImpl*>(sampler.get());
 		b.m_aspect = aspect;
 		return true;
 	}
@@ -495,7 +501,7 @@ public:
 	Bool bindUniformBuffer(U32 set, U32 binding, BufferPtr buff, PtrSize offset, PtrSize range)
 	{
 		ShaderBufferBinding& b = m_ubos[set][binding];
-		b.m_buff = buff->m_impl.get();
+		b.m_buff = static_cast<BufferImpl*>(buff.get());
 		b.m_offset = offset;
 		b.m_range = range;
 		return true;
@@ -506,7 +512,7 @@ public:
 	Bool bindStorageBuffer(U32 set, U32 binding, BufferPtr buff, PtrSize offset, PtrSize range)
 	{
 		ShaderBufferBinding& b = m_ssbos[set][binding];
-		b.m_buff = buff->m_impl.get();
+		b.m_buff = static_cast<BufferImpl*>(buff.get());
 		b.m_offset = offset;
 		b.m_range = range;
 		return true;
@@ -524,7 +530,7 @@ public:
 	Bool bindImage(U32 set, U32 binding, TexturePtr img, U32 level)
 	{
 		ImageBinding& b = m_images[set][binding];
-		b.m_tex = img->m_impl.get();
+		b.m_tex = static_cast<TextureImpl*>(img.get());
 		b.m_level = level;
 		return true;
 	}
@@ -533,9 +539,10 @@ public:
 
 	Bool bindShaderProgram(ShaderProgramPtr prog)
 	{
-		if(prog->m_impl.get() != m_prog)
+		ShaderProgramImpl* const progimpl = static_cast<ShaderProgramImpl*>(prog.get());
+		if(progimpl != m_prog)
 		{
-			m_prog = prog->m_impl.get();
+			m_prog = progimpl;
 			return true;
 		}
 		return false;
@@ -544,12 +551,12 @@ public:
 
 	/// @name other
 	/// @{
-	FramebufferImpl* m_fb = nullptr;
+	const FramebufferImpl* m_fb = nullptr;
 
 	Bool beginRenderPass(const FramebufferPtr& fb)
 	{
 		ANKI_ASSERT(!insideRenderPass() && "Already inside a renderpass");
-		m_fb = fb->m_impl.get();
+		m_fb = static_cast<const FramebufferImpl*>(fb.get());
 		m_lastSecondLevelCmdb = nullptr;
 		return true;
 	}

+ 28 - 38
src/anki/gr/gl/Texture.cpp

@@ -11,54 +11,44 @@
 namespace anki
 {
 
-Texture::Texture(GrManager* manager)
-	: GrObject(manager, CLASS_TYPE)
+Texture* Texture::newInstance(GrManager* manager, const TextureInitInfo& init)
 {
-}
-
-Texture::~Texture()
-{
-}
-
-class CreateTextureCommand final : public GlCommand
-{
-public:
-	IntrusivePtr<Texture> m_tex;
-	TextureInitInfo m_init;
-
-	CreateTextureCommand(Texture* tex, const TextureInitInfo& init)
-		: m_tex(tex)
-		, m_init(init)
+	class CreateTextureCommand final : public GlCommand
 	{
-	}
+	public:
+		TexturePtr m_tex;
+		TextureInitInfo m_init;
 
-	Error operator()(GlState&)
-	{
-		TextureImpl& impl = *m_tex->m_impl;
+		CreateTextureCommand(Texture* tex, const TextureInitInfo& init)
+			: m_tex(tex)
+			, m_init(init)
+		{
+		}
 
-		impl.init(m_init);
+		Error operator()(GlState&)
+		{
+			TextureImpl& impl = static_cast<TextureImpl&>(*m_tex);
 
-		GlObject::State oldState = impl.setStateAtomically(GlObject::State::CREATED);
-		ANKI_ASSERT(oldState == GlObject::State::TO_BE_CREATED);
-		(void)oldState;
+			impl.init(m_init);
 
-		return Error::NONE;
-	}
-};
+			GlObject::State oldState = impl.setStateAtomically(GlObject::State::CREATED);
+			ANKI_ASSERT(oldState == GlObject::State::TO_BE_CREATED);
+			(void)oldState;
 
-void Texture::init(const TextureInitInfo& init)
-{
-	ANKI_ASSERT(textureInitInfoValid(init));
-	m_impl.reset(getAllocator().newInstance<TextureImpl>(&getManager()));
+			return Error::NONE;
+		}
+	};
+
+	TextureImpl* impl = manager->getAllocator().newInstance<TextureImpl>(manager);
 
-	// Need to pre-init because some funcs ask for members and we don't want
-	// to serialize
-	m_impl->preInit(init);
+	// Need to pre-init because some funcs ask for members and we don't want to serialize
+	impl->preInit(init);
 
-	CommandBufferPtr cmdb = getManager().newInstance<CommandBuffer>(CommandBufferInitInfo());
+	CommandBufferPtr cmdb = manager->newCommandBuffer(CommandBufferInitInfo());
+	static_cast<CommandBufferImpl&>(*cmdb).pushBackNewCommand<CreateTextureCommand>(impl, init);
+	static_cast<CommandBufferImpl&>(*cmdb).flush();
 
-	cmdb->m_impl->pushBackNewCommand<CreateTextureCommand>(this, init);
-	cmdb->flush();
+	return impl;
 }
 
 } // end namespace anki

+ 36 - 32
src/anki/gr/gl/TextureImpl.cpp

@@ -39,6 +39,8 @@ static GLenum convertTextureType(TextureType type)
 	case TextureType::CUBE_ARRAY:
 		out = GL_TEXTURE_CUBE_MAP_ARRAY;
 		break;
+	default:
+		ANKI_ASSERT(0);
 	};
 
 	return out;
@@ -86,26 +88,27 @@ public:
 TextureImpl::~TextureImpl()
 {
 	GrManager& manager = getManager();
-	RenderingThread& thread = manager.getImplementation().getRenderingThread();
+	RenderingThread& thread = static_cast<GrManagerImpl&>(manager).getRenderingThread();
 
 	if(!thread.isServerThread())
 	{
 		CommandBufferPtr commands;
 
-		commands = manager.newInstance<CommandBuffer>(CommandBufferInitInfo());
-		commands->m_impl->pushBackNewCommand<DeleteTextureCommand>(m_glName, m_texViews, getAllocator());
-		commands->flush();
+		commands = manager.newCommandBuffer(CommandBufferInitInfo());
+		static_cast<CommandBufferImpl&>(*commands).pushBackNewCommand<DeleteTextureCommand>(
+			m_glName, m_texViews, getAllocator());
+		static_cast<CommandBufferImpl&>(*commands).flush();
 	}
 	else
 	{
 		DeleteTextureCommand cmd(m_glName, m_texViews, getAllocator());
-		cmd(manager.getImplementation().getState());
+		cmd(static_cast<GrManagerImpl&>(manager).getState());
 	}
 
 	m_glName = 0;
 }
 
-void TextureImpl::bind()
+void TextureImpl::bind() const
 {
 	glActiveTexture(GL_TEXTURE0);
 	glBindTexture(m_target, m_glName);
@@ -121,17 +124,17 @@ void TextureImpl::preInit(const TextureInitInfo& init)
 	m_layerCount = init.m_layerCount;
 	m_target = convertTextureType(init.m_type);
 	m_texType = init.m_type;
-	m_pformat = init.m_format;
+	m_format = init.m_format;
 
-	convertTextureInformation(init.m_format, m_compressed, m_format, m_internalFormat, m_type, m_dsAspect);
+	convertTextureInformation(init.m_format, m_compressed, m_glFormat, m_internalFormat, m_glType, m_dsAspect);
 
 	if(m_target != GL_TEXTURE_3D)
 	{
-		m_mipsCount = min<U>(init.m_mipmapsCount, computeMaxMipmapCount2d(m_width, m_height));
+		m_mipCount = min<U>(init.m_mipmapsCount, computeMaxMipmapCount2d(m_width, m_height));
 	}
 	else
 	{
-		m_mipsCount = min<U>(init.m_mipmapsCount, computeMaxMipmapCount3d(m_width, m_height, m_depth));
+		m_mipCount = min<U>(init.m_mipmapsCount, computeMaxMipmapCount3d(m_width, m_height, m_depth));
 	}
 
 	// Surface count
@@ -183,16 +186,16 @@ void TextureImpl::init(const TextureInitInfo& init)
 	{
 	case GL_TEXTURE_2D:
 	case GL_TEXTURE_CUBE_MAP:
-		glTexStorage2D(m_target, m_mipsCount, m_internalFormat, m_width, m_height);
+		glTexStorage2D(m_target, m_mipCount, m_internalFormat, m_width, m_height);
 		break;
 	case GL_TEXTURE_CUBE_MAP_ARRAY:
-		glTexStorage3D(m_target, m_mipsCount, m_internalFormat, m_width, m_height, m_layerCount * 6);
+		glTexStorage3D(m_target, m_mipCount, m_internalFormat, m_width, m_height, m_layerCount * 6);
 		break;
 	case GL_TEXTURE_2D_ARRAY:
-		glTexStorage3D(m_target, m_mipsCount, m_internalFormat, m_width, m_height, m_layerCount);
+		glTexStorage3D(m_target, m_mipCount, m_internalFormat, m_width, m_height, m_layerCount);
 		break;
 	case GL_TEXTURE_3D:
-		glTexStorage3D(m_target, m_mipsCount, m_internalFormat, m_width, m_height, m_depth);
+		glTexStorage3D(m_target, m_mipCount, m_internalFormat, m_width, m_height, m_depth);
 		break;
 	case GL_TEXTURE_2D_MULTISAMPLE:
 		glTexStorage2DMultisample(m_target, init.m_samples, m_internalFormat, m_width, m_height, GL_FALSE);
@@ -218,7 +221,7 @@ void TextureImpl::init(const TextureInitInfo& init)
 		}
 
 		// Make sure that the texture is complete
-		glTexParameteri(m_target, GL_TEXTURE_MAX_LEVEL, m_mipsCount - 1);
+		glTexParameteri(m_target, GL_TEXTURE_MAX_LEVEL, m_mipCount - 1);
 
 		// Set filtering type
 		GLenum minFilter = GL_NONE;
@@ -269,33 +272,34 @@ void TextureImpl::writeSurface(const TextureSurfaceInfo& surf, GLuint pbo, PtrSi
 	case GL_TEXTURE_2D:
 		if(!m_compressed)
 		{
-			glTexSubImage2D(m_target, mipmap, 0, 0, w, h, m_format, m_type, ptrOffset);
+			glTexSubImage2D(m_target, mipmap, 0, 0, w, h, m_glFormat, m_glType, ptrOffset);
 		}
 		else
 		{
-			glCompressedTexSubImage2D(m_target, mipmap, 0, 0, w, h, m_format, dataSize, ptrOffset);
+			glCompressedTexSubImage2D(m_target, mipmap, 0, 0, w, h, m_glFormat, dataSize, ptrOffset);
 		}
 		break;
 	case GL_TEXTURE_CUBE_MAP:
 		if(!m_compressed)
 		{
-			glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + surfIdx, mipmap, 0, 0, w, h, m_format, m_type, ptrOffset);
+			glTexSubImage2D(
+				GL_TEXTURE_CUBE_MAP_POSITIVE_X + surfIdx, mipmap, 0, 0, w, h, m_glFormat, m_glType, ptrOffset);
 		}
 		else
 		{
 			glCompressedTexSubImage2D(
-				GL_TEXTURE_CUBE_MAP_POSITIVE_X + surfIdx, mipmap, 0, 0, w, h, m_format, dataSize, ptrOffset);
+				GL_TEXTURE_CUBE_MAP_POSITIVE_X + surfIdx, mipmap, 0, 0, w, h, m_glFormat, dataSize, ptrOffset);
 		}
 		break;
 	case GL_TEXTURE_2D_ARRAY:
 	case GL_TEXTURE_3D:
 		if(!m_compressed)
 		{
-			glTexSubImage3D(m_target, mipmap, 0, 0, surfIdx, w, h, 1, m_format, m_type, ptrOffset);
+			glTexSubImage3D(m_target, mipmap, 0, 0, surfIdx, w, h, 1, m_glFormat, m_glType, ptrOffset);
 		}
 		else
 		{
-			glCompressedTexSubImage3D(m_target, mipmap, 0, 0, surfIdx, w, h, 1, m_format, dataSize, ptrOffset);
+			glCompressedTexSubImage3D(m_target, mipmap, 0, 0, surfIdx, w, h, 1, m_glFormat, dataSize, ptrOffset);
 		}
 		break;
 	default:
@@ -306,7 +310,7 @@ void TextureImpl::writeSurface(const TextureSurfaceInfo& surf, GLuint pbo, PtrSi
 	ANKI_CHECK_GL_ERROR();
 }
 
-void TextureImpl::writeVolume(const TextureVolumeInfo& vol, GLuint pbo, PtrSize offset, PtrSize dataSize)
+void TextureImpl::writeVolume(const TextureVolumeInfo& vol, GLuint pbo, PtrSize offset, PtrSize dataSize) const
 {
 	checkSurfaceOrVolume(vol);
 	ANKI_ASSERT(dataSize > 0);
@@ -326,11 +330,11 @@ void TextureImpl::writeVolume(const TextureVolumeInfo& vol, GLuint pbo, PtrSize
 
 	if(!m_compressed)
 	{
-		glTexSubImage3D(m_target, mipmap, 0, 0, 0, w, h, d, m_format, m_type, ptrOffset);
+		glTexSubImage3D(m_target, mipmap, 0, 0, 0, w, h, d, m_glFormat, m_glType, ptrOffset);
 	}
 	else
 	{
-		glCompressedTexSubImage3D(m_target, mipmap, 0, 0, 0, w, h, d, m_format, dataSize, ptrOffset);
+		glCompressedTexSubImage3D(m_target, mipmap, 0, 0, 0, w, h, d, m_glFormat, dataSize, ptrOffset);
 	}
 
 	glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
@@ -369,7 +373,7 @@ void TextureImpl::generateMipmaps2d(U face, U layer)
 				ANKI_ASSERT(0);
 			}
 
-			glTextureView(m_texViews[surface], target, m_glName, m_internalFormat, 0, m_mipsCount, surface, 1);
+			glTextureView(m_texViews[surface], target, m_glName, m_internalFormat, 0, m_mipCount, surface, 1);
 		}
 
 		glGenerateTextureMipmap(m_texViews[surface]);
@@ -386,8 +390,8 @@ void TextureImpl::copy(const TextureImpl& src,
 	const TextureSurfaceInfo& destSurf)
 {
 	ANKI_ASSERT(src.m_internalFormat == dest.m_internalFormat);
-	ANKI_ASSERT(src.m_format == dest.m_format);
-	ANKI_ASSERT(src.m_type == dest.m_type);
+	ANKI_ASSERT(src.m_glFormat == dest.m_glFormat);
+	ANKI_ASSERT(src.m_glType == dest.m_glType);
 
 	U width = src.m_width >> srcSurf.m_level;
 	U height = src.m_height >> srcSurf.m_level;
@@ -418,29 +422,29 @@ void TextureImpl::copy(const TextureImpl& src,
 void TextureImpl::clear(const TextureSurfaceInfo& surf, const ClearValue& clearValue, DepthStencilAspectBit aspect)
 {
 	ANKI_ASSERT(isCreated());
-	ANKI_ASSERT(surf.m_level < m_mipsCount);
+	ANKI_ASSERT(surf.m_level < m_mipCount);
 	ANKI_ASSERT((aspect & m_dsAspect) == aspect);
 
 	// Find the aspect to clear
 	GLenum format;
 	if(aspect == DepthStencilAspectBit::DEPTH)
 	{
-		ANKI_ASSERT(m_format == GL_DEPTH_COMPONENT || m_format == GL_DEPTH_STENCIL);
+		ANKI_ASSERT(m_glFormat == GL_DEPTH_COMPONENT || m_glFormat == GL_DEPTH_STENCIL);
 		format = GL_DEPTH_COMPONENT;
 	}
 	else if(aspect == DepthStencilAspectBit::STENCIL)
 	{
-		ANKI_ASSERT(m_format == GL_STENCIL_INDEX || m_format == GL_DEPTH_STENCIL);
+		ANKI_ASSERT(m_glFormat == GL_STENCIL_INDEX || m_glFormat == GL_DEPTH_STENCIL);
 		format = GL_STENCIL_INDEX;
 	}
 	else if(aspect == DepthStencilAspectBit::DEPTH_STENCIL)
 	{
-		ANKI_ASSERT(m_format == GL_DEPTH_STENCIL);
+		ANKI_ASSERT(m_glFormat == GL_DEPTH_STENCIL);
 		format = GL_DEPTH_STENCIL;
 	}
 	else
 	{
-		format = m_format;
+		format = m_glFormat;
 	}
 
 	U surfaceIdx = computeSurfaceIdx(surf);

+ 9 - 15
src/anki/gr/gl/TextureImpl.h

@@ -5,6 +5,7 @@
 
 #pragma once
 
+#include <anki/gr/Texture.h>
 #include <anki/gr/gl/GlObject.h>
 #include <anki/gr/common/Misc.h>
 #include <anki/util/DynamicArray.h>
@@ -16,28 +17,21 @@ namespace anki
 /// @{
 
 /// Texture container.
-class TextureImpl : public GlObject
+class TextureImpl final : public Texture, public GlObject
 {
 public:
 	GLenum m_target = GL_NONE; ///< GL_TEXTURE_2D, GL_TEXTURE_3D... etc
 	GLenum m_internalFormat = GL_NONE; ///< GL_COMPRESSED_RED, GL_RGB16 etc
-	GLenum m_format = GL_NONE;
-	GLenum m_type = GL_NONE;
-	TextureType m_texType = TextureType::_1D;
-	U32 m_width = 0;
-	U32 m_height = 0;
-	U32 m_depth = 0;
-	U32 m_layerCount = 0;
+	GLenum m_glFormat = GL_NONE;
+	GLenum m_glType = GL_NONE;
 	U32 m_surfaceCountPerLevel = 0;
-	U8 m_mipsCount = 0;
 	U8 m_faceCount = 0; ///< 6 for cubes and 1 for the rest
 	Bool8 m_compressed = false;
-	PixelFormat m_pformat;
 	DynamicArray<GLuint> m_texViews; ///< Temp views for gen mips.
 	DepthStencilAspectBit m_dsAspect = DepthStencilAspectBit::NONE;
 
 	TextureImpl(GrManager* manager)
-		: GlObject(manager)
+		: Texture(manager)
 	{
 	}
 
@@ -45,13 +39,13 @@ public:
 
 	void checkSurfaceOrVolume(const TextureSurfaceInfo& surf) const
 	{
-		checkTextureSurface(m_texType, m_depth, m_mipsCount, m_layerCount, surf);
+		checkTextureSurface(m_texType, m_depth, m_mipCount, m_layerCount, surf);
 	}
 
 	void checkSurfaceOrVolume(const TextureVolumeInfo& vol) const
 	{
 		ANKI_ASSERT(m_texType == TextureType::_3D);
-		ANKI_ASSERT(vol.m_level < m_mipsCount);
+		ANKI_ASSERT(vol.m_level < m_mipCount);
 	}
 
 	/// Init some stuff.
@@ -64,7 +58,7 @@ public:
 	void writeSurface(const TextureSurfaceInfo& surf, GLuint pbo, PtrSize offset, PtrSize dataSize);
 
 	/// Write texture data.
-	void writeVolume(const TextureVolumeInfo& vol, GLuint pbo, PtrSize offset, PtrSize dataSize);
+	void writeVolume(const TextureVolumeInfo& vol, GLuint pbo, PtrSize offset, PtrSize dataSize) const;
 
 	/// Generate mipmaps.
 	void generateMipmaps2d(U face, U layer);
@@ -75,7 +69,7 @@ public:
 		const TextureImpl& dest,
 		const TextureSurfaceInfo& destSurf);
 
-	void bind();
+	void bind() const;
 
 	void clear(const TextureSurfaceInfo& surf, const ClearValue& clearValue, DepthStencilAspectBit aspect);
 

+ 7 - 18
src/anki/gr/vulkan/Buffer.cpp

@@ -5,37 +5,26 @@
 
 #include <anki/gr/Buffer.h>
 #include <anki/gr/vulkan/BufferImpl.h>
+#include <anki/gr/GrManager.h>
 
 namespace anki
 {
 
-Buffer::Buffer(GrManager* manager)
-	: GrObject(manager, CLASS_TYPE)
+Buffer* Buffer::newInstance(GrManager* manager, const BufferInitInfo& init)
 {
-}
-
-Buffer::~Buffer()
-{
-}
-
-void Buffer::init(const BufferInitInfo& inf)
-{
-	m_impl.reset(getAllocator().newInstance<BufferImpl>(&getManager()));
-
-	if(m_impl->init(inf))
-	{
-		ANKI_VK_LOGF("Cannot recover");
-	}
+	return BufferImpl::newInstanceHelper(manager, init);
 }
 
 void* Buffer::map(PtrSize offset, PtrSize range, BufferMapAccessBit access)
 {
-	return m_impl->map(offset, range, access);
+	ANKI_VK_SELF(BufferImpl);
+	return self.map(offset, range, access);
 }
 
 void Buffer::unmap()
 {
-	m_impl->unmap();
+	ANKI_VK_SELF(BufferImpl);
+	self.unmap();
 }
 
 } // end namespace anki

+ 3 - 5
src/anki/gr/vulkan/BufferImpl.h

@@ -5,6 +5,7 @@
 
 #pragma once
 
+#include <anki/gr/Buffer.h>
 #include <anki/gr/vulkan/VulkanObject.h>
 #include <anki/gr/vulkan/GpuMemoryManager.h>
 
@@ -15,11 +16,11 @@ namespace anki
 /// @{
 
 /// Buffer implementation
-class BufferImpl : public VulkanObject
+class BufferImpl final : public Buffer, public VulkanObject<Buffer, BufferImpl>
 {
 public:
 	BufferImpl(GrManager* manager)
-		: VulkanObject(manager)
+		: Buffer(manager)
 	{
 	}
 
@@ -67,10 +68,7 @@ public:
 private:
 	VkBuffer m_handle = VK_NULL_HANDLE;
 	GpuMemoryHandle m_memHandle;
-	BufferMapAccessBit m_access = BufferMapAccessBit::NONE;
-	U32 m_size = 0;
 	VkMemoryPropertyFlags m_memoryFlags = 0;
-	BufferUsageBit m_usage = BufferUsageBit::NONE;
 
 #if ANKI_EXTRA_CHECKS
 	Bool8 m_mapped = false;

+ 108 - 71
src/anki/gr/vulkan/CommandBuffer.cpp

@@ -10,23 +10,9 @@
 namespace anki
 {
 
-CommandBuffer::CommandBuffer(GrManager* manager)
-	: GrObject(manager, CLASS_TYPE)
+CommandBuffer* CommandBuffer::newInstance(GrManager* manager, const CommandBufferInitInfo& init)
 {
-}
-
-CommandBuffer::~CommandBuffer()
-{
-}
-
-void CommandBuffer::init(CommandBufferInitInfo& inf)
-{
-	m_impl.reset(getAllocator().newInstance<CommandBufferImpl>(&getManager()));
-
-	if(m_impl->init(inf))
-	{
-		ANKI_VK_LOGF("Cannot recover");
-	}
+	return CommandBufferImpl::newInstanceHelper(manager, init);
 }
 
 CommandBufferInitHints CommandBuffer::computeInitHints() const
@@ -38,11 +24,12 @@ CommandBufferInitHints CommandBuffer::computeInitHints() const
 
 void CommandBuffer::flush(FencePtr* fence)
 {
-	m_impl->endRecording();
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.endRecording();
 
-	if(!m_impl->isSecondLevel())
+	if(!self.isSecondLevel())
 	{
-		m_impl->getGrManagerImpl().flushCommandBuffer(CommandBufferPtr(this), fence);
+		self.getGrManagerImpl().flushCommandBuffer(CommandBufferPtr(this), fence);
 	}
 	else
 	{
@@ -52,58 +39,68 @@ void CommandBuffer::flush(FencePtr* fence)
 
 void CommandBuffer::finish()
 {
-	m_impl->endRecording();
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.endRecording();
 
-	if(!m_impl->isSecondLevel())
+	if(!self.isSecondLevel())
 	{
-		m_impl->getGrManagerImpl().finishCommandBuffer(CommandBufferPtr(this));
+		self.getGrManagerImpl().finishCommandBuffer(CommandBufferPtr(this));
 	}
 }
 
 void CommandBuffer::bindVertexBuffer(
 	U32 binding, BufferPtr buff, PtrSize offset, PtrSize stride, VertexStepRate stepRate)
 {
-	m_impl->bindVertexBuffer(binding, buff, offset, stride, stepRate);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.bindVertexBuffer(binding, buff, offset, stride, stepRate);
 }
 
 void CommandBuffer::setVertexAttribute(U32 location, U32 buffBinding, const PixelFormat& fmt, PtrSize relativeOffset)
 {
-	m_impl->setVertexAttribute(location, buffBinding, fmt, relativeOffset);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.setVertexAttribute(location, buffBinding, fmt, relativeOffset);
 }
 
 void CommandBuffer::bindIndexBuffer(BufferPtr buff, PtrSize offset, IndexType type)
 {
-	m_impl->bindIndexBuffer(buff, offset, type);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.bindIndexBuffer(buff, offset, type);
 }
 
 void CommandBuffer::setPrimitiveRestart(Bool enable)
 {
-	m_impl->setPrimitiveRestart(enable);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.setPrimitiveRestart(enable);
 }
 
 void CommandBuffer::setViewport(U32 minx, U32 miny, U32 width, U32 height)
 {
-	m_impl->setViewport(minx, miny, width, height);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.setViewport(minx, miny, width, height);
 }
 
 void CommandBuffer::setScissor(U32 minx, U32 miny, U32 width, U32 height)
 {
-	m_impl->setScissor(minx, miny, width, height);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.setScissor(minx, miny, width, height);
 }
 
 void CommandBuffer::setFillMode(FillMode mode)
 {
-	m_impl->setFillMode(mode);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.setFillMode(mode);
 }
 
 void CommandBuffer::setCullMode(FaceSelectionBit mode)
 {
-	m_impl->setCullMode(mode);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.setCullMode(mode);
 }
 
 void CommandBuffer::setPolygonOffset(F32 factor, F32 units)
 {
-	m_impl->setPolygonOffset(factor, units);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.setPolygonOffset(factor, units);
 }
 
 void CommandBuffer::setStencilOperations(FaceSelectionBit face,
@@ -111,85 +108,101 @@ void CommandBuffer::setStencilOperations(FaceSelectionBit face,
 	StencilOperation stencilPassDepthFail,
 	StencilOperation stencilPassDepthPass)
 {
-	m_impl->setStencilOperations(face, stencilFail, stencilPassDepthFail, stencilPassDepthPass);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.setStencilOperations(face, stencilFail, stencilPassDepthFail, stencilPassDepthPass);
 }
 
 void CommandBuffer::setStencilCompareOperation(FaceSelectionBit face, CompareOperation comp)
 {
-	m_impl->setStencilCompareOperation(face, comp);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.setStencilCompareOperation(face, comp);
 }
 
 void CommandBuffer::setStencilCompareMask(FaceSelectionBit face, U32 mask)
 {
-	m_impl->setStencilCompareMask(face, mask);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.setStencilCompareMask(face, mask);
 }
 
 void CommandBuffer::setStencilWriteMask(FaceSelectionBit face, U32 mask)
 {
-	m_impl->setStencilWriteMask(face, mask);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.setStencilWriteMask(face, mask);
 }
 
 void CommandBuffer::setStencilReference(FaceSelectionBit face, U32 ref)
 {
-	m_impl->setStencilReference(face, ref);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.setStencilReference(face, ref);
 }
 
 void CommandBuffer::setDepthWrite(Bool enable)
 {
-	m_impl->setDepthWrite(enable);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.setDepthWrite(enable);
 }
 
 void CommandBuffer::setDepthCompareOperation(CompareOperation op)
 {
-	m_impl->setDepthCompareOperation(op);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.setDepthCompareOperation(op);
 }
 
 void CommandBuffer::setAlphaToCoverage(Bool enable)
 {
-	m_impl->setAlphaToCoverage(enable);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.setAlphaToCoverage(enable);
 }
 
 void CommandBuffer::setColorChannelWriteMask(U32 attachment, ColorBit mask)
 {
-	m_impl->setColorChannelWriteMask(attachment, mask);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.setColorChannelWriteMask(attachment, mask);
 }
 
 void CommandBuffer::setBlendFactors(
 	U32 attachment, BlendFactor srcRgb, BlendFactor dstRgb, BlendFactor srcA, BlendFactor dstA)
 {
-	m_impl->setBlendFactors(attachment, srcRgb, dstRgb, srcA, dstA);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.setBlendFactors(attachment, srcRgb, dstRgb, srcA, dstA);
 }
 
 void CommandBuffer::setBlendOperation(U32 attachment, BlendOperation funcRgb, BlendOperation funcA)
 {
-	m_impl->setBlendOperation(attachment, funcRgb, funcA);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.setBlendOperation(attachment, funcRgb, funcA);
 }
 
 void CommandBuffer::bindTexture(
 	U32 set, U32 binding, TexturePtr tex, TextureUsageBit usage, DepthStencilAspectBit aspect)
 {
-	m_impl->bindTexture(set, binding, tex, usage, aspect);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.bindTexture(set, binding, tex, usage, aspect);
 }
 
 void CommandBuffer::bindTextureAndSampler(
 	U32 set, U32 binding, TexturePtr tex, SamplerPtr sampler, TextureUsageBit usage, DepthStencilAspectBit aspect)
 {
-	m_impl->bindTextureAndSampler(set, binding, tex, sampler, usage, aspect);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.bindTextureAndSampler(set, binding, tex, sampler, usage, aspect);
 }
 
 void CommandBuffer::bindUniformBuffer(U32 set, U32 binding, BufferPtr buff, PtrSize offset, PtrSize range)
 {
-	m_impl->bindUniformBuffer(set, binding, buff, offset, range);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.bindUniformBuffer(set, binding, buff, offset, range);
 }
 
 void CommandBuffer::bindStorageBuffer(U32 set, U32 binding, BufferPtr buff, PtrSize offset, PtrSize range)
 {
-	m_impl->bindStorageBuffer(set, binding, buff, offset, range);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.bindStorageBuffer(set, binding, buff, offset, range);
 }
 
 void CommandBuffer::bindImage(U32 set, U32 binding, TexturePtr img, U32 level)
 {
-	m_impl->bindImage(set, binding, img, level);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.bindImage(set, binding, img, level);
 }
 
 void CommandBuffer::bindTextureBuffer(
@@ -200,7 +213,8 @@ void CommandBuffer::bindTextureBuffer(
 
 void CommandBuffer::bindShaderProgram(ShaderProgramPtr prog)
 {
-	m_impl->bindShaderProgram(prog);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.bindShaderProgram(prog);
 }
 
 void CommandBuffer::beginRenderPass(FramebufferPtr fb,
@@ -211,43 +225,51 @@ void CommandBuffer::beginRenderPass(FramebufferPtr fb,
 	U32 width,
 	U32 height)
 {
-	m_impl->beginRenderPass(fb, colorAttachmentUsages, depthStencilAttachmentUsage, minx, miny, width, height);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.beginRenderPass(fb, colorAttachmentUsages, depthStencilAttachmentUsage, minx, miny, width, height);
 }
 
 void CommandBuffer::endRenderPass()
 {
-	m_impl->endRenderPass();
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.endRenderPass();
 }
 
 void CommandBuffer::drawElements(
 	PrimitiveTopology topology, U32 count, U32 instanceCount, U32 firstIndex, U32 baseVertex, U32 baseInstance)
 {
-	m_impl->drawElements(topology, count, instanceCount, firstIndex, baseVertex, baseInstance);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.drawElements(topology, count, instanceCount, firstIndex, baseVertex, baseInstance);
 }
 
 void CommandBuffer::drawArrays(PrimitiveTopology topology, U32 count, U32 instanceCount, U32 first, U32 baseInstance)
 {
-	m_impl->drawArrays(topology, count, instanceCount, first, baseInstance);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.drawArrays(topology, count, instanceCount, first, baseInstance);
 }
 
 void CommandBuffer::drawArraysIndirect(PrimitiveTopology topology, U32 drawCount, PtrSize offset, BufferPtr buff)
 {
-	m_impl->drawArraysIndirect(topology, drawCount, offset, buff);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.drawArraysIndirect(topology, drawCount, offset, buff);
 }
 
 void CommandBuffer::drawElementsIndirect(PrimitiveTopology topology, U32 drawCount, PtrSize offset, BufferPtr buff)
 {
-	m_impl->drawElementsIndirect(topology, drawCount, offset, buff);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.drawElementsIndirect(topology, drawCount, offset, buff);
 }
 
 void CommandBuffer::dispatchCompute(U32 groupCountX, U32 groupCountY, U32 groupCountZ)
 {
-	m_impl->dispatchCompute(groupCountX, groupCountY, groupCountZ);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.dispatchCompute(groupCountX, groupCountY, groupCountZ);
 }
 
 void CommandBuffer::generateMipmaps2d(TexturePtr tex, U face, U layer)
 {
-	m_impl->generateMipmaps2d(tex, face, layer);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.generateMipmaps2d(tex, face, layer);
 }
 
 void CommandBuffer::generateMipmaps3d(TexturePtr tex)
@@ -270,84 +292,99 @@ void CommandBuffer::copyTextureVolumeToTextureVolume(
 void CommandBuffer::clearTextureSurface(
 	TexturePtr tex, const TextureSurfaceInfo& surf, const ClearValue& clearValue, DepthStencilAspectBit aspect)
 {
-	m_impl->clearTextureSurface(tex, surf, clearValue, aspect);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.clearTextureSurface(tex, surf, clearValue, aspect);
 }
 
 void CommandBuffer::clearTextureVolume(
 	TexturePtr tex, const TextureVolumeInfo& vol, const ClearValue& clearValue, DepthStencilAspectBit aspect)
 {
-	m_impl->clearTextureVolume(tex, vol, clearValue, aspect);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.clearTextureVolume(tex, vol, clearValue, aspect);
 }
 
 void CommandBuffer::copyBufferToTextureSurface(
 	BufferPtr buff, PtrSize offset, PtrSize range, TexturePtr tex, const TextureSurfaceInfo& surf)
 {
-	m_impl->copyBufferToTextureSurface(buff, offset, range, tex, surf);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.copyBufferToTextureSurface(buff, offset, range, tex, surf);
 }
 
 void CommandBuffer::copyBufferToTextureVolume(
 	BufferPtr buff, PtrSize offset, PtrSize range, TexturePtr tex, const TextureVolumeInfo& vol)
 {
-	m_impl->copyBufferToTextureVolume(buff, offset, range, tex, vol);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.copyBufferToTextureVolume(buff, offset, range, tex, vol);
 }
 
 void CommandBuffer::fillBuffer(BufferPtr buff, PtrSize offset, PtrSize size, U32 value)
 {
-	m_impl->fillBuffer(buff, offset, size, value);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.fillBuffer(buff, offset, size, value);
 }
 
 void CommandBuffer::writeOcclusionQueryResultToBuffer(OcclusionQueryPtr query, PtrSize offset, BufferPtr buff)
 {
-	m_impl->writeOcclusionQueryResultToBuffer(query, offset, buff);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.writeOcclusionQueryResultToBuffer(query, offset, buff);
 }
 
 void CommandBuffer::copyBufferToBuffer(
 	BufferPtr src, PtrSize srcOffset, BufferPtr dst, PtrSize dstOffset, PtrSize range)
 {
-	m_impl->copyBufferToBuffer(src, srcOffset, dst, dstOffset, range);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.copyBufferToBuffer(src, srcOffset, dst, dstOffset, range);
 }
 
 void CommandBuffer::setTextureSurfaceBarrier(
 	TexturePtr tex, TextureUsageBit prevUsage, TextureUsageBit nextUsage, const TextureSurfaceInfo& surf)
 {
-	m_impl->setTextureSurfaceBarrier(tex, prevUsage, nextUsage, surf);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.setTextureSurfaceBarrier(tex, prevUsage, nextUsage, surf);
 }
 
 void CommandBuffer::setTextureVolumeBarrier(
 	TexturePtr tex, TextureUsageBit prevUsage, TextureUsageBit nextUsage, const TextureVolumeInfo& vol)
 {
-	m_impl->setTextureVolumeBarrier(tex, prevUsage, nextUsage, vol);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.setTextureVolumeBarrier(tex, prevUsage, nextUsage, vol);
 }
 
 void CommandBuffer::setBufferBarrier(
 	BufferPtr buff, BufferUsageBit before, BufferUsageBit after, PtrSize offset, PtrSize size)
 {
-	m_impl->setBufferBarrier(buff, before, after, offset, size);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.setBufferBarrier(buff, before, after, offset, size);
 }
 
 void CommandBuffer::resetOcclusionQuery(OcclusionQueryPtr query)
 {
-	m_impl->resetOcclusionQuery(query);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.resetOcclusionQuery(query);
 }
 
 void CommandBuffer::beginOcclusionQuery(OcclusionQueryPtr query)
 {
-	m_impl->beginOcclusionQuery(query);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.beginOcclusionQuery(query);
 }
 
 void CommandBuffer::endOcclusionQuery(OcclusionQueryPtr query)
 {
-	m_impl->endOcclusionQuery(query);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.endOcclusionQuery(query);
 }
 
 void CommandBuffer::pushSecondLevelCommandBuffer(CommandBufferPtr cmdb)
 {
-	m_impl->pushSecondLevelCommandBuffer(cmdb);
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.pushSecondLevelCommandBuffer(cmdb);
 }
 
 Bool CommandBuffer::isEmpty() const
 {
-	return m_impl->isEmpty();
+	ANKI_VK_SELF_CONST(CommandBufferImpl);
+	return self.isEmpty();
 }
 
 } // end namespace anki

+ 60 - 46
src/anki/gr/vulkan/CommandBufferImpl.cpp

@@ -15,11 +15,6 @@
 namespace anki
 {
 
-CommandBufferImpl::CommandBufferImpl(GrManager* manager)
-	: VulkanObject(manager)
-{
-}
-
 CommandBufferImpl::~CommandBufferImpl()
 {
 	if(m_empty)
@@ -66,20 +61,23 @@ void CommandBufferImpl::beginRecording()
 
 	if(!!(m_flags & CommandBufferFlag::SECOND_LEVEL))
 	{
-		FramebufferImpl& impl = *m_activeFb->m_impl;
+		FramebufferImpl& impl = static_cast<FramebufferImpl&>(*m_activeFb);
 		impl.sync();
 
 		// Calc the layouts
 		Array<VkImageLayout, MAX_COLOR_ATTACHMENTS> colAttLayouts;
 		for(U i = 0; i < impl.getColorAttachmentCount(); ++i)
 		{
-			colAttLayouts[i] = impl.getColorAttachment(i)->m_impl->computeLayout(m_colorAttachmentUsages[i], 0);
+			colAttLayouts[i] = static_cast<const TextureImpl&>(
+				*impl.getColorAttachment(
+					i)).computeLayout(m_colorAttachmentUsages[i], 0);
 		}
 
 		VkImageLayout dsAttLayout = VK_IMAGE_LAYOUT_MAX_ENUM;
 		if(impl.hasDepthStencil())
 		{
-			dsAttLayout = impl.getDepthStencilAttachment()->m_impl->computeLayout(m_depthStencilAttachmentUsage, 0);
+			dsAttLayout = static_cast<const TextureImpl&>(*impl.getDepthStencilAttachment())
+							  .computeLayout(m_depthStencilAttachmentUsage, 0);
 		}
 
 		inheritance.renderPass = impl.getRenderPassHandle(colAttLayouts, dsAttLayout);
@@ -118,10 +116,11 @@ void CommandBufferImpl::beginRenderPass(FramebufferPtr fb,
 	m_rpCommandCount = 0;
 	m_activeFb = fb;
 
-	fb->m_impl->sync();
+	FramebufferImpl& fbimpl = static_cast<FramebufferImpl&>(*fb);
+	fbimpl.sync();
 
 	U32 fbWidth, fbHeight;
-	fb->m_impl->getAttachmentsSize(fbWidth, fbHeight);
+	fbimpl.getAttachmentsSize(fbWidth, fbHeight);
 	m_fbSize[0] = fbWidth;
 	m_fbSize[1] = fbHeight;
 
@@ -154,7 +153,7 @@ void CommandBufferImpl::beginRenderPassInternal()
 {
 	m_state.beginRenderPass(m_activeFb);
 
-	FramebufferImpl& impl = *m_activeFb->m_impl;
+	FramebufferImpl& impl = static_cast<FramebufferImpl&>(*m_activeFb);
 
 	VkRenderPassBeginInfo bi = {};
 	bi.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
@@ -171,13 +170,16 @@ void CommandBufferImpl::beginRenderPassInternal()
 		Array<VkImageLayout, MAX_COLOR_ATTACHMENTS> colAttLayouts;
 		for(U i = 0; i < impl.getColorAttachmentCount(); ++i)
 		{
-			colAttLayouts[i] = impl.getColorAttachment(i)->m_impl->computeLayout(m_colorAttachmentUsages[i], 0);
+			colAttLayouts[i] = static_cast<const TextureImpl&>(
+				*impl.getColorAttachment(
+					i)).computeLayout(m_colorAttachmentUsages[i], 0);
 		}
 
 		VkImageLayout dsAttLayout = VK_IMAGE_LAYOUT_MAX_ENUM;
 		if(impl.hasDepthStencil())
 		{
-			dsAttLayout = impl.getDepthStencilAttachment()->m_impl->computeLayout(m_depthStencilAttachmentUsage, 0);
+			dsAttLayout = static_cast<const TextureImpl&>(*impl.getDepthStencilAttachment())
+							  .computeLayout(m_depthStencilAttachmentUsage, 0);
 		}
 
 		bi.renderPass = impl.getRenderPassHandle(colAttLayouts, dsAttLayout);
@@ -231,11 +233,11 @@ void CommandBufferImpl::endRenderPass()
 	ANKI_CMD(vkCmdEndRenderPass(m_handle), ANY_OTHER_COMMAND);
 
 	// Default FB barrier/transition
-	if(m_activeFb->m_impl->isDefaultFramebuffer())
+	if(static_cast<const FramebufferImpl&>(*m_activeFb).isDefaultFramebuffer())
 	{
 		MicroSwapchainPtr swapchain;
 		U32 backbufferIdx;
-		m_activeFb->m_impl->getDefaultFramebufferInfo(swapchain, backbufferIdx);
+		static_cast<const FramebufferImpl&>(*m_activeFb).getDefaultFramebufferInfo(swapchain, backbufferIdx);
 
 		setImageBarrier(VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
 			VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
@@ -289,10 +291,10 @@ void CommandBufferImpl::generateMipmaps2d(TexturePtr tex, U face, U layer)
 {
 	commandCommon();
 
-	const TextureImpl& impl = *tex->m_impl;
-	ANKI_ASSERT(impl.m_type != TextureType::_3D && "Not for 3D");
+	const TextureImpl& impl = static_cast<const TextureImpl&>(*tex);
+	ANKI_ASSERT(impl.getTextureType() != TextureType::_3D && "Not for 3D");
 
-	for(U i = 0; i < impl.m_mipCount - 1u; ++i)
+	for(U i = 0; i < impl.getMipmapCount() - 1u; ++i)
 	{
 		// Transition source
 		if(i > 0)
@@ -326,16 +328,16 @@ void CommandBufferImpl::generateMipmaps2d(TexturePtr tex, U face, U layer)
 		}
 
 		// Setup the blit struct
-		I32 srcWidth = impl.m_width >> i;
-		I32 srcHeight = impl.m_height >> i;
+		I32 srcWidth = impl.getWidth() >> i;
+		I32 srcHeight = impl.getHeight() >> i;
 
-		I32 dstWidth = impl.m_width >> (i + 1);
-		I32 dstHeight = impl.m_height >> (i + 1);
+		I32 dstWidth = impl.getWidth() >> (i + 1);
+		I32 dstHeight = impl.getHeight() >> (i + 1);
 
 		ANKI_ASSERT(srcWidth > 0 && srcHeight > 0 && dstWidth > 0 && dstHeight > 0);
 
 		U vkLayer = 0;
-		switch(impl.m_type)
+		switch(impl.getTextureType())
 		{
 		case TextureType::_2D:
 		case TextureType::_2D_ARRAY:
@@ -645,16 +647,16 @@ void CommandBufferImpl::copyBufferToTextureSurface(
 {
 	commandCommon();
 
-	TextureImpl& impl = *tex->m_impl;
+	const TextureImpl& impl = static_cast<const TextureImpl&>(*tex);
 	impl.checkSurfaceOrVolume(surf);
 	ANKI_ASSERT(impl.usageValid(TextureUsageBit::TRANSFER_DESTINATION));
 	const VkImageLayout layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
 
 	if(!impl.m_workarounds)
 	{
-		U width = impl.m_width >> surf.m_level;
-		U height = impl.m_height >> surf.m_level;
-		ANKI_ASSERT(range == computeSurfaceSize(width, height, impl.m_format));
+		U width = impl.getWidth() >> surf.m_level;
+		U height = impl.getHeight() >> surf.m_level;
+		ANKI_ASSERT(range == computeSurfaceSize(width, height, impl.getPixelFormat()));
 
 		// Copy
 		VkBufferImageCopy region;
@@ -670,20 +672,22 @@ void CommandBufferImpl::copyBufferToTextureSurface(
 		region.bufferImageHeight = 0;
 		region.bufferRowLength = 0;
 
-		ANKI_CMD(vkCmdCopyBufferToImage(m_handle, buff->m_impl->getHandle(), impl.m_imageHandle, layout, 1, &region),
+		ANKI_CMD(
+			vkCmdCopyBufferToImage(
+				m_handle, static_cast<const BufferImpl&>(*buff).getHandle(), impl.m_imageHandle, layout, 1, &region),
 			ANY_OTHER_COMMAND);
 	}
 	else if(!!(impl.m_workarounds & TextureImplWorkaround::R8G8B8_TO_R8G8B8A8))
 	{
-		U width = impl.m_width >> surf.m_level;
-		U height = impl.m_height >> surf.m_level;
+		U width = impl.getWidth() >> surf.m_level;
+		U height = impl.getHeight() >> surf.m_level;
 
 		// Create a new shadow buffer
 		const PtrSize shadowSize =
 			computeSurfaceSize(width, height, PixelFormat(ComponentFormat::R8G8B8A8, TransformFormat::UNORM));
-		BufferPtr shadow = getGrManager().newInstance<Buffer>(
+		BufferPtr shadow = getManager().newBuffer(
 			BufferInitInfo(shadowSize, BufferUsageBit::TRANSFER_ALL, BufferMapAccessBit::NONE, "Workaround"));
-		const VkBuffer shadowHandle = shadow->m_impl->getHandle();
+		const VkBuffer shadowHandle = static_cast<const BufferImpl&>(*shadow).getHandle();
 		m_microCmdb->pushObjectRef(shadow);
 
 		// Create the copy regions
@@ -702,7 +706,11 @@ void CommandBufferImpl::copyBufferToTextureSurface(
 		}
 
 		// Copy buffer to buffer
-		ANKI_CMD(vkCmdCopyBuffer(m_handle, buff->m_impl->getHandle(), shadowHandle, copies.getSize(), &copies[0]),
+		ANKI_CMD(vkCmdCopyBuffer(m_handle,
+					 static_cast<const BufferImpl&>(*buff).getHandle(),
+					 shadowHandle,
+					 copies.getSize(),
+					 &copies[0]),
 			ANY_OTHER_COMMAND);
 
 		// Set barrier
@@ -712,7 +720,7 @@ void CommandBufferImpl::copyBufferToTextureSurface(
 			VK_ACCESS_TRANSFER_READ_BIT,
 			0,
 			shadowSize,
-			shadow->m_impl->getHandle());
+			static_cast<const BufferImpl&>(*shadow).getHandle());
 
 		// Do the copy to the image
 		VkBufferImageCopy region;
@@ -745,17 +753,17 @@ void CommandBufferImpl::copyBufferToTextureVolume(
 {
 	commandCommon();
 
-	TextureImpl& impl = *tex->m_impl;
+	const TextureImpl& impl = static_cast<const TextureImpl&>(*tex);
 	impl.checkSurfaceOrVolume(vol);
 	ANKI_ASSERT(impl.usageValid(TextureUsageBit::TRANSFER_DESTINATION));
 	const VkImageLayout layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
 
 	if(!impl.m_workarounds)
 	{
-		U width = impl.m_width >> vol.m_level;
-		U height = impl.m_height >> vol.m_level;
-		U depth = impl.m_depth >> vol.m_level;
-		ANKI_ASSERT(range == computeVolumeSize(width, height, depth, impl.m_format));
+		U width = impl.getWidth() >> vol.m_level;
+		U height = impl.getHeight() >> vol.m_level;
+		U depth = impl.getDepth() >> vol.m_level;
+		ANKI_ASSERT(range == computeVolumeSize(width, height, depth, impl.getPixelFormat()));
 
 		// Copy
 		VkBufferImageCopy region;
@@ -771,22 +779,24 @@ void CommandBufferImpl::copyBufferToTextureVolume(
 		region.bufferImageHeight = 0;
 		region.bufferRowLength = 0;
 
-		ANKI_CMD(vkCmdCopyBufferToImage(m_handle, buff->m_impl->getHandle(), impl.m_imageHandle, layout, 1, &region),
+		ANKI_CMD(
+			vkCmdCopyBufferToImage(
+				m_handle, static_cast<const BufferImpl&>(*buff).getHandle(), impl.m_imageHandle, layout, 1, &region),
 			ANY_OTHER_COMMAND);
 	}
 	else if(!!(impl.m_workarounds & TextureImplWorkaround::R8G8B8_TO_R8G8B8A8))
 	{
 		// Find the offset to the RGBA staging buff
-		U width = impl.m_width >> vol.m_level;
-		U height = impl.m_height >> vol.m_level;
-		U depth = impl.m_depth >> vol.m_level;
+		U width = impl.getWidth() >> vol.m_level;
+		U height = impl.getHeight() >> vol.m_level;
+		U depth = impl.getDepth() >> vol.m_level;
 
 		// Create a new shadow buffer
 		const PtrSize shadowSize =
 			computeVolumeSize(width, height, depth, PixelFormat(ComponentFormat::R8G8B8A8, TransformFormat::UNORM));
-		BufferPtr shadow = getGrManager().newInstance<Buffer>(
+		BufferPtr shadow = getManager().newBuffer(
 			BufferInitInfo(shadowSize, BufferUsageBit::TRANSFER_ALL, BufferMapAccessBit::NONE, "Workaround"));
-		const VkBuffer shadowHandle = shadow->m_impl->getHandle();
+		const VkBuffer shadowHandle = static_cast<const BufferImpl&>(*shadow).getHandle();
 		m_microCmdb->pushObjectRef(shadow);
 
 		// Create the copy regions
@@ -808,7 +818,11 @@ void CommandBufferImpl::copyBufferToTextureVolume(
 		}
 
 		// Copy buffer to buffer
-		ANKI_CMD(vkCmdCopyBuffer(m_handle, buff->m_impl->getHandle(), shadowHandle, copies.getSize(), &copies[0]),
+		ANKI_CMD(vkCmdCopyBuffer(m_handle,
+					 static_cast<const BufferImpl&>(*buff).getHandle(),
+					 shadowHandle,
+					 copies.getSize(),
+					 &copies[0]),
 			ANY_OTHER_COMMAND);
 
 		// Set barrier

+ 18 - 10
src/anki/gr/vulkan/CommandBufferImpl.h

@@ -5,11 +5,13 @@
 
 #pragma once
 
+#include <anki/gr/CommandBuffer.h>
 #include <anki/gr/vulkan/VulkanObject.h>
 #include <anki/gr/vulkan/CommandBufferFactory.h>
 #include <anki/gr/CommandBuffer.h>
 #include <anki/gr/Texture.h>
 #include <anki/gr/Buffer.h>
+#include <anki/gr/Shader.h>
 #include <anki/gr/vulkan/BufferImpl.h>
 #include <anki/gr/vulkan/TextureImpl.h>
 #include <anki/gr/vulkan/Pipeline.h>
@@ -41,11 +43,14 @@ enum class CommandBufferCommandType : U8
 };
 
 /// Command buffer implementation.
-class CommandBufferImpl : public VulkanObject
+class CommandBufferImpl final : public CommandBuffer, public VulkanObject<CommandBuffer, CommandBufferImpl>
 {
 public:
 	/// Default constructor
-	CommandBufferImpl(GrManager* manager);
+	CommandBufferImpl(GrManager* manager)
+		: CommandBuffer(manager)
+	{
+	}
 
 	~CommandBufferImpl();
 
@@ -81,7 +86,7 @@ public:
 	{
 		commandCommon();
 		m_state.bindVertexBuffer(binding, stride, stepRate);
-		VkBuffer vkbuff = buff->m_impl->getHandle();
+		VkBuffer vkbuff = static_cast<const BufferImpl&>(*buff).getHandle();
 		ANKI_CMD(vkCmdBindVertexBuffers(m_handle, binding, 1, &vkbuff, &offset), ANY_OTHER_COMMAND);
 		m_microCmdb->pushObjectRef(buff);
 	}
@@ -95,7 +100,8 @@ public:
 	void bindIndexBuffer(BufferPtr buff, PtrSize offset, IndexType type)
 	{
 		commandCommon();
-		ANKI_CMD(vkCmdBindIndexBuffer(m_handle, buff->m_impl->getHandle(), offset, convertIndexType(type)),
+		ANKI_CMD(vkCmdBindIndexBuffer(
+					 m_handle, static_cast<const BufferImpl&>(*buff).getHandle(), offset, convertIndexType(type)),
 			ANY_OTHER_COMMAND);
 		m_microCmdb->pushObjectRef(buff);
 	}
@@ -217,9 +223,10 @@ public:
 	{
 		commandCommon();
 		const U realBinding = binding;
-		Texture& tex = *tex_;
-		ANKI_ASSERT((!tex.m_impl->m_depthStencil || !!aspect) && "Need to set aspect for DS textures");
-		const VkImageLayout lay = tex.m_impl->computeLayout(usage, 0);
+		const Texture& tex = *tex_;
+		const TextureImpl& teximpl = static_cast<const TextureImpl&>(tex);
+		ANKI_ASSERT((!teximpl.m_depthStencil || !!aspect) && "Need to set aspect for DS textures");
+		const VkImageLayout lay = teximpl.computeLayout(usage, 0);
 		m_dsetState[set].bindTexture(realBinding, &tex, aspect, lay);
 		m_microCmdb->pushObjectRef(tex_);
 	}
@@ -229,9 +236,10 @@ public:
 	{
 		commandCommon();
 		const U realBinding = binding;
-		Texture& tex = *tex_;
-		ANKI_ASSERT((!tex.m_impl->m_depthStencil || !!aspect) && "Need to set aspect for DS textures");
-		const VkImageLayout lay = tex.m_impl->computeLayout(usage, 0);
+		const Texture& tex = *tex_;
+		const TextureImpl& teximpl = static_cast<const TextureImpl&>(tex);
+		ANKI_ASSERT((!teximpl.m_depthStencil || !!aspect) && "Need to set aspect for DS textures");
+		const VkImageLayout lay = teximpl.computeLayout(usage, 0);
 		m_dsetState[set].bindTextureAndSampler(realBinding, &tex, sampler.get(), aspect, lay);
 		m_microCmdb->pushObjectRef(tex_);
 		m_microCmdb->pushObjectRef(sampler);

+ 34 - 29
src/anki/gr/vulkan/CommandBufferImpl.inl.h

@@ -129,7 +129,7 @@ inline void CommandBufferImpl::setImageBarrier(VkPipelineStageFlags srcStage,
 inline void CommandBufferImpl::setTextureBarrierRange(
 	TexturePtr tex, TextureUsageBit prevUsage, TextureUsageBit nextUsage, const VkImageSubresourceRange& range)
 {
-	const TextureImpl& impl = *tex->m_impl;
+	const TextureImpl& impl = static_cast<const TextureImpl&>(*tex);
 	ANKI_ASSERT(impl.usageValid(prevUsage));
 	ANKI_ASSERT(impl.usageValid(nextUsage));
 
@@ -157,7 +157,7 @@ inline void CommandBufferImpl::setTextureSurfaceBarrier(
 		return;
 	}
 
-	const TextureImpl& impl = *tex->m_impl;
+	const TextureImpl& impl = static_cast<const TextureImpl&>(*tex);
 	impl.checkSurfaceOrVolume(surf);
 
 	VkImageSubresourceRange range;
@@ -174,7 +174,7 @@ inline void CommandBufferImpl::setTextureVolumeBarrier(
 			&& "This transition happens inside CommandBufferImpl::generateMipmaps");
 	}
 
-	const TextureImpl& impl = *tex->m_impl;
+	const TextureImpl& impl = static_cast<const TextureImpl&>(*tex);
 	impl.checkSurfaceOrVolume(vol);
 
 	VkImageSubresourceRange range;
@@ -224,7 +224,7 @@ inline void CommandBufferImpl::setBufferBarrier(VkPipelineStageFlags srcStage,
 inline void CommandBufferImpl::setBufferBarrier(
 	BufferPtr buff, BufferUsageBit before, BufferUsageBit after, PtrSize offset, PtrSize size)
 {
-	const BufferImpl& impl = *buff->m_impl;
+	const BufferImpl& impl = static_cast<const BufferImpl&>(*buff);
 
 	VkPipelineStageFlags srcStage;
 	VkAccessFlags srcAccess;
@@ -258,7 +258,7 @@ inline void CommandBufferImpl::drawArraysIndirect(
 {
 	m_state.setPrimitiveTopology(topology);
 	drawcallCommon();
-	const BufferImpl& impl = *buff->m_impl;
+	const BufferImpl& impl = static_cast<const BufferImpl&>(*buff);
 	ANKI_ASSERT(impl.usageValid(BufferUsageBit::INDIRECT));
 	ANKI_ASSERT((offset % 4) == 0);
 	ANKI_ASSERT((offset + sizeof(DrawArraysIndirectInfo) * drawCount) <= impl.getSize());
@@ -272,7 +272,7 @@ inline void CommandBufferImpl::drawElementsIndirect(
 {
 	m_state.setPrimitiveTopology(topology);
 	drawcallCommon();
-	const BufferImpl& impl = *buff->m_impl;
+	const BufferImpl& impl = static_cast<const BufferImpl&>(*buff);
 	ANKI_ASSERT(impl.usageValid(BufferUsageBit::INDIRECT));
 	ANKI_ASSERT((offset % 4) == 0);
 	ANKI_ASSERT((offset + sizeof(DrawElementsIndirectInfo) * drawCount) <= impl.getSize());
@@ -325,8 +325,8 @@ inline void CommandBufferImpl::resetOcclusionQuery(OcclusionQueryPtr query)
 {
 	commandCommon();
 
-	VkQueryPool handle = query->m_impl->m_handle.m_pool;
-	U32 idx = query->m_impl->m_handle.m_queryIndex;
+	VkQueryPool handle = static_cast<const OcclusionQueryImpl&>(*query).m_handle.m_pool;
+	U32 idx = static_cast<const OcclusionQueryImpl&>(*query).m_handle.m_queryIndex;
 	ANKI_ASSERT(handle);
 
 #if ANKI_BATCH_COMMANDS
@@ -353,8 +353,8 @@ inline void CommandBufferImpl::beginOcclusionQuery(OcclusionQueryPtr query)
 {
 	commandCommon();
 
-	VkQueryPool handle = query->m_impl->m_handle.m_pool;
-	U32 idx = query->m_impl->m_handle.m_queryIndex;
+	VkQueryPool handle = static_cast<const OcclusionQueryImpl&>(*query).m_handle.m_pool;
+	U32 idx = static_cast<const OcclusionQueryImpl&>(*query).m_handle.m_queryIndex;
 	ANKI_ASSERT(handle);
 
 	ANKI_CMD(vkCmdBeginQuery(m_handle, handle, idx, 0), ANY_OTHER_COMMAND);
@@ -366,8 +366,8 @@ inline void CommandBufferImpl::endOcclusionQuery(OcclusionQueryPtr query)
 {
 	commandCommon();
 
-	VkQueryPool handle = query->m_impl->m_handle.m_pool;
-	U32 idx = query->m_impl->m_handle.m_queryIndex;
+	VkQueryPool handle = static_cast<const OcclusionQueryImpl&>(*query).m_handle.m_pool;
+	U32 idx = static_cast<const OcclusionQueryImpl&>(*query).m_handle.m_queryIndex;
 	ANKI_ASSERT(handle);
 
 	ANKI_CMD(vkCmdEndQuery(m_handle, handle, idx), ANY_OTHER_COMMAND);
@@ -384,7 +384,7 @@ inline void CommandBufferImpl::clearTextureInternal(
 	static_assert(sizeof(vclear) == sizeof(clearValue), "See file");
 	memcpy(&vclear, &clearValue, sizeof(clearValue));
 
-	const TextureImpl& impl = *tex->m_impl;
+	const TextureImpl& impl = static_cast<const TextureImpl&>(*tex);
 	if(impl.m_aspect == VK_IMAGE_ASPECT_COLOR_BIT)
 	{
 		ANKI_CMD(vkCmdClearColorImage(
@@ -402,8 +402,8 @@ inline void CommandBufferImpl::clearTextureInternal(
 inline void CommandBufferImpl::clearTextureSurface(
 	TexturePtr tex, const TextureSurfaceInfo& surf, const ClearValue& clearValue, DepthStencilAspectBit aspect)
 {
-	const TextureImpl& impl = *tex->m_impl;
-	ANKI_ASSERT(impl.m_type != TextureType::_3D && "Not for 3D");
+	const TextureImpl& impl = static_cast<const TextureImpl&>(*tex);
+	ANKI_ASSERT(impl.getTextureType() != TextureType::_3D && "Not for 3D");
 
 	VkImageSubresourceRange range;
 	impl.computeSubResourceRange(surf, aspect, range);
@@ -413,8 +413,8 @@ inline void CommandBufferImpl::clearTextureSurface(
 inline void CommandBufferImpl::clearTextureVolume(
 	TexturePtr tex, const TextureVolumeInfo& vol, const ClearValue& clearValue, DepthStencilAspectBit aspect)
 {
-	const TextureImpl& impl = *tex->m_impl;
-	ANKI_ASSERT(impl.m_type == TextureType::_3D && "Only for 3D");
+	const TextureImpl& impl = static_cast<const TextureImpl&>(*tex);
+	ANKI_ASSERT(impl.getTextureType() == TextureType::_3D && "Only for 3D");
 
 	VkImageSubresourceRange range;
 	impl.computeSubResourceRange(vol, aspect, range);
@@ -428,7 +428,7 @@ inline void CommandBufferImpl::pushSecondLevelCommandBuffer(CommandBufferPtr cmd
 	ANKI_ASSERT(m_subpassContents == VK_SUBPASS_CONTENTS_MAX_ENUM
 		|| m_subpassContents == VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
 
-	ANKI_ASSERT(cmdb->m_impl->m_finalized);
+	ANKI_ASSERT(static_cast<const CommandBufferImpl&>(*cmdb).m_finalized);
 
 	m_subpassContents = VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS;
 
@@ -445,9 +445,10 @@ inline void CommandBufferImpl::pushSecondLevelCommandBuffer(CommandBufferPtr cmd
 		m_secondLevelAtoms.resize(m_alloc, max<U>(8, m_secondLevelAtomCount * 2));
 	}
 
-	m_secondLevelAtoms[m_secondLevelAtomCount++] = cmdb->m_impl->m_handle;
+	m_secondLevelAtoms[m_secondLevelAtomCount++] = static_cast<const CommandBufferImpl&>(*cmdb).m_handle;
 #else
-	ANKI_CMD(vkCmdExecuteCommands(m_handle, 1, &cmdb->m_impl->m_handle), ANY_OTHER_COMMAND);
+	ANKI_CMD(
+		vkCmdExecuteCommands(m_handle, 1, &static_cast<const CommandBufferImpl&>(*cmdb).m_handle), ANY_OTHER_COMMAND);
 #endif
 
 	++m_rpCommandCount;
@@ -518,7 +519,7 @@ inline void CommandBufferImpl::drawcallCommon()
 		const Bool flipvp = flipViewport();
 
 		U32 fbWidth, fbHeight;
-		m_activeFb->m_impl->getAttachmentsSize(fbWidth, fbHeight);
+		static_cast<const FramebufferImpl&>(*m_activeFb).getAttachmentsSize(fbWidth, fbHeight);
 
 		VkViewport vp = computeViewport(&m_viewport[0], fbWidth, fbHeight, flipvp);
 
@@ -538,7 +539,7 @@ inline void CommandBufferImpl::drawcallCommon()
 		const Bool flipvp = flipViewport();
 
 		U32 fbWidth, fbHeight;
-		m_activeFb->m_impl->getAttachmentsSize(fbWidth, fbHeight);
+		static_cast<const FramebufferImpl&>(*m_activeFb).getAttachmentsSize(fbWidth, fbHeight);
 
 		VkRect2D scissor = computeScissor(&m_scissor[0], fbWidth, fbHeight, flipvp);
 
@@ -637,7 +638,7 @@ inline void CommandBufferImpl::fillBuffer(BufferPtr buff, PtrSize offset, PtrSiz
 {
 	commandCommon();
 	ANKI_ASSERT(!insideRenderPass());
-	const BufferImpl& impl = *buff->m_impl;
+	const BufferImpl& impl = static_cast<const BufferImpl&>(*buff);
 	ANKI_ASSERT(impl.usageValid(BufferUsageBit::FILL));
 
 	ANKI_ASSERT(offset < impl.getSize());
@@ -658,12 +659,12 @@ inline void CommandBufferImpl::writeOcclusionQueryResultToBuffer(
 	commandCommon();
 	ANKI_ASSERT(!insideRenderPass());
 
-	const BufferImpl& impl = *buff->m_impl;
+	const BufferImpl& impl = static_cast<const BufferImpl&>(*buff);
 	ANKI_ASSERT(impl.usageValid(BufferUsageBit::QUERY_RESULT));
 	ANKI_ASSERT((offset % 4) == 0);
 	ANKI_ASSERT((offset + sizeof(U32)) <= impl.getSize());
 
-	const OcclusionQueryImpl& q = *query->m_impl;
+	const OcclusionQueryImpl& q = static_cast<const OcclusionQueryImpl&>(*query);
 
 #if ANKI_BATCH_COMMANDS
 	flushBatches(CommandBufferCommandType::WRITE_QUERY_RESULT);
@@ -700,7 +701,7 @@ inline void CommandBufferImpl::bindShaderProgram(ShaderProgramPtr& prog)
 {
 	commandCommon();
 
-	ShaderProgramImpl& impl = *prog->m_impl;
+	ShaderProgramImpl& impl = static_cast<ShaderProgramImpl&>(*prog);
 
 	if(impl.isGraphics())
 	{
@@ -739,8 +740,12 @@ inline void CommandBufferImpl::copyBufferToBuffer(
 	region.dstOffset = dstOffset;
 	region.size = range;
 
-	ANKI_CMD(
-		vkCmdCopyBuffer(m_handle, src->m_impl->getHandle(), dst->m_impl->getHandle(), 1, &region), ANY_OTHER_COMMAND);
+	ANKI_CMD(vkCmdCopyBuffer(m_handle,
+				 static_cast<const BufferImpl&>(*src).getHandle(),
+				 static_cast<const BufferImpl&>(*dst).getHandle(),
+				 1,
+				 &region),
+		ANY_OTHER_COMMAND);
 
 	m_microCmdb->pushObjectRef(src);
 	m_microCmdb->pushObjectRef(dst);
@@ -748,7 +753,7 @@ inline void CommandBufferImpl::copyBufferToBuffer(
 
 inline Bool CommandBufferImpl::flipViewport() const
 {
-	return m_activeFb->m_impl->isDefaultFramebuffer()
+	return static_cast<const FramebufferImpl&>(*m_activeFb).isDefaultFramebuffer()
 		&& !!(getGrManagerImpl().getExtensions() & VulkanExtensions::KHR_MAINENANCE1);
 }
 

+ 3 - 0
src/anki/gr/vulkan/Common.h

@@ -31,6 +31,9 @@ class GrManagerImpl;
 #define ANKI_VK_LOGW(...) ANKI_LOG("VK  ", WARNING, __VA_ARGS__)
 #define ANKI_VK_LOGF(...) ANKI_LOG("VK  ", FATAL, __VA_ARGS__)
 
+#define ANKI_VK_SELF(class_) class_& self = *static_cast<class_*>(this)
+#define ANKI_VK_SELF_CONST(class_) const class_& self = *static_cast<const class_*>(this)
+
 enum class VulkanExtensions : U16
 {
 	NONE = 0,

+ 17 - 16
src/anki/gr/vulkan/DescriptorSet.h

@@ -7,6 +7,7 @@
 
 #include <anki/gr/vulkan/Common.h>
 #include <anki/gr/Buffer.h>
+#include <anki/gr/vulkan/BufferImpl.h>
 #include <anki/gr/Texture.h>
 #include <anki/gr/vulkan/TextureImpl.h>
 #include <anki/gr/Sampler.h>
@@ -65,8 +66,8 @@ private:
 class TextureBinding
 {
 public:
-	TextureImpl* m_tex = nullptr;
-	MicroSampler* m_sampler = nullptr;
+	const TextureImpl* m_tex = nullptr;
+	const MicroSampler* m_sampler = nullptr;
 	DepthStencilAspectBit m_aspect = DepthStencilAspectBit::NONE;
 	VkImageLayout m_layout = VK_IMAGE_LAYOUT_MAX_ENUM;
 };
@@ -74,7 +75,7 @@ public:
 class BufferBinding
 {
 public:
-	BufferImpl* m_buff = nullptr;
+	const BufferImpl* m_buff = nullptr;
 	PtrSize m_offset = MAX_PTR_SIZE;
 	PtrSize m_range = 0;
 };
@@ -82,7 +83,7 @@ public:
 class ImageBinding
 {
 public:
-	TextureImpl* m_tex = nullptr;
+	const TextureImpl* m_tex = nullptr;
 	U16 m_level = 0;
 };
 
@@ -109,15 +110,15 @@ public:
 		m_layoutDirty = true;
 	}
 
-	void bindTexture(U binding, Texture* tex, DepthStencilAspectBit aspect, VkImageLayout layout)
+	void bindTexture(U binding, const Texture* tex, DepthStencilAspectBit aspect, VkImageLayout layout)
 	{
 		AnyBinding& b = m_bindings[binding];
 		b = {};
 		b.m_type = DescriptorType::TEXTURE;
 		b.m_uuids[0] = b.m_uuids[1] = tex->getUuid();
 
-		b.m_tex.m_tex = tex->m_impl.get();
-		b.m_tex.m_sampler = tex->m_impl->m_sampler.get();
+		b.m_tex.m_tex = static_cast<const TextureImpl*>(tex);
+		b.m_tex.m_sampler = static_cast<const TextureImpl*>(tex)->m_sampler.get();
 		b.m_tex.m_aspect = aspect;
 		b.m_tex.m_layout = layout;
 
@@ -125,7 +126,7 @@ public:
 	}
 
 	void bindTextureAndSampler(
-		U binding, Texture* tex, Sampler* sampler, DepthStencilAspectBit aspect, VkImageLayout layout)
+		U binding, const Texture* tex, const Sampler* sampler, DepthStencilAspectBit aspect, VkImageLayout layout)
 	{
 		AnyBinding& b = m_bindings[binding];
 		b = {};
@@ -133,22 +134,22 @@ public:
 		b.m_uuids[0] = tex->getUuid();
 		b.m_uuids[1] = sampler->getUuid();
 
-		b.m_tex.m_tex = tex->m_impl.get();
-		b.m_tex.m_sampler = sampler->m_impl->m_sampler.get();
+		b.m_tex.m_tex = static_cast<const TextureImpl*>(tex);
+		b.m_tex.m_sampler = static_cast<const SamplerImpl*>(sampler)->m_sampler.get();
 		b.m_tex.m_aspect = aspect;
 		b.m_tex.m_layout = layout;
 
 		m_anyBindingDirty = true;
 	}
 
-	void bindUniformBuffer(U binding, Buffer* buff, PtrSize offset, PtrSize range)
+	void bindUniformBuffer(U binding, const Buffer* buff, PtrSize offset, PtrSize range)
 	{
 		AnyBinding& b = m_bindings[binding];
 		b = {};
 		b.m_type = DescriptorType::UNIFORM_BUFFER;
 		b.m_uuids[0] = b.m_uuids[1] = buff->getUuid();
 
-		b.m_buff.m_buff = buff->m_impl.get();
+		b.m_buff.m_buff = static_cast<const BufferImpl*>(buff);
 		b.m_buff.m_offset = offset;
 		b.m_buff.m_range = range;
 
@@ -156,14 +157,14 @@ public:
 		m_dynamicOffsetDirty.set(binding);
 	}
 
-	void bindStorageBuffer(U binding, Buffer* buff, PtrSize offset, PtrSize range)
+	void bindStorageBuffer(U binding, const Buffer* buff, PtrSize offset, PtrSize range)
 	{
 		AnyBinding& b = m_bindings[binding];
 		b = {};
 		b.m_type = DescriptorType::STORAGE_BUFFER;
 		b.m_uuids[0] = b.m_uuids[1] = buff->getUuid();
 
-		b.m_buff.m_buff = buff->m_impl.get();
+		b.m_buff.m_buff = static_cast<const BufferImpl*>(buff);
 		b.m_buff.m_offset = offset;
 		b.m_buff.m_range = range;
 
@@ -171,14 +172,14 @@ public:
 		m_dynamicOffsetDirty.set(binding);
 	}
 
-	void bindImage(U binding, Texture* tex, U32 level)
+	void bindImage(U binding, const Texture* tex, U32 level)
 	{
 		AnyBinding& b = m_bindings[binding];
 		b = {};
 		b.m_type = DescriptorType::IMAGE;
 		b.m_uuids[0] = b.m_uuids[1] = tex->getUuid();
 
-		b.m_image.m_tex = tex->m_impl.get();
+		b.m_image.m_tex = static_cast<const TextureImpl*>(tex);
 		b.m_image.m_level = level;
 
 		m_anyBindingDirty = true;

+ 5 - 8
src/anki/gr/vulkan/Fence.cpp

@@ -5,22 +5,19 @@
 
 #include <anki/gr/Fence.h>
 #include <anki/gr/vulkan/FenceImpl.h>
+#include <anki/gr/GrManager.h>
 
 namespace anki
 {
 
-Fence::Fence(GrManager* manager)
-	: GrObject(manager, CLASS_TYPE)
+Fence* Fence::newInstance(GrManager* manager)
 {
+	return manager->getAllocator().newInstance<FenceImpl>(manager);
 }
 
-Fence::~Fence()
+Bool Fence::clientWait(Second seconds)
 {
-}
-
-Bool Fence::clientWait(F64 seconds)
-{
-	return m_impl->m_fence->clientWait(seconds);
+	return static_cast<FenceImpl*>(this)->m_fence->clientWait(seconds);
 }
 
 } // end namespace anki

+ 1 - 1
src/anki/gr/vulkan/FenceFactory.h

@@ -44,7 +44,7 @@ public:
 
 	Bool done() const;
 
-	Bool clientWait(F64 seconds);
+	Bool clientWait(Second seconds);
 
 private:
 	VkFence m_handle = VK_NULL_HANDLE;

+ 1 - 1
src/anki/gr/vulkan/FenceFactory.inl.h

@@ -55,7 +55,7 @@ inline Bool MicroFence::done() const
 	return false;
 }
 
-inline Bool MicroFence::clientWait(F64 seconds)
+inline Bool MicroFence::clientWait(Second seconds)
 {
 	if(seconds == 0.0)
 	{

+ 3 - 2
src/anki/gr/vulkan/FenceImpl.h

@@ -5,6 +5,7 @@
 
 #pragma once
 
+#include <anki/gr/Fence.h>
 #include <anki/gr/vulkan/VulkanObject.h>
 #include <anki/gr/vulkan/FenceFactory.h>
 
@@ -15,13 +16,13 @@ namespace anki
 /// @{
 
 /// Buffer implementation
-class FenceImpl : public VulkanObject
+class FenceImpl final : public Fence, public VulkanObject<Fence, FenceImpl>
 {
 public:
 	MicroFencePtr m_fence;
 
 	FenceImpl(GrManager* manager)
-		: VulkanObject(manager)
+		: Fence(manager)
 	{
 	}
 

+ 3 - 15
src/anki/gr/vulkan/Framebuffer.cpp

@@ -5,26 +5,14 @@
 
 #include <anki/gr/Framebuffer.h>
 #include <anki/gr/vulkan/FramebufferImpl.h>
+#include <anki/gr/GrManager.h>
 
 namespace anki
 {
 
-Framebuffer::Framebuffer(GrManager* manager)
-	: GrObject(manager, CLASS_TYPE)
+Framebuffer* Framebuffer::newInstance(GrManager* manager, const FramebufferInitInfo& init)
 {
-}
-
-Framebuffer::~Framebuffer()
-{
-}
-
-void Framebuffer::init(const FramebufferInitInfo& init)
-{
-	m_impl.reset(getAllocator().newInstance<FramebufferImpl>(&getManager()));
-	if(m_impl->init(init))
-	{
-		ANKI_VK_LOGF("Cannot recover");
-	}
+	return FramebufferImpl::newInstanceHelper(manager, init);
 }
 
 } // end namespace anki

+ 8 - 8
src/anki/gr/vulkan/FramebufferImpl.cpp

@@ -47,7 +47,7 @@ Error FramebufferImpl::init(const FramebufferInitInfo& init)
 
 	if(!m_defaultFb && init.m_depthStencilAttachment.m_texture)
 	{
-		const TextureImpl& tex = *init.m_depthStencilAttachment.m_texture->m_impl;
+		const TextureImpl& tex = static_cast<const TextureImpl&>(*init.m_depthStencilAttachment.m_texture);
 
 		if(!!(tex.m_workarounds & TextureImplWorkaround::S8_TO_D24S8))
 		{
@@ -140,14 +140,14 @@ Error FramebufferImpl::initFbs(const FramebufferInitInfo& init)
 	for(U i = 0; i < init.m_colorAttachmentCount; ++i)
 	{
 		const FramebufferAttachmentInfo& att = init.m_colorAttachments[i];
-		TextureImpl& tex = *att.m_texture->m_impl;
+		const TextureImpl& tex = static_cast<const TextureImpl&>(*att.m_texture);
 
 		imgViews[count++] = tex.getOrCreateSingleSurfaceView(att.m_surface, att.m_aspect);
 
 		if(m_noDflt.m_width == 0)
 		{
-			m_noDflt.m_width = tex.m_width >> att.m_surface.m_level;
-			m_noDflt.m_height = tex.m_height >> att.m_surface.m_level;
+			m_noDflt.m_width = tex.getWidth() >> att.m_surface.m_level;
+			m_noDflt.m_height = tex.getHeight() >> att.m_surface.m_level;
 		}
 
 		m_noDflt.m_refs[i] = att.m_texture;
@@ -156,14 +156,14 @@ Error FramebufferImpl::initFbs(const FramebufferInitInfo& init)
 	if(hasDepthStencil())
 	{
 		const FramebufferAttachmentInfo& att = init.m_depthStencilAttachment;
-		TextureImpl& tex = *att.m_texture->m_impl;
+		const TextureImpl& tex = static_cast<const TextureImpl&>(*att.m_texture);
 
 		imgViews[count++] = tex.getOrCreateSingleSurfaceView(att.m_surface, m_aspect);
 
 		if(m_noDflt.m_width == 0)
 		{
-			m_noDflt.m_width = tex.m_width >> att.m_surface.m_level;
-			m_noDflt.m_height = tex.m_height >> att.m_surface.m_level;
+			m_noDflt.m_width = tex.getWidth() >> att.m_surface.m_level;
+			m_noDflt.m_height = tex.getHeight() >> att.m_surface.m_level;
 		}
 
 		m_noDflt.m_refs[MAX_COLOR_ATTACHMENTS] = att.m_texture;
@@ -186,7 +186,7 @@ void FramebufferImpl::setupAttachmentDescriptor(
 	const FramebufferAttachmentInfo& att, VkAttachmentDescription& desc, VkImageLayout layout) const
 {
 	desc = {};
-	desc.format = convertFormat(att.m_texture->m_impl->m_format);
+	desc.format = convertFormat(att.m_texture->getPixelFormat());
 	desc.samples = VK_SAMPLE_COUNT_1_BIT;
 	desc.loadOp = convertLoadOp(att.m_loadOperation);
 	desc.storeOp = convertStoreOp(att.m_storeOperation);

+ 4 - 3
src/anki/gr/vulkan/FramebufferImpl.h

@@ -5,6 +5,7 @@
 
 #pragma once
 
+#include <anki/gr/Framebuffer.h>
 #include <anki/gr/vulkan/VulkanObject.h>
 #include <anki/gr/vulkan/SwapchainFactory.h>
 #include <anki/util/HashMap.h>
@@ -20,11 +21,11 @@ class FramebufferAttachmentInfo;
 /// @{
 
 /// Framebuffer implementation.
-class FramebufferImpl : public VulkanObject
+class FramebufferImpl final : public Framebuffer, public VulkanObject<Framebuffer, FramebufferImpl>
 {
 public:
 	FramebufferImpl(GrManager* manager)
-		: VulkanObject(manager)
+		: Framebuffer(manager)
 	{
 	}
 
@@ -125,7 +126,7 @@ public:
 		}
 	}
 
-	void getDefaultFramebufferInfo(MicroSwapchainPtr& swapchain, U32& crntBackBufferIdx)
+	void getDefaultFramebufferInfo(MicroSwapchainPtr& swapchain, U32& crntBackBufferIdx) const
 	{
 		ANKI_ASSERT(m_defaultFb);
 		swapchain = m_dflt.m_swapchain;

+ 95 - 17
src/anki/gr/vulkan/GrManager.cpp

@@ -5,8 +5,16 @@
 
 #include <anki/gr/GrManager.h>
 #include <anki/gr/vulkan/GrManagerImpl.h>
-#include <anki/gr/vulkan/TextureImpl.h>
+
+#include <anki/gr/Buffer.h>
 #include <anki/gr/Texture.h>
+#include <anki/gr/Sampler.h>
+#include <anki/gr/Shader.h>
+#include <anki/gr/ShaderProgram.h>
+#include <anki/gr/CommandBuffer.h>
+#include <anki/gr/Framebuffer.h>
+#include <anki/gr/OcclusionQuery.h>
+#include <anki/gr/RenderGraph.h>
 
 namespace anki
 {
@@ -18,39 +26,106 @@ GrManager::GrManager()
 GrManager::~GrManager()
 {
 	// Destroy in reverse order
-	m_impl.reset(nullptr);
 	m_cacheDir.destroy(m_alloc);
 }
 
-Error GrManager::init(GrManagerInitInfo& init)
+Error GrManager::newInstance(GrManagerInitInfo& init, GrManager*& gr)
 {
-	m_alloc = HeapAllocator<U8>(init.m_allocCallback, init.m_allocCallbackUserData);
+	auto alloc = HeapAllocator<U8>(init.m_allocCallback, init.m_allocCallbackUserData);
+
+	GrManagerImpl* impl = alloc.newInstance<GrManagerImpl>();
+
+	// Init
+	impl->m_alloc = HeapAllocator<U8>(init.m_allocCallback, init.m_allocCallbackUserData);
+	impl->m_cacheDir.create(alloc, init.m_cacheDirectory);
+	Error err = impl->init(init);
 
-	m_cacheDir.create(m_alloc, init.m_cacheDirectory);
+	if(err)
+	{
+		alloc.deleteInstance(impl);
+		gr = nullptr;
+	}
+	else
+	{
+		gr = impl;
+	}
 
-	m_impl.reset(m_alloc.newInstance<GrManagerImpl>(this));
-	ANKI_CHECK(m_impl->init(init));
+	return err;
+}
 
-	return Error::NONE;
+void GrManager::deleteInstance(GrManager* gr)
+{
+	ANKI_ASSERT(gr);
+	auto alloc = gr->m_alloc;
+	gr->~GrManager();
+	alloc.deallocate(gr, 1);
 }
 
 void GrManager::beginFrame()
 {
-	m_impl->beginFrame();
+	ANKI_VK_SELF(GrManagerImpl);
+	self.beginFrame();
 }
 
 void GrManager::swapBuffers()
 {
-	m_impl->endFrame();
+	ANKI_VK_SELF(GrManagerImpl);
+	self.endFrame();
 }
 
 void GrManager::finish()
 {
+	// TODO
+}
+
+BufferPtr GrManager::newBuffer(const BufferInitInfo& init)
+{
+	return BufferPtr(Buffer::newInstance(this, init));
+}
+
+TexturePtr GrManager::newTexture(const TextureInitInfo& init)
+{
+	return TexturePtr(Texture::newInstance(this, init));
+}
+
+SamplerPtr GrManager::newSampler(const SamplerInitInfo& init)
+{
+	return SamplerPtr(Sampler::newInstance(this, init));
+}
+
+ShaderPtr GrManager::newShader(const ShaderInitInfo& init)
+{
+	return ShaderPtr(Shader::newInstance(this, init));
+}
+
+ShaderProgramPtr GrManager::newShaderProgram(const ShaderProgramInitInfo& init)
+{
+	return ShaderProgramPtr(ShaderProgram::newInstance(this, init));
+}
+
+CommandBufferPtr GrManager::newCommandBuffer(const CommandBufferInitInfo& init)
+{
+	return CommandBufferPtr(CommandBuffer::newInstance(this, init));
+}
+
+FramebufferPtr GrManager::newFramebuffer(const FramebufferInitInfo& init)
+{
+	return FramebufferPtr(Framebuffer::newInstance(this, init));
+}
+
+OcclusionQueryPtr GrManager::newOcclusionQuery()
+{
+	return OcclusionQueryPtr(OcclusionQuery::newInstance(this));
+}
+
+RenderGraphPtr GrManager::newRenderGraph()
+{
+	return RenderGraphPtr(RenderGraph::newInstance(this));
 }
 
 void GrManager::getTextureSurfaceUploadInfo(TexturePtr tex, const TextureSurfaceInfo& surf, PtrSize& allocationSize)
 {
-	const TextureImpl& impl = *tex->m_impl;
+	const TextureImpl& impl = static_cast<const TextureImpl&>(*tex);
 	impl.checkSurfaceOrVolume(surf);
 
 	U width = impl.m_width >> surf.m_level;
@@ -77,7 +152,7 @@ void GrManager::getTextureSurfaceUploadInfo(TexturePtr tex, const TextureSurface
 
 void GrManager::getTextureVolumeUploadInfo(TexturePtr tex, const TextureVolumeInfo& vol, PtrSize& allocationSize)
 {
-	const TextureImpl& impl = *tex->m_impl;
+	const TextureImpl& impl = static_cast<const TextureImpl&>(*tex);
 	impl.checkSurfaceOrVolume(vol);
 
 	U width = impl.m_width >> vol.m_level;
@@ -105,19 +180,22 @@ void GrManager::getTextureVolumeUploadInfo(TexturePtr tex, const TextureVolumeIn
 
 void GrManager::getUniformBufferInfo(U32& bindOffsetAlignment, PtrSize& maxUniformBlockSize) const
 {
-	bindOffsetAlignment = m_impl->getPhysicalDeviceProperties().limits.minUniformBufferOffsetAlignment;
-	maxUniformBlockSize = m_impl->getPhysicalDeviceProperties().limits.maxUniformBufferRange;
+	ANKI_VK_SELF_CONST(GrManagerImpl);
+	bindOffsetAlignment = self.getPhysicalDeviceProperties().limits.minUniformBufferOffsetAlignment;
+	maxUniformBlockSize = self.getPhysicalDeviceProperties().limits.maxUniformBufferRange;
 }
 
 void GrManager::getStorageBufferInfo(U32& bindOffsetAlignment, PtrSize& maxStorageBlockSize) const
 {
-	bindOffsetAlignment = m_impl->getPhysicalDeviceProperties().limits.minStorageBufferOffsetAlignment;
-	maxStorageBlockSize = m_impl->getPhysicalDeviceProperties().limits.maxStorageBufferRange;
+	ANKI_VK_SELF_CONST(GrManagerImpl);
+	bindOffsetAlignment = self.getPhysicalDeviceProperties().limits.minStorageBufferOffsetAlignment;
+	maxStorageBlockSize = self.getPhysicalDeviceProperties().limits.maxStorageBufferRange;
 }
 
 void GrManager::getTextureBufferInfo(U32& bindOffsetAlignment, PtrSize& maxRange) const
 {
-	bindOffsetAlignment = m_impl->getPhysicalDeviceProperties().limits.minTexelBufferOffsetAlignment;
+	ANKI_VK_SELF_CONST(GrManagerImpl);
+	bindOffsetAlignment = self.getPhysicalDeviceProperties().limits.minTexelBufferOffsetAlignment;
 	maxRange = MAX_U32;
 }
 

+ 3 - 9
src/anki/gr/vulkan/GrManagerImpl.cpp

@@ -87,11 +87,6 @@ GrManagerImpl::~GrManagerImpl()
 	m_vkHandleToName.destroy(getAllocator());
 }
 
-GrAllocator<U8> GrManagerImpl::getAllocator() const
-{
-	return m_manager->getAllocator();
-}
-
 Error GrManagerImpl::init(const GrManagerInitInfo& init)
 {
 	Error err = initInternal(init);
@@ -707,7 +702,7 @@ void GrManagerImpl::resetFrame(PerFrame& frame)
 
 void GrManagerImpl::flushCommandBuffer(CommandBufferPtr cmdb, FencePtr* outFence, Bool wait)
 {
-	CommandBufferImpl& impl = *cmdb->m_impl;
+	CommandBufferImpl& impl = static_cast<CommandBufferImpl&>(*cmdb);
 	VkCommandBuffer handle = impl.getHandle();
 
 	VkSubmitInfo submit = {};
@@ -718,9 +713,8 @@ void GrManagerImpl::flushCommandBuffer(CommandBufferPtr cmdb, FencePtr* outFence
 	// Create fence
 	if(outFence)
 	{
-		outFence->reset(getAllocator().newInstance<Fence>(m_manager));
-		(*outFence)->m_impl.reset(getAllocator().newInstance<FenceImpl>(m_manager));
-		(*outFence)->m_impl->m_fence = fence;
+		outFence->reset(getAllocator().newInstance<FenceImpl>(this));
+		static_cast<FenceImpl&>(**outFence).m_fence = fence;
 	}
 
 	LockGuard<Mutex> lock(m_globalMtx);

+ 3 - 8
src/anki/gr/vulkan/GrManagerImpl.h

@@ -5,6 +5,7 @@
 
 #pragma once
 
+#include <anki/gr/GrManager.h>
 #include <anki/gr/vulkan/Common.h>
 #include <anki/gr/vulkan/GpuMemoryManager.h>
 #include <anki/gr/vulkan/SemaphoreFactory.h>
@@ -32,21 +33,17 @@ class ConfigSet;
 /// @{
 
 /// Vulkan implementation of GrManager.
-class GrManagerImpl
+class GrManagerImpl : public GrManager
 {
 public:
-	GrManagerImpl(GrManager* manager)
-		: m_manager(manager)
+	GrManagerImpl()
 	{
-		ANKI_ASSERT(manager);
 	}
 
 	~GrManagerImpl();
 
 	ANKI_USE_RESULT Error init(const GrManagerInitInfo& cfg);
 
-	GrAllocator<U8> getAllocator() const;
-
 	U32 getGraphicsQueueFamily() const
 	{
 		return m_queueIdx;
@@ -189,8 +186,6 @@ public:
 	}
 
 private:
-	GrManager* m_manager = nullptr;
-
 	U64 m_frame = 0;
 
 #if ANKI_GR_MANAGER_DEBUG_MEMMORY

+ 3 - 16
src/anki/gr/vulkan/OcclusionQuery.cpp

@@ -5,27 +5,14 @@
 
 #include <anki/gr/OcclusionQuery.h>
 #include <anki/gr/vulkan/OcclusionQueryImpl.h>
+#include <anki/gr/GrManager.h>
 
 namespace anki
 {
 
-OcclusionQuery::OcclusionQuery(GrManager* manager)
-	: GrObject(manager, CLASS_TYPE)
+OcclusionQuery* OcclusionQuery::newInstance(GrManager* manager)
 {
-}
-
-OcclusionQuery::~OcclusionQuery()
-{
-}
-
-void OcclusionQuery::init()
-{
-	m_impl.reset(getAllocator().newInstance<OcclusionQueryImpl>(&getManager()));
-
-	if(m_impl->init())
-	{
-		ANKI_VK_LOGF("Cannot recover");
-	}
+	return OcclusionQueryImpl::newInstanceHelper(manager);
 }
 
 } // end namespace anki

+ 4 - 3
src/anki/gr/vulkan/OcclusionQueryImpl.h

@@ -5,6 +5,7 @@
 
 #pragma once
 
+#include <anki/gr/OcclusionQuery.h>
 #include <anki/gr/vulkan/VulkanObject.h>
 #include <anki/gr/vulkan/QueryExtra.h>
 
@@ -15,13 +16,13 @@ namespace anki
 /// @{
 
 /// Occlusion query.
-class OcclusionQueryImpl : public VulkanObject
+class OcclusionQueryImpl final : public OcclusionQuery, public VulkanObject<OcclusionQuery, OcclusionQueryImpl>
 {
 public:
-	QueryAllocationHandle m_handle;
+	QueryAllocationHandle m_handle = {};
 
 	OcclusionQueryImpl(GrManager* manager)
-		: VulkanObject(manager)
+		: OcclusionQuery(manager)
 	{
 	}
 

+ 2 - 2
src/anki/gr/vulkan/Pipeline.cpp

@@ -202,7 +202,7 @@ const VkGraphicsPipelineCreateInfo& PipelineStateTracker::updatePipelineCreateIn
 	ci.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
 
 	// Prog
-	ci.pStages = m_state.m_prog->m_impl->getShaderCreateInfos(ci.stageCount);
+	ci.pStages = static_cast<const ShaderProgramImpl&>(*m_state.m_prog).getShaderCreateInfos(ci.stageCount);
 
 	// Vert
 	VkPipelineVertexInputStateCreateInfo& vertCi = m_ci.m_vert;
@@ -370,7 +370,7 @@ const VkGraphicsPipelineCreateInfo& PipelineStateTracker::updatePipelineCreateIn
 	ci.pDynamicState = &dynCi;
 
 	// The rest
-	ci.layout = m_state.m_prog->m_impl->getPipelineLayout().getHandle();
+	ci.layout = static_cast<const ShaderProgramImpl&>(*m_state.m_prog).getPipelineLayout().getHandle();
 	ci.renderPass = m_rpass;
 	ci.subpass = 0;
 

+ 5 - 4
src/anki/gr/vulkan/Pipeline.h

@@ -356,7 +356,7 @@ public:
 	{
 		if(prog != m_state.m_prog)
 		{
-			const ShaderProgramImpl& impl = *prog->m_impl;
+			const ShaderProgramImpl& impl = static_cast<const ShaderProgramImpl&>(*prog);
 			m_shaderColorAttachmentWritemask = impl.getReflectionInfo().m_colorAttachmentWritemask;
 			m_shaderAttributeMask = impl.getReflectionInfo().m_attributeMask;
 			m_state.m_prog = prog;
@@ -368,11 +368,12 @@ public:
 	{
 		ANKI_ASSERT(m_rpass == VK_NULL_HANDLE);
 		Bool d, s;
-		fb->m_impl->getAttachmentInfo(m_fbColorAttachmentMask, d, s);
+		const FramebufferImpl& fbimpl = static_cast<const FramebufferImpl&>(*fb);
+		fbimpl.getAttachmentInfo(m_fbColorAttachmentMask, d, s);
 		m_fbDepth = d;
 		m_fbStencil = s;
-		m_rpass = fb->m_impl->getCompatibleRenderPass();
-		m_defaultFb = fb->m_impl->isDefaultFramebuffer();
+		m_rpass = fbimpl.getCompatibleRenderPass();
+		m_defaultFb = fbimpl.isDefaultFramebuffer();
 		m_fb = fb;
 	}
 

+ 3 - 16
src/anki/gr/vulkan/Sampler.cpp

@@ -5,27 +5,14 @@
 
 #include <anki/gr/Sampler.h>
 #include <anki/gr/vulkan/SamplerImpl.h>
+#include <anki/gr/GrManager.h>
 
 namespace anki
 {
 
-Sampler::Sampler(GrManager* manager)
-	: GrObject(manager, CLASS_TYPE)
+Sampler* Sampler::newInstance(GrManager* manager, const SamplerInitInfo& init)
 {
-}
-
-Sampler::~Sampler()
-{
-}
-
-void Sampler::init(const SamplerInitInfo& init)
-{
-	m_impl.reset(getAllocator().newInstance<SamplerImpl>(&getManager()));
-
-	if(m_impl->init(init))
-	{
-		ANKI_VK_LOGF("Cannot recover");
-	}
+	return SamplerImpl::newInstanceHelper(manager, init);
 }
 
 } // end namespace anki

+ 3 - 2
src/anki/gr/vulkan/SamplerImpl.h

@@ -5,6 +5,7 @@
 
 #pragma once
 
+#include <anki/gr/Sampler.h>
 #include <anki/gr/vulkan/VulkanObject.h>
 #include <anki/gr/vulkan/SamplerFactory.h>
 
@@ -15,13 +16,13 @@ namespace anki
 /// @{
 
 /// Vulkan implementation of Sampler.
-class SamplerImpl : public VulkanObject
+class SamplerImpl final : public Sampler, public VulkanObject<Sampler, SamplerImpl>
 {
 public:
 	MicroSamplerPtr m_sampler;
 
 	SamplerImpl(GrManager* manager)
-		: VulkanObject(manager)
+		: Sampler(manager)
 	{
 	}
 

+ 3 - 18
src/anki/gr/vulkan/Shader.cpp

@@ -5,29 +5,14 @@
 
 #include <anki/gr/Shader.h>
 #include <anki/gr/vulkan/ShaderImpl.h>
+#include <anki/gr/GrManager.h>
 
 namespace anki
 {
 
-Shader::Shader(GrManager* manager)
-	: GrObject(manager, CLASS_TYPE)
+Shader* Shader::newInstance(GrManager* manager, const ShaderInitInfo& init)
 {
-}
-
-Shader::~Shader()
-{
-}
-
-void Shader::init(ShaderType shaderType, const CString& source)
-{
-	ANKI_ASSERT(!source.isEmpty());
-
-	m_impl.reset(getAllocator().newInstance<ShaderImpl>(&getManager()));
-
-	if(m_impl->init(shaderType, source))
-	{
-		ANKI_VK_LOGF("Cannot recover");
-	}
+	return ShaderImpl::newInstanceHelper(manager, init);
 }
 
 } // end namespace anki

+ 7 - 6
src/anki/gr/vulkan/ShaderImpl.cpp

@@ -221,11 +221,12 @@ Error ShaderImpl::genSpirv(const CString& source, std::vector<unsigned int>& spi
 	return Error::NONE;
 }
 
-Error ShaderImpl::init(ShaderType shaderType, const CString& source)
+Error ShaderImpl::init(const ShaderInitInfo& inf)
 {
-	ANKI_ASSERT(source);
+	ANKI_ASSERT(inf.m_source && inf.m_source.getLength() > 0);
 	ANKI_ASSERT(m_handle == VK_NULL_HANDLE);
-	m_shaderType = shaderType;
+	m_shaderType = inf.m_shaderType;
+	CString source = inf.m_source;
 
 	// Setup the shader
 	auto alloc = getAllocator();
@@ -240,7 +241,7 @@ Error ShaderImpl::init(ShaderType shaderType, const CString& source)
 
 	fullSrc.sprintf(SHADER_HEADER,
 		&GPU_VENDOR_STR[getGrManagerImpl().getGpuVendor()][0],
-		shaderName[shaderType],
+		shaderName[m_shaderType],
 		0,
 		MAX_TEXTURE_BINDINGS,
 		MAX_TEXTURE_BINDINGS + MAX_UNIFORM_BUFFER_BINDINGS,
@@ -264,7 +265,7 @@ Error ShaderImpl::init(ShaderType shaderType, const CString& source)
 			newName = name++;
 		}
 
-		switch(shaderType)
+		switch(m_shaderType)
 		{
 		case ShaderType::VERTEX:
 			ext = "vert";
@@ -290,7 +291,7 @@ Error ShaderImpl::init(ShaderType shaderType, const CString& source)
 		}
 
 		StringAuto fname(alloc);
-		CString cacheDir = getGrManager().getCacheDirectory();
+		CString cacheDir = getManager().getCacheDirectory();
 		fname.sprintf("%s/%05u.%s", &cacheDir[0], newName, ext);
 
 		File file;

+ 4 - 4
src/anki/gr/vulkan/ShaderImpl.h

@@ -5,9 +5,9 @@
 
 #pragma once
 
+#include <anki/gr/Shader.h>
 #include <anki/gr/vulkan/VulkanObject.h>
 #include <anki/gr/vulkan/DescriptorSet.h>
-#include <anki/util/String.h>
 #include <anki/util/BitSet.h>
 #include <vector>
 
@@ -18,7 +18,7 @@ namespace anki
 /// @{
 
 /// Shader vulkan implementation.
-class ShaderImpl : public VulkanObject
+class ShaderImpl final : public Shader, public VulkanObject<Shader, ShaderImpl>
 {
 public:
 	VkShaderModule m_handle = VK_NULL_HANDLE;
@@ -31,13 +31,13 @@ public:
 	Array<BitSet<MAX_BINDINGS_PER_DESCRIPTOR_SET, U8>, MAX_DESCRIPTOR_SETS> m_activeBindingMask = {{{false}, {false}}};
 
 	ShaderImpl(GrManager* manager)
-		: VulkanObject(manager)
+		: Shader(manager)
 	{
 	}
 
 	~ShaderImpl();
 
-	ANKI_USE_RESULT Error init(ShaderType shaderType, const CString& source);
+	ANKI_USE_RESULT Error init(const ShaderInitInfo& init);
 
 private:
 	/// Generate SPIRV from GLSL.

+ 3 - 56
src/anki/gr/vulkan/ShaderProgram.cpp

@@ -6,67 +6,14 @@
 #include <anki/gr/ShaderProgram.h>
 #include <anki/gr/vulkan/ShaderProgramImpl.h>
 #include <anki/gr/Shader.h>
+#include <anki/gr/GrManager.h>
 
 namespace anki
 {
 
-ShaderProgram::ShaderProgram(GrManager* manager)
-	: GrObject(manager, CLASS_TYPE)
+ShaderProgram* ShaderProgram::newInstance(GrManager* manager, const ShaderProgramInitInfo& init)
 {
-}
-
-ShaderProgram::~ShaderProgram()
-{
-}
-
-void ShaderProgram::init(ShaderPtr vert, ShaderPtr frag)
-{
-	ANKI_ASSERT(vert && frag);
-
-	Array<ShaderPtr, U(ShaderType::COUNT)> shaders = {};
-	shaders[ShaderType::VERTEX] = vert;
-	shaders[ShaderType::FRAGMENT] = frag;
-
-	m_impl.reset(getAllocator().newInstance<ShaderProgramImpl>(&getManager()));
-
-	if(m_impl->init(shaders))
-	{
-		ANKI_VK_LOGF("Cannot recover");
-	}
-}
-
-void ShaderProgram::init(ShaderPtr comp)
-{
-	ANKI_ASSERT(comp);
-
-	Array<ShaderPtr, U(ShaderType::COUNT)> shaders = {};
-	shaders[ShaderType::COMPUTE] = comp;
-
-	m_impl.reset(getAllocator().newInstance<ShaderProgramImpl>(&getManager()));
-
-	if(m_impl->init(shaders))
-	{
-		ANKI_VK_LOGF("Cannot recover");
-	}
-}
-
-void ShaderProgram::init(ShaderPtr vert, ShaderPtr tessc, ShaderPtr tesse, ShaderPtr geom, ShaderPtr frag)
-{
-	ANKI_ASSERT(vert && frag);
-
-	Array<ShaderPtr, U(ShaderType::COUNT)> shaders = {};
-	shaders[ShaderType::VERTEX] = vert;
-	shaders[ShaderType::TESSELLATION_CONTROL] = tessc;
-	shaders[ShaderType::TESSELLATION_EVALUATION] = tesse;
-	shaders[ShaderType::GEOMETRY] = geom;
-	shaders[ShaderType::FRAGMENT] = frag;
-
-	m_impl.reset(getAllocator().newInstance<ShaderProgramImpl>(&getManager()));
-
-	if(m_impl->init(shaders))
-	{
-		ANKI_VK_LOGF("Cannot recover");
-	}
+	return ShaderProgramImpl::newInstanceHelper(manager, init);
 }
 
 } // end namespace anki

+ 10 - 14
src/anki/gr/vulkan/ShaderProgramImpl.cpp

@@ -12,11 +12,6 @@
 namespace anki
 {
 
-ShaderProgramImpl::ShaderProgramImpl(GrManager* manager)
-	: VulkanObject(manager)
-{
-}
-
 ShaderProgramImpl::~ShaderProgramImpl()
 {
 	if(m_pplineFactory)
@@ -31,10 +26,10 @@ ShaderProgramImpl::~ShaderProgramImpl()
 	}
 }
 
-Error ShaderProgramImpl::init(const Array<ShaderPtr, U(ShaderType::COUNT)>& shaders)
+Error ShaderProgramImpl::init(const ShaderProgramInitInfo& inf)
 {
 	ShaderTypeBit shaderMask = ShaderTypeBit::NONE;
-	m_shaders = shaders;
+	m_shaders = inf.m_shaders;
 
 	// Merge bindings
 	//
@@ -45,14 +40,14 @@ Error ShaderProgramImpl::init(const Array<ShaderPtr, U(ShaderType::COUNT)>& shad
 	{
 		for(ShaderType stype = ShaderType::FIRST; stype < ShaderType::COUNT; ++stype)
 		{
-			if(!shaders[stype].isCreated())
+			if(!m_shaders[stype].isCreated())
 			{
 				continue;
 			}
 
 			shaderMask |= static_cast<ShaderTypeBit>(1 << stype);
 
-			const ShaderImpl& simpl = *shaders[stype]->m_impl;
+			const ShaderImpl& simpl = *scast<const ShaderImpl*>(m_shaders[stype].get());
 
 			m_refl.m_descriptorSetMask |= simpl.m_descriptorSetMask;
 			m_refl.m_activeBindingMask[set] |= simpl.m_activeBindingMask[set];
@@ -112,8 +107,9 @@ Error ShaderProgramImpl::init(const Array<ShaderPtr, U(ShaderType::COUNT)>& shad
 	const Bool graphicsProg = !!(shaderMask & ShaderTypeBit::VERTEX);
 	if(graphicsProg)
 	{
-		m_refl.m_attributeMask = shaders[ShaderType::VERTEX]->m_impl->m_attributeMask;
-		m_refl.m_colorAttachmentWritemask = shaders[ShaderType::FRAGMENT]->m_impl->m_colorAttachmentWritemask;
+		m_refl.m_attributeMask = scast<const ShaderImpl*>(m_shaders[ShaderType::VERTEX].get())->m_attributeMask;
+		m_refl.m_colorAttachmentWritemask =
+			scast<const ShaderImpl*>(m_shaders[ShaderType::FRAGMENT].get())->m_colorAttachmentWritemask;
 
 		const U attachmentCount = m_refl.m_colorAttachmentWritemask.getEnabledBitCount();
 		for(U i = 0; i < attachmentCount; ++i)
@@ -128,7 +124,7 @@ Error ShaderProgramImpl::init(const Array<ShaderPtr, U(ShaderType::COUNT)>& shad
 	{
 		for(ShaderType stype = ShaderType::VERTEX; stype <= ShaderType::FRAGMENT; ++stype)
 		{
-			if(!shaders[stype].isCreated())
+			if(!m_shaders[stype].isCreated())
 			{
 				continue;
 			}
@@ -138,7 +134,7 @@ Error ShaderProgramImpl::init(const Array<ShaderPtr, U(ShaderType::COUNT)>& shad
 			inf.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
 			inf.stage = convertShaderTypeBit(static_cast<ShaderTypeBit>(1 << stype));
 			inf.pName = "main";
-			inf.module = shaders[stype]->m_impl->m_handle;
+			inf.module = scast<const ShaderImpl*>(m_shaders[stype].get())->m_handle;
 		}
 	}
 
@@ -162,7 +158,7 @@ Error ShaderProgramImpl::init(const Array<ShaderPtr, U(ShaderType::COUNT)>& shad
 		ci.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
 		ci.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT;
 		ci.stage.pName = "main";
-		ci.stage.module = shaders[ShaderType::COMPUTE]->m_impl->m_handle;
+		ci.stage.module = scast<const ShaderImpl*>(m_shaders[ShaderType::COMPUTE].get())->m_handle;
 
 		ANKI_VK_CHECK(vkCreateComputePipelines(
 			getDevice(), getGrManagerImpl().getPipelineCache(), 1, &ci, nullptr, &m_computePpline));

+ 8 - 3
src/anki/gr/vulkan/ShaderProgramImpl.h

@@ -5,6 +5,7 @@
 
 #pragma once
 
+#include <anki/gr/ShaderProgram.h>
 #include <anki/gr/vulkan/VulkanObject.h>
 #include <anki/gr/vulkan/PipelineLayout.h>
 
@@ -27,13 +28,17 @@ public:
 };
 
 /// Shader program implementation.
-class ShaderProgramImpl : public VulkanObject
+class ShaderProgramImpl final : public ShaderProgram, public VulkanObject<ShaderProgram, ShaderProgramImpl>
 {
 public:
-	ShaderProgramImpl(GrManager* manager);
+	ShaderProgramImpl(GrManager* manager)
+		: ShaderProgram(manager)
+	{
+	}
+
 	~ShaderProgramImpl();
 
-	Error init(const Array<ShaderPtr, U(ShaderType::COUNT)>& shaders);
+	Error init(const ShaderProgramInitInfo& inf);
 
 	Bool isGraphics() const
 	{

+ 3 - 16
src/anki/gr/vulkan/Texture.cpp

@@ -5,27 +5,14 @@
 
 #include <anki/gr/Texture.h>
 #include <anki/gr/vulkan/TextureImpl.h>
+#include <anki/gr/GrManager.h>
 
 namespace anki
 {
 
-Texture::Texture(GrManager* manager)
-	: GrObject(manager, CLASS_TYPE)
+Texture* Texture::newInstance(GrManager* manager, const TextureInitInfo& init)
 {
-}
-
-Texture::~Texture()
-{
-}
-
-void Texture::init(const TextureInitInfo& init)
-{
-	m_impl.reset(getAllocator().newInstance<TextureImpl>(&getManager(), getUuid()));
-
-	if(m_impl->init(init, this))
-	{
-		ANKI_VK_LOGF("Cannot recover");
-	}
+	return TextureImpl::newInstanceHelper(manager, init);
 }
 
 } // end namespace anki

+ 14 - 20
src/anki/gr/vulkan/TextureImpl.cpp

@@ -14,12 +14,6 @@
 namespace anki
 {
 
-TextureImpl::TextureImpl(GrManager* manager, U64 uuid)
-	: VulkanObject(manager)
-	, m_uuid(uuid)
-{
-}
-
 TextureImpl::~TextureImpl()
 {
 	for(auto it : m_viewsMap)
@@ -48,7 +42,7 @@ TextureImpl::~TextureImpl()
 	}
 }
 
-Error TextureImpl::init(const TextureInitInfo& init_, Texture* tex)
+Error TextureImpl::init(const TextureInitInfo& init_)
 {
 	TextureInitInfo init = init_;
 
@@ -64,7 +58,7 @@ Error TextureImpl::init(const TextureInitInfo& init_, Texture* tex)
 	m_width = init.m_width;
 	m_height = init.m_height;
 	m_depth = init.m_depth;
-	m_type = init.m_type;
+	m_texType = init.m_type;
 	if(init.getName())
 	{
 		strcpy(&m_name[0], init.getName().cstr());
@@ -74,7 +68,7 @@ Error TextureImpl::init(const TextureInitInfo& init_, Texture* tex)
 		m_name[0] = '\0';
 	}
 
-	if(m_type == TextureType::_3D)
+	if(m_texType == TextureType::_3D)
 	{
 		m_mipCount = min<U>(init.m_mipmapsCount, computeMaxMipmapCount3d(m_width, m_height, m_depth));
 	}
@@ -91,8 +85,6 @@ Error TextureImpl::init(const TextureInitInfo& init_, Texture* tex)
 	m_depthStencil = formatIsDepthStencil(m_format);
 	m_aspect = convertImageAspect(m_format);
 	m_usage = init.m_usage;
-	m_usageWhenEncountered = init.m_usageWhenEncountered;
-	ANKI_ASSERT((m_usageWhenEncountered | m_usage) == m_usage);
 
 	if(m_aspect & VK_IMAGE_ASPECT_DEPTH_BIT)
 	{
@@ -129,7 +121,7 @@ Error TextureImpl::init(const TextureInitInfo& init_, Texture* tex)
 
 		CommandBufferInitInfo cmdbinit;
 		cmdbinit.m_flags = CommandBufferFlag::GRAPHICS_WORK | CommandBufferFlag::SMALL_BATCH;
-		CommandBufferPtr cmdb = getGrManager().newInstance<CommandBuffer>(cmdbinit);
+		CommandBufferPtr cmdb = getManager().newCommandBuffer(cmdbinit);
 
 		VkImageSubresourceRange range;
 		range.aspectMask = m_aspect;
@@ -138,9 +130,10 @@ Error TextureImpl::init(const TextureInitInfo& init_, Texture* tex)
 		range.layerCount = m_layerCount;
 		range.levelCount = m_mipCount;
 
-		cmdb->m_impl->setTextureBarrierRange(TexturePtr(tex), TextureUsageBit::NONE, init.m_initialUsage, range);
+		static_cast<CommandBufferImpl&>(*cmdb).setTextureBarrierRange(
+			TexturePtr(this), TextureUsageBit::NONE, init.m_initialUsage, range);
 
-		cmdb->m_impl->endRecording();
+		static_cast<CommandBufferImpl&>(*cmdb).endRecording();
 		getGrManagerImpl().flushCommandBuffer(cmdb, nullptr);
 	}
 
@@ -269,12 +262,12 @@ Error TextureImpl::initImage(const TextureInitInfo& init_)
 	VkImageCreateInfo ci = {};
 	ci.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
 	ci.flags = calcCreateFlags(init);
-	ci.imageType = convertTextureType(m_type);
+	ci.imageType = convertTextureType(m_texType);
 	ci.format = m_vkFormat;
 	ci.extent.width = init.m_width;
 	ci.extent.height = init.m_height;
 
-	switch(m_type)
+	switch(m_texType)
 	{
 	case TextureType::_1D:
 	case TextureType::_2D:
@@ -676,7 +669,7 @@ VkImageLayout TextureImpl::computeLayout(TextureUsageBit usage, U level) const
 	return out;
 }
 
-VkImageView TextureImpl::getOrCreateSingleLevelView(U32 mip, DepthStencilAspectBit aspect)
+VkImageView TextureImpl::getOrCreateSingleLevelView(U32 mip, DepthStencilAspectBit aspect) const
 {
 	ANKI_ASSERT(mip < m_mipCount);
 
@@ -688,7 +681,8 @@ VkImageView TextureImpl::getOrCreateSingleLevelView(U32 mip, DepthStencilAspectB
 	return getOrCreateView(ci);
 }
 
-VkImageView TextureImpl::getOrCreateSingleSurfaceView(const TextureSurfaceInfo& surf, DepthStencilAspectBit aspect)
+VkImageView TextureImpl::getOrCreateSingleSurfaceView(
+	const TextureSurfaceInfo& surf, DepthStencilAspectBit aspect) const
 {
 	checkSurfaceOrVolume(surf);
 
@@ -699,7 +693,7 @@ VkImageView TextureImpl::getOrCreateSingleSurfaceView(const TextureSurfaceInfo&
 	return getOrCreateView(ci);
 }
 
-VkImageView TextureImpl::getOrCreateResourceGroupView(DepthStencilAspectBit aspect)
+VkImageView TextureImpl::getOrCreateResourceGroupView(DepthStencilAspectBit aspect) const
 {
 	VkImageViewCreateInfo ci = m_viewCreateInfoTemplate;
 	ci.subresourceRange.aspectMask = convertAspect(aspect);
@@ -707,7 +701,7 @@ VkImageView TextureImpl::getOrCreateResourceGroupView(DepthStencilAspectBit aspe
 	return getOrCreateView(ci);
 }
 
-VkImageView TextureImpl::getOrCreateView(const VkImageViewCreateInfo& ci)
+VkImageView TextureImpl::getOrCreateView(const VkImageViewCreateInfo& ci) const
 {
 	LockGuard<Mutex> lock(m_viewsMapMtx);
 	auto it = m_viewsMap.find(ci);

+ 15 - 21
src/anki/gr/vulkan/TextureImpl.h

@@ -5,6 +5,7 @@
 
 #pragma once
 
+#include <anki/gr/Texture.h>
 #include <anki/gr/vulkan/VulkanObject.h>
 #include <anki/gr/vulkan/GpuMemoryManager.h>
 #include <anki/gr/common/Misc.h>
@@ -30,7 +31,7 @@ enum class TextureImplWorkaround : U8
 ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(TextureImplWorkaround, inline)
 
 /// Texture container.
-class TextureImpl : public VulkanObject
+class TextureImpl final : public Texture, public VulkanObject<Texture, TextureImpl>
 {
 public:
 	MicroSamplerPtr m_sampler;
@@ -39,37 +40,31 @@ public:
 
 	GpuMemoryHandle m_memHandle;
 
-	U32 m_width = 0;
-	U32 m_height = 0;
-	U32 m_depth = 0;
-	TextureType m_type = TextureType::CUBE;
-	U8 m_mipCount = 0;
-	U32 m_layerCount = 0;
 	U32 m_surfaceOrVolumeCount = 0;
 	VkImageAspectFlags m_aspect = 0;
 	DepthStencilAspectBit m_akAspect = DepthStencilAspectBit::NONE;
-	TextureUsageBit m_usage = TextureUsageBit::NONE;
-	TextureUsageBit m_usageWhenEncountered = TextureUsageBit::NONE;
-	PixelFormat m_format;
 	VkFormat m_vkFormat = VK_FORMAT_UNDEFINED;
 
 	Bool m_depthStencil = false;
 	TextureImplWorkaround m_workarounds = TextureImplWorkaround::NONE;
 
-	TextureImpl(GrManager* manager, U64 uuid);
+	TextureImpl(GrManager* manager)
+		: Texture(manager)
+	{
+	}
 
 	~TextureImpl();
 
-	ANKI_USE_RESULT Error init(const TextureInitInfo& init, Texture* tex);
+	ANKI_USE_RESULT Error init(const TextureInitInfo& init);
 
 	void checkSurfaceOrVolume(const TextureSurfaceInfo& surf) const
 	{
-		checkTextureSurface(m_type, m_depth, m_mipCount, m_layerCount, surf);
+		checkTextureSurface(m_texType, m_depth, m_mipCount, m_layerCount, surf);
 	}
 
 	void checkSurfaceOrVolume(const TextureVolumeInfo& vol) const
 	{
-		ANKI_ASSERT(m_type == TextureType::_3D);
+		ANKI_ASSERT(m_texType == TextureType::_3D);
 		ANKI_ASSERT(vol.m_level < m_mipCount);
 	}
 
@@ -93,12 +88,12 @@ public:
 	}
 
 	/// For image load/store.
-	VkImageView getOrCreateSingleLevelView(U32 mip, DepthStencilAspectBit aspect);
+	VkImageView getOrCreateSingleLevelView(U32 mip, DepthStencilAspectBit aspect) const;
 
-	VkImageView getOrCreateSingleSurfaceView(const TextureSurfaceInfo& surf, DepthStencilAspectBit aspect);
+	VkImageView getOrCreateSingleSurfaceView(const TextureSurfaceInfo& surf, DepthStencilAspectBit aspect) const;
 
 	/// That view will be used in descriptor sets.
-	VkImageView getOrCreateResourceGroupView(DepthStencilAspectBit aspect);
+	VkImageView getOrCreateResourceGroupView(DepthStencilAspectBit aspect) const;
 
 	/// By knowing the previous and new texture usage calculate the relavant info for a ppline barrier.
 	void computeBarrierInfo(TextureUsageBit before,
@@ -132,10 +127,9 @@ private:
 		}
 	};
 
-	HashMap<VkImageViewCreateInfo, VkImageView, ViewHasher> m_viewsMap;
-	Mutex m_viewsMapMtx;
+	mutable HashMap<VkImageViewCreateInfo, VkImageView, ViewHasher> m_viewsMap;
+	mutable Mutex m_viewsMapMtx;
 	VkImageViewCreateInfo m_viewCreateInfoTemplate;
-	U64 m_uuid; ///< Steal the UUID from the Texture.
 
 	VkDeviceMemory m_dedicatedMem = VK_NULL_HANDLE;
 
@@ -149,7 +143,7 @@ private:
 
 	ANKI_USE_RESULT Error initImage(const TextureInitInfo& init);
 
-	VkImageView getOrCreateView(const VkImageViewCreateInfo& ci);
+	VkImageView getOrCreateView(const VkImageViewCreateInfo& ci) const;
 
 	U computeSubresourceIdx(const TextureSurfaceInfo& surf) const;
 

+ 3 - 3
src/anki/gr/vulkan/TextureImpl.inl.h

@@ -33,7 +33,7 @@ inline void TextureImpl::computeSubResourceRange(
 	range.aspectMask = convertAspect(aspect);
 	range.baseMipLevel = surf.m_level;
 	range.levelCount = 1;
-	switch(m_type)
+	switch(m_texType)
 	{
 	case TextureType::_2D:
 		range.baseArrayLayer = 0;
@@ -72,7 +72,7 @@ inline U TextureImpl::computeVkArrayLayer(const TextureSurfaceInfo& surf) const
 {
 	checkSurfaceOrVolume(surf);
 	U layer = 0;
-	switch(m_type)
+	switch(m_texType)
 	{
 	case TextureType::_2D:
 		layer = 0;
@@ -100,7 +100,7 @@ inline U TextureImpl::computeSubresourceIdx(const TextureSurfaceInfo& surf) cons
 {
 	checkSurfaceOrVolume(surf);
 
-	switch(m_type)
+	switch(m_texType)
 	{
 	case TextureType::_1D:
 	case TextureType::_2D:

+ 30 - 18
src/anki/gr/vulkan/VulkanObject.cpp

@@ -7,27 +7,39 @@
 #include <anki/gr/GrManager.h>
 #include <anki/gr/vulkan/GrManagerImpl.h>
 
-namespace anki
-{
-
-VkDevice VulkanObject::getDevice() const
-{
-	return m_manager->getImplementation().getDevice();
-}
+#include <anki/gr/vulkan/BufferImpl.h>
+#include <anki/gr/vulkan/TextureImpl.h>
+#include <anki/gr/vulkan/SamplerImpl.h>
+#include <anki/gr/vulkan/ShaderImpl.h>
+#include <anki/gr/vulkan/ShaderProgramImpl.h>
+#include <anki/gr/vulkan/CommandBufferImpl.h>
+#include <anki/gr/vulkan/FramebufferImpl.h>
+#include <anki/gr/vulkan/OcclusionQueryImpl.h>
+#include <anki/gr/vulkan/FenceImpl.h>
 
-GrAllocator<U8> VulkanObject::getAllocator() const
+namespace anki
 {
-	return m_manager->getAllocator();
-}
 
-GrManagerImpl& VulkanObject::getGrManagerImpl()
-{
-	return m_manager->getImplementation();
-}
+#define ANKI_INSTANTIATE_GR_OBJECT(type_)                                                              \
+	template<>                                                                                         \
+	VkDevice VulkanObject<type_, type_##Impl>::getDevice() const                                       \
+	{                                                                                                  \
+		return getGrManagerImpl().getDevice();                                                         \
+	}                                                                                                  \
+	template<>                                                                                         \
+	GrManagerImpl& VulkanObject<type_, type_##Impl>::getGrManagerImpl()                                \
+	{                                                                                                  \
+		return static_cast<GrManagerImpl&>(static_cast<type_##Impl*>(this)->getManager());             \
+	}                                                                                                  \
+	template<>                                                                                         \
+	const GrManagerImpl& VulkanObject<type_, type_##Impl>::getGrManagerImpl() const                    \
+	{                                                                                                  \
+		return static_cast<const GrManagerImpl&>(static_cast<const type_##Impl*>(this)->getManager()); \
+	}
 
-const GrManagerImpl& VulkanObject::getGrManagerImpl() const
-{
-	return m_manager->getImplementation();
-}
+#define ANKI_INSTANTIATE_GR_OBJECT_DELIMITER()
+#include <anki/gr/common/InstantiationMacros.h>
+#undef ANKI_INSTANTIATE_GR_OBJECT_DELIMITER
+#undef ANKI_INSTANTIATE_GR_OBJECT
 
 } // end namespace anki

+ 20 - 21
src/anki/gr/vulkan/VulkanObject.h

@@ -13,37 +13,36 @@ namespace anki
 /// @addtogroup vulkan
 /// @{
 
-/// The base class for all Vulkan object implementations.
+/// Halper class that extends the XXXImpl objects.
+template<typename TBaseClass, typename TImplClass>
 class VulkanObject
 {
 public:
-	VulkanObject(GrManager* manager)
-		: m_manager(manager)
-	{
-		ANKI_ASSERT(manager);
-	}
-
-	virtual ~VulkanObject()
-	{
-	}
-
 	VkDevice getDevice() const;
 
-	GrAllocator<U8> getAllocator() const;
-
 	GrManagerImpl& getGrManagerImpl();
 
 	const GrManagerImpl& getGrManagerImpl() const;
 
-	GrManager& getGrManager()
-	{
-		ANKI_ASSERT(m_manager);
-		return *m_manager;
-	}
-
-protected:
-	GrManager* m_manager = nullptr;
+	/// Convenience method to allocate and initialize an XXXImpl.
+	template<typename TGrManager, typename... TArgs>
+	static ANKI_USE_RESULT TBaseClass* newInstanceHelper(TGrManager* manager, TArgs&&... args);
 };
+
+// Do this trick to avoid including heavy headers
+#define ANKI_INSTANTIATE_GR_OBJECT(type_)                                \
+	template<>                                                           \
+	VkDevice VulkanObject<type_, type_##Impl>::getDevice() const;        \
+	template<>                                                           \
+	GrManagerImpl& VulkanObject<type_, type_##Impl>::getGrManagerImpl(); \
+	template<>                                                           \
+	const GrManagerImpl& VulkanObject<type_, type_##Impl>::getGrManagerImpl() const;
+#define ANKI_INSTANTIATE_GR_OBJECT_DELIMITER()
+#include <anki/gr/common/InstantiationMacros.h>
+#undef ANKI_INSTANTIATE_GR_OBJECT_DELIMITER
+#undef ANKI_INSTANTIATE_GR_OBJECT
 /// @}
 
 } // end namespace anki
+
+#include <anki/gr/vulkan/VulkanObject.inl.h>

+ 27 - 0
src/anki/gr/vulkan/VulkanObject.inl.h

@@ -0,0 +1,27 @@
+// Copyright (C) 2009-2017, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <anki/gr/vulkan/VulkanObject.h>
+
+namespace anki
+{
+
+template<typename TBaseClass, typename TImplClass>
+template<typename TGrManager, typename... TArgs>
+inline TBaseClass* VulkanObject<TBaseClass, TImplClass>::newInstanceHelper(TGrManager* manager, TArgs&&... args)
+{
+	TImplClass* impl = manager->getAllocator().template newInstance<TImplClass>(manager);
+	Error err = impl->init(std::forward<TArgs>(args)...);
+	if(err)
+	{
+		manager->getAllocator().deleteInstance(impl);
+		impl = nullptr;
+		ANKI_VK_LOGF("Error while creating an instance. Will not try to recover");
+	}
+
+	return impl;
+}
+
+} // end namespace anki

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

@@ -39,7 +39,7 @@ Error DebugDrawer::init(Renderer* r)
 	// Create the vert buffs
 	for(BufferPtr& v : m_vertBuff)
 	{
-		v = gr.newInstance<Buffer>(BufferInitInfo(
+		v = gr.newBuffer(BufferInitInfo(
 			sizeof(Vertex) * MAX_VERTS_PER_FRAME, BufferUsageBit::VERTEX, BufferMapAccessBit::WRITE, "DbgDrawer"));
 	}
 

+ 4 - 6
src/anki/renderer/Indirect.cpp

@@ -81,7 +81,7 @@ Error Indirect::initInternal(const ConfigSet& config)
 	sinit.m_minLod = 0.0;
 	sinit.m_maxLod = 1.0;
 	sinit.m_repeat = false;
-	m_integrationLutSampler = getGrManager().newInstance<Sampler>(sinit);
+	m_integrationLutSampler = getGrManager().newSampler(sinit);
 
 	return Error::NONE;
 }
@@ -92,12 +92,12 @@ Error Indirect::loadMesh(CString fname, BufferPtr& vert, BufferPtr& idx, U32& id
 	ANKI_CHECK(loader.load(fname));
 
 	PtrSize vertBuffSize = loader.getHeader().m_totalVerticesCount * sizeof(Vec3);
-	vert = getGrManager().newInstance<Buffer>(BufferInitInfo(vertBuffSize,
+	vert = getGrManager().newBuffer(BufferInitInfo(vertBuffSize,
 		BufferUsageBit::VERTEX | BufferUsageBit::BUFFER_UPLOAD_DESTINATION,
 		BufferMapAccessBit::NONE,
 		"IndirectMesh"));
 
-	idx = getGrManager().newInstance<Buffer>(BufferInitInfo(loader.getIndexDataSize(),
+	idx = getGrManager().newBuffer(BufferInitInfo(loader.getIndexDataSize(),
 		BufferUsageBit::INDEX | BufferUsageBit::BUFFER_UPLOAD_DESTINATION,
 		BufferMapAccessBit::NONE,
 		"IndirectMesh"));
@@ -105,7 +105,7 @@ Error Indirect::loadMesh(CString fname, BufferPtr& vert, BufferPtr& idx, U32& id
 	// Upload data
 	CommandBufferInitInfo init;
 	init.m_flags = CommandBufferFlag::SMALL_BATCH;
-	CommandBufferPtr cmdb = getGrManager().newInstance<CommandBuffer>(init);
+	CommandBufferPtr cmdb = getGrManager().newCommandBuffer(init);
 
 	TransferGpuAllocatorHandle handle;
 	ANKI_CHECK(m_r->getResourceManager().getTransferGpuAllocator().allocate(vertBuffSize, handle));
@@ -207,7 +207,6 @@ Error Indirect::initLightShading(const ConfigSet& config)
 		texinit.m_type = TextureType::CUBE_ARRAY;
 		texinit.m_layerCount = m_cacheEntries.getSize();
 		texinit.m_initialUsage = TextureUsageBit::SAMPLED_FRAGMENT;
-		texinit.m_usageWhenEncountered = TextureUsageBit::SAMPLED_FRAGMENT;
 
 		m_lightShading.m_cubeArr = m_r->createAndClearRenderTarget(texinit);
 	}
@@ -259,7 +258,6 @@ Error Indirect::initIrradiance(const ConfigSet& config)
 		texinit.m_layerCount = m_cacheEntries.getSize();
 		texinit.m_type = TextureType::CUBE_ARRAY;
 		texinit.m_initialUsage = TextureUsageBit::SAMPLED_FRAGMENT;
-		texinit.m_usageWhenEncountered = TextureUsageBit::SAMPLED_FRAGMENT;
 
 		m_irradiance.m_cubeArr = m_r->createAndClearRenderTarget(texinit);
 	}

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

@@ -76,7 +76,7 @@ Error LensFlare::initOcclusion(const ConfigSet& config)
 {
 	GrManager& gr = getGrManager();
 
-	m_indirectBuff = gr.newInstance<Buffer>(BufferInitInfo(m_maxFlares * sizeof(DrawArraysIndirectInfo),
+	m_indirectBuff = gr.newBuffer(BufferInitInfo(m_maxFlares * sizeof(DrawArraysIndirectInfo),
 		BufferUsageBit::INDIRECT | BufferUsageBit::STORAGE_COMPUTE_WRITE,
 		BufferMapAccessBit::NONE,
 		"LensFlares"));

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

@@ -71,7 +71,7 @@ Error MainRenderer::init(ThreadPool* threadpool,
 		ANKI_R_LOGI("The main renderer will have to blit the offscreen renderer's result");
 	}
 
-	m_rgraph = gr->newInstance<RenderGraph>();
+	m_rgraph = gr->newRenderGraph();
 
 	ANKI_R_LOGI("Main renderer initialized. Rendering size %ux%u", m_width, m_height);
 

+ 7 - 8
src/anki/renderer/Renderer.cpp

@@ -92,12 +92,11 @@ Error Renderer::initInternal(const ConfigSet& config)
 		texinit.m_width = texinit.m_height = 4;
 		texinit.m_usage = TextureUsageBit::SAMPLED_FRAGMENT;
 		texinit.m_format = PixelFormat(ComponentFormat::R8G8B8A8, TransformFormat::UNORM);
-		texinit.m_usageWhenEncountered = TextureUsageBit::SAMPLED_FRAGMENT;
 		texinit.m_initialUsage = TextureUsageBit::SAMPLED_FRAGMENT;
-		m_dummyTex = getGrManager().newInstance<Texture>(texinit);
+		m_dummyTex = getGrManager().newTexture(texinit);
 	}
 
-	m_dummyBuff = getGrManager().newInstance<Buffer>(BufferInitInfo(getDummyBufferSize(),
+	m_dummyBuff = getGrManager().newBuffer(BufferInitInfo(getDummyBufferSize(),
 		BufferUsageBit::UNIFORM_ALL | BufferUsageBit::STORAGE_ALL,
 		BufferMapAccessBit::NONE,
 		"Dummy"));
@@ -151,10 +150,10 @@ Error Renderer::initInternal(const ConfigSet& config)
 	SamplerInitInfo sinit;
 	sinit.m_repeat = false;
 	sinit.m_minMagFilter = SamplingFilter::NEAREST;
-	m_nearestSampler = m_gr->newInstance<Sampler>(sinit);
+	m_nearestSampler = m_gr->newSampler(sinit);
 
 	sinit.m_minMagFilter = SamplingFilter::LINEAR;
-	m_linearSampler = m_gr->newInstance<Sampler>(sinit);
+	m_linearSampler = m_gr->newSampler(sinit);
 
 	initJitteredMats();
 
@@ -344,7 +343,7 @@ TexturePtr Renderer::createAndClearRenderTarget(const TextureInitInfo& inf, cons
 	const U faceCount = (inf.m_type == TextureType::CUBE || inf.m_type == TextureType::CUBE_ARRAY) ? 6 : 1;
 
 	// Create tex
-	TexturePtr tex = m_gr->newInstance<Texture>(inf);
+	TexturePtr tex = m_gr->newTexture(inf);
 
 	// Clear all surfaces
 	CommandBufferInitInfo cmdbinit;
@@ -353,7 +352,7 @@ TexturePtr Renderer::createAndClearRenderTarget(const TextureInitInfo& inf, cons
 	{
 		cmdbinit.m_flags |= CommandBufferFlag::SMALL_BATCH;
 	}
-	CommandBufferPtr cmdb = m_gr->newInstance<CommandBuffer>(cmdbinit);
+	CommandBufferPtr cmdb = m_gr->newCommandBuffer(cmdbinit);
 
 	for(U mip = 0; mip < inf.m_mipmapsCount; ++mip)
 	{
@@ -388,7 +387,7 @@ TexturePtr Renderer::createAndClearRenderTarget(const TextureInitInfo& inf, cons
 
 					colUsage[0] = TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE;
 				}
-				FramebufferPtr fb = m_gr->newInstance<Framebuffer>(fbInit);
+				FramebufferPtr fb = m_gr->newFramebuffer(fbInit);
 
 				cmdb->setTextureSurfaceBarrier(
 					tex, TextureUsageBit::NONE, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE, surf);

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

@@ -38,14 +38,14 @@ Error Tonemapping::initInternal(const ConfigSet& initializer)
 	m_grProg = variant->getProgram();
 
 	// Create buffer
-	m_luminanceBuff = getGrManager().newInstance<Buffer>(BufferInitInfo(sizeof(Vec4),
+	m_luminanceBuff = getGrManager().newBuffer(BufferInitInfo(sizeof(Vec4),
 		BufferUsageBit::STORAGE_ALL | BufferUsageBit::UNIFORM_ALL | BufferUsageBit::BUFFER_UPLOAD_DESTINATION,
 		BufferMapAccessBit::NONE,
 		"AvgLum"));
 
 	CommandBufferInitInfo cmdbinit;
 	cmdbinit.m_flags = CommandBufferFlag::SMALL_BATCH | CommandBufferFlag::TRANSFER_WORK;
-	CommandBufferPtr cmdb = getGrManager().newInstance<CommandBuffer>(cmdbinit);
+	CommandBufferPtr cmdb = getGrManager().newCommandBuffer(cmdbinit);
 
 	TransferGpuAllocatorHandle handle;
 	ANKI_CHECK(m_r->getResourceManager().getTransferGpuAllocator().allocate(sizeof(Vec4), handle));

+ 4 - 4
src/anki/resource/Mesh.cpp

@@ -102,12 +102,12 @@ Error Mesh::load(const ResourceFilename& filename, Bool async)
 	// Allocate the buffers
 	GrManager& gr = getManager().getGrManager();
 
-	m_vertBuff = gr.newInstance<Buffer>(BufferInitInfo(loader.getVertexDataSize(),
+	m_vertBuff = gr.newBuffer(BufferInitInfo(loader.getVertexDataSize(),
 		BufferUsageBit::VERTEX | BufferUsageBit::BUFFER_UPLOAD_DESTINATION | BufferUsageBit::FILL,
 		BufferMapAccessBit::NONE,
 		"MeshVert"));
 
-	m_indicesBuff = gr.newInstance<Buffer>(BufferInitInfo(loader.getIndexDataSize(),
+	m_indicesBuff = gr.newBuffer(BufferInitInfo(loader.getIndexDataSize(),
 		BufferUsageBit::INDEX | BufferUsageBit::BUFFER_UPLOAD_DESTINATION | BufferUsageBit::FILL,
 		BufferMapAccessBit::NONE,
 		"MeshIdx"));
@@ -115,7 +115,7 @@ Error Mesh::load(const ResourceFilename& filename, Bool async)
 	// Clear them
 	CommandBufferInitInfo cmdbinit;
 	cmdbinit.m_flags = CommandBufferFlag::SMALL_BATCH;
-	CommandBufferPtr cmdb = gr.newInstance<CommandBuffer>(cmdbinit);
+	CommandBufferPtr cmdb = gr.newCommandBuffer(cmdbinit);
 
 	cmdb->fillBuffer(m_vertBuff, 0, MAX_PTR_SIZE, 0);
 	cmdb->fillBuffer(m_indicesBuff, 0, MAX_PTR_SIZE, 0);
@@ -150,7 +150,7 @@ Error Mesh::load(LoadContext& ctx)
 
 	CommandBufferInitInfo cmdbinit;
 	cmdbinit.m_flags = CommandBufferFlag::SMALL_BATCH | CommandBufferFlag::TRANSFER_WORK;
-	CommandBufferPtr cmdb = gr.newInstance<CommandBuffer>(cmdbinit);
+	CommandBufferPtr cmdb = gr.newCommandBuffer(cmdbinit);
 
 	// Set barriers
 	cmdb->setBufferBarrier(

+ 8 - 8
src/anki/resource/ShaderProgramResource.cpp

@@ -1073,7 +1073,7 @@ void ShaderProgramResource::initVariant(WeakArray<const ShaderProgramResourceMut
 	shaderHeaderSrc.join("", shaderHeader);
 
 	// Create the shaders and the program
-	Array<ShaderPtr, U(ShaderType::COUNT)> shaders;
+	ShaderProgramInitInfo progInf;
 	for(ShaderType i = ShaderType::FIRST; i < ShaderType::COUNT; ++i)
 	{
 		if(!m_sources[i])
@@ -1085,20 +1085,20 @@ void ShaderProgramResource::initVariant(WeakArray<const ShaderProgramResourceMut
 		src.append(shaderHeader);
 		src.append(m_sources[i]);
 
-		shaders[i] = getManager().getGrManager().newInstance<Shader>(i, src.toCString());
+		ShaderInitInfo inf("RsrcShader");
+		inf.m_shaderType = i;
+		inf.m_source = src.toCString();
+
+		progInf.m_shaders[i] = getManager().getGrManager().newShader(inf);
 	}
 
 	if(!m_compute)
 	{
-		variant.m_prog = getManager().getGrManager().newInstance<ShaderProgram>(shaders[ShaderType::VERTEX],
-			shaders[ShaderType::TESSELLATION_CONTROL],
-			shaders[ShaderType::TESSELLATION_EVALUATION],
-			shaders[ShaderType::GEOMETRY],
-			shaders[ShaderType::FRAGMENT]);
+		variant.m_prog = getManager().getGrManager().newShaderProgram(progInf);
 	}
 	else
 	{
-		variant.m_prog = getManager().getGrManager().newInstance<ShaderProgram>(shaders[ShaderType::COMPUTE]);
+		variant.m_prog = getManager().getGrManager().newShaderProgram(progInf);
 	}
 }
 

+ 2 - 3
src/anki/resource/TextureResource.cpp

@@ -70,7 +70,6 @@ Error TextureResource::load(const ResourceFilename& filename, Bool async)
 	TextureInitInfo init("RsrcTex");
 	init.m_usage = TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::SAMPLED_TESSELLATION_EVALUATION
 		| TextureUsageBit::TRANSFER_DESTINATION;
-	init.m_usageWhenEncountered = TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::SAMPLED_TESSELLATION_EVALUATION;
 	U faces = 0;
 
 	ResourceFilePtr file;
@@ -174,7 +173,7 @@ Error TextureResource::load(const ResourceFilename& filename, Bool async)
 	init.m_sampling.m_anisotropyLevel = getManager().getTextureAnisotropy();
 
 	// Create the texture
-	m_tex = getManager().getGrManager().newInstance<Texture>(init);
+	m_tex = getManager().getGrManager().newTexture(init);
 
 	// Set the context
 	ctx->m_faces = faces;
@@ -210,7 +209,7 @@ Error TextureResource::load(LoadingContext& ctx)
 
 		CommandBufferInitInfo ci;
 		ci.m_flags = CommandBufferFlag::TRANSFER_WORK | CommandBufferFlag::SMALL_BATCH;
-		CommandBufferPtr cmdb = ctx.m_gr->newInstance<CommandBuffer>(ci);
+		CommandBufferPtr cmdb = ctx.m_gr->newCommandBuffer(ci);
 
 		// Set the barriers of the batch
 		for(U i = begin; i < end; ++i)

+ 1 - 1
src/anki/resource/TransferGpuAllocator.cpp

@@ -34,7 +34,7 @@ public:
 	{
 		TransferGpuAllocator::Memory* mm = m_alloc.newInstance<TransferGpuAllocator::Memory>();
 
-		mm->m_buffer = m_gr->newInstance<Buffer>(
+		mm->m_buffer = m_gr->newBuffer(
 			BufferInitInfo(size, BufferUsageBit::BUFFER_UPLOAD_SOURCE, BufferMapAccessBit::WRITE, "Transfer"));
 		mm->m_mappedMemory = mm->m_buffer->map(0, size, BufferMapAccessBit::WRITE);
 

+ 3 - 4
src/anki/ui/Font.cpp

@@ -70,7 +70,7 @@ void Font::createTexture(const void* data, U32 width, U32 height)
 
 	// Create and populate the buffer
 	PtrSize buffSize = width * height * 4;
-	BufferPtr buff = m_manager->getGrManager().newInstance<Buffer>(
+	BufferPtr buff = m_manager->getGrManager().newBuffer(
 		BufferInitInfo(buffSize, BufferUsageBit::BUFFER_UPLOAD_DESTINATION, BufferMapAccessBit::WRITE, "UI"));
 	void* mapped = buff->map(0, buffSize, BufferMapAccessBit::WRITE);
 	memcpy(mapped, data, buffSize);
@@ -83,17 +83,16 @@ void Font::createTexture(const void* data, U32 width, U32 height)
 	texInit.m_format = PixelFormat(ComponentFormat::R8G8B8A8, TransformFormat::UNORM);
 	texInit.m_usage =
 		TextureUsageBit::TRANSFER_DESTINATION | TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::GENERATE_MIPMAPS;
-	texInit.m_usageWhenEncountered = TextureUsageBit::SAMPLED_FRAGMENT;
 	texInit.m_mipmapsCount = 4;
 	texInit.m_sampling.m_minMagFilter = SamplingFilter::NEAREST;
 	texInit.m_sampling.m_mipmapFilter = SamplingFilter::NEAREST;
 
-	m_tex = m_manager->getGrManager().newInstance<Texture>(texInit);
+	m_tex = m_manager->getGrManager().newTexture(texInit);
 
 	// Do the copy
 	CommandBufferInitInfo cmdbInit;
 	cmdbInit.m_flags = CommandBufferFlag::TRANSFER_WORK | CommandBufferFlag::SMALL_BATCH;
-	CommandBufferPtr cmdb = m_manager->getGrManager().newInstance<CommandBuffer>(cmdbInit);
+	CommandBufferPtr cmdb = m_manager->getGrManager().newCommandBuffer(cmdbInit);
 
 	TextureSurfaceInfo surf(0, 0, 0, 0);
 

+ 2 - 3
tests/framework/Framework.cpp

@@ -247,14 +247,13 @@ NativeWindow* createWindow(const Config& cfg)
 
 GrManager* createGrManager(const Config& cfg, NativeWindow* win)
 {
-	GrManager* gr = new GrManager();
-
 	GrManagerInitInfo inf;
 	inf.m_allocCallback = allocAligned;
 	inf.m_cacheDirectory = "./";
 	inf.m_config = &cfg;
 	inf.m_window = win;
-	ANKI_TEST_EXPECT_NO_ERR(gr->init(inf));
+	GrManager* gr;
+	ANKI_TEST_EXPECT_NO_ERR(GrManager::newInstance(inf, gr));
 
 	return gr;
 }

+ 60 - 57
tests/gr/Gr.cpp

@@ -300,15 +300,15 @@ static StagingGpuMemoryManager* stagingMem = nullptr;
 	ANKI_TEST_EXPECT_NO_ERR(transfAlloc->init(128_MB, gr, gr->getAllocator())); \
 	{
 
-#define COMMON_END()    \
-	}                   \
-	gr->finish();       \
-	delete transfAlloc; \
-	delete stagingMem;  \
-	delete gr;          \
-	delete win;         \
-	win = nullptr;      \
-	gr = nullptr;       \
+#define COMMON_END()               \
+	}                              \
+	gr->finish();                  \
+	delete transfAlloc;            \
+	delete stagingMem;             \
+	GrManager::deleteInstance(gr); \
+	delete win;                    \
+	win = nullptr;                 \
+	gr = nullptr;                  \
 	stagingMem = nullptr;
 
 static void* setUniforms(PtrSize size, CommandBufferPtr& cmdb, U set, U binding)
@@ -352,9 +352,13 @@ const PixelFormat DS_FORMAT = PixelFormat(ComponentFormat::D24S8, TransformForma
 
 static ShaderProgramPtr createProgram(CString vertSrc, CString fragSrc, GrManager& gr)
 {
-	ShaderPtr vert = gr.newInstance<Shader>(ShaderType::VERTEX, vertSrc);
-	ShaderPtr frag = gr.newInstance<Shader>(ShaderType::FRAGMENT, fragSrc);
-	return gr.newInstance<ShaderProgram>(vert, frag);
+	ShaderPtr vert = gr.newShader({ShaderType::VERTEX, vertSrc});
+	ShaderPtr frag = gr.newShader({ShaderType::FRAGMENT, fragSrc});
+
+	ShaderProgramInitInfo inf;
+	inf.m_shaders[ShaderType::VERTEX] = vert;
+	inf.m_shaders[ShaderType::FRAGMENT] = frag;
+	return gr.newShaderProgram(inf);
 }
 
 static FramebufferPtr createDefaultFb(GrManager& gr)
@@ -363,7 +367,7 @@ static FramebufferPtr createDefaultFb(GrManager& gr)
 	fbinit.m_colorAttachmentCount = 1;
 	fbinit.m_colorAttachments[0].m_clearValue.m_colorf = {{1.0, 0.0, 1.0, 1.0}};
 
-	return gr.newInstance<Framebuffer>(fbinit);
+	return gr.newFramebuffer(fbinit);
 }
 
 static void createCube(GrManager& gr, BufferPtr& verts, BufferPtr& indices)
@@ -374,13 +378,13 @@ static void createCube(GrManager& gr, BufferPtr& verts, BufferPtr& indices)
 	static const Array<U16, 6 * 2 * 3> idx = {
 		{0, 1, 3, 3, 1, 2, 1, 5, 6, 1, 6, 2, 7, 4, 0, 7, 0, 3, 6, 5, 7, 7, 5, 4, 0, 4, 5, 0, 5, 1, 3, 2, 6, 3, 6, 7}};
 
-	verts = gr.newInstance<Buffer>(BufferInitInfo(sizeof(pos), BufferUsageBit::VERTEX, BufferMapAccessBit::WRITE));
+	verts = gr.newBuffer(BufferInitInfo(sizeof(pos), BufferUsageBit::VERTEX, BufferMapAccessBit::WRITE));
 
 	void* mapped = verts->map(0, sizeof(pos), BufferMapAccessBit::WRITE);
 	memcpy(mapped, &pos[0], sizeof(pos));
 	verts->unmap();
 
-	indices = gr.newInstance<Buffer>(BufferInitInfo(sizeof(idx), BufferUsageBit::INDEX, BufferMapAccessBit::WRITE));
+	indices = gr.newBuffer(BufferInitInfo(sizeof(idx), BufferUsageBit::INDEX, BufferMapAccessBit::WRITE));
 	mapped = indices->map(0, sizeof(idx), BufferMapAccessBit::WRITE);
 	memcpy(mapped, &idx[0], sizeof(idx));
 	indices->unmap();
@@ -392,7 +396,7 @@ ANKI_TEST(Gr, Shader)
 {
 	COMMON_BEGIN()
 
-	ShaderPtr shader = gr->newInstance<Shader>(ShaderType::FRAGMENT, FRAG_MRT_SRC);
+	ShaderPtr shader = gr->newShader({ShaderType::FRAGMENT, FRAG_MRT_SRC});
 
 	COMMON_END()
 }
@@ -423,7 +427,7 @@ ANKI_TEST(Gr, ClearScreen)
 
 		CommandBufferInitInfo cinit;
 		cinit.m_flags = CommandBufferFlag::GRAPHICS_WORK | CommandBufferFlag::SMALL_BATCH;
-		CommandBufferPtr cmdb = gr->newInstance<CommandBuffer>(cinit);
+		CommandBufferPtr cmdb = gr->newCommandBuffer(cinit);
 
 		cmdb->beginRenderPass(fb, {}, {});
 		cmdb->endRenderPass();
@@ -460,7 +464,7 @@ ANKI_TEST(Gr, SimpleDrawcall)
 
 		CommandBufferInitInfo cinit;
 		cinit.m_flags = CommandBufferFlag::GRAPHICS_WORK;
-		CommandBufferPtr cmdb = gr->newInstance<CommandBuffer>(cinit);
+		CommandBufferPtr cmdb = gr->newCommandBuffer(cinit);
 
 		cmdb->setViewport(0, 0, WIDTH, HEIGHT);
 		cmdb->bindShaderProgram(prog);
@@ -498,7 +502,7 @@ ANKI_TEST(Gr, ViewportAndScissor)
 		fbinit.m_colorAttachmentCount = 1;
 		fbinit.m_colorAttachments[0].m_clearValue.m_colorf = {{randFloat(1.0), randFloat(1.0), randFloat(1.0), 1.0}};
 
-		f = gr->newInstance<Framebuffer>(fbinit);
+		f = gr->newFramebuffer(fbinit);
 	}
 
 	static const Array2d<U, 4, 4> VIEWPORTS = {{{{0, 0, WIDTH / 2, HEIGHT / 2}},
@@ -518,7 +522,7 @@ ANKI_TEST(Gr, ViewportAndScissor)
 
 		CommandBufferInitInfo cinit;
 		cinit.m_flags = CommandBufferFlag::GRAPHICS_WORK | CommandBufferFlag::SMALL_BATCH;
-		CommandBufferPtr cmdb = gr->newInstance<CommandBuffer>(cinit);
+		CommandBufferPtr cmdb = gr->newCommandBuffer(cinit);
 
 		U idx = (i / 30) % 4;
 		auto vp = VIEWPORTS[idx];
@@ -577,7 +581,7 @@ ANKI_TEST(Gr, ViewportAndScissorOffscreen)
 	init.m_sampling.m_minMagFilter = SamplingFilter::NEAREST;
 	init.m_sampling.m_mipmapFilter = SamplingFilter::NEAREST;
 	init.m_type = TextureType::_2D;
-	TexturePtr rt = gr->newInstance<Texture>(init);
+	TexturePtr rt = gr->newTexture(init);
 
 	Array<FramebufferPtr, 4> fb;
 	for(FramebufferPtr& f : fb)
@@ -587,7 +591,7 @@ ANKI_TEST(Gr, ViewportAndScissorOffscreen)
 		fbinit.m_colorAttachments[0].m_clearValue.m_colorf = {{randFloat(1.0), randFloat(1.0), randFloat(1.0), 1.0}};
 		fbinit.m_colorAttachments[0].m_texture = rt;
 
-		f = gr->newInstance<Framebuffer>(fbinit);
+		f = gr->newFramebuffer(fbinit);
 	}
 
 	FramebufferPtr defaultFb = createDefaultFb(*gr);
@@ -611,7 +615,7 @@ ANKI_TEST(Gr, ViewportAndScissorOffscreen)
 		{
 			CommandBufferInitInfo cinit;
 			cinit.m_flags = CommandBufferFlag::GRAPHICS_WORK | CommandBufferFlag::SMALL_BATCH;
-			CommandBufferPtr cmdb = gr->newInstance<CommandBuffer>(cinit);
+			CommandBufferPtr cmdb = gr->newCommandBuffer(cinit);
 
 			cmdb->setViewport(0, 0, RT_WIDTH, RT_HEIGHT);
 			cmdb->setTextureSurfaceBarrier(rt,
@@ -629,7 +633,7 @@ ANKI_TEST(Gr, ViewportAndScissorOffscreen)
 
 		CommandBufferInitInfo cinit;
 		cinit.m_flags = CommandBufferFlag::GRAPHICS_WORK | CommandBufferFlag::SMALL_BATCH;
-		CommandBufferPtr cmdb = gr->newInstance<CommandBuffer>(cinit);
+		CommandBufferPtr cmdb = gr->newCommandBuffer(cinit);
 
 		// Draw offscreen
 		cmdb->setTextureSurfaceBarrier(rt,
@@ -683,9 +687,9 @@ ANKI_TEST(Gr, Buffer)
 {
 	COMMON_BEGIN()
 
-	BufferPtr a = gr->newInstance<Buffer>(BufferInitInfo(512, BufferUsageBit::UNIFORM_ALL, BufferMapAccessBit::NONE));
+	BufferPtr a = gr->newBuffer(BufferInitInfo(512, BufferUsageBit::UNIFORM_ALL, BufferMapAccessBit::NONE));
 
-	BufferPtr b = gr->newInstance<Buffer>(
+	BufferPtr b = gr->newBuffer(
 		BufferInitInfo(64, BufferUsageBit::STORAGE_ALL, BufferMapAccessBit::WRITE | BufferMapAccessBit::READ));
 
 	void* ptr = b->map(0, 64, BufferMapAccessBit::WRITE);
@@ -708,8 +712,8 @@ ANKI_TEST(Gr, DrawWithUniforms)
 	COMMON_BEGIN()
 
 	// A non-uploaded buffer
-	BufferPtr b = gr->newInstance<Buffer>(
-		BufferInitInfo(sizeof(Vec4) * 3, BufferUsageBit::UNIFORM_ALL, BufferMapAccessBit::WRITE));
+	BufferPtr b =
+		gr->newBuffer(BufferInitInfo(sizeof(Vec4) * 3, BufferUsageBit::UNIFORM_ALL, BufferMapAccessBit::WRITE));
 
 	Vec4* ptr = static_cast<Vec4*>(b->map(0, sizeof(Vec4) * 3, BufferMapAccessBit::WRITE));
 	ANKI_TEST_EXPECT_NEQ(ptr, nullptr);
@@ -734,7 +738,7 @@ ANKI_TEST(Gr, DrawWithUniforms)
 
 		CommandBufferInitInfo cinit;
 		cinit.m_flags = CommandBufferFlag::GRAPHICS_WORK;
-		CommandBufferPtr cmdb = gr->newInstance<CommandBuffer>(cinit);
+		CommandBufferPtr cmdb = gr->newCommandBuffer(cinit);
 
 		cmdb->setViewport(0, 0, WIDTH, HEIGHT);
 		cmdb->bindShaderProgram(prog);
@@ -779,8 +783,7 @@ ANKI_TEST(Gr, DrawWithVertex)
 	};
 	static_assert(sizeof(Vert) == sizeof(Vec4), "See file");
 
-	BufferPtr b =
-		gr->newInstance<Buffer>(BufferInitInfo(sizeof(Vert) * 3, BufferUsageBit::VERTEX, BufferMapAccessBit::WRITE));
+	BufferPtr b = gr->newBuffer(BufferInitInfo(sizeof(Vert) * 3, BufferUsageBit::VERTEX, BufferMapAccessBit::WRITE));
 
 	Vert* ptr = static_cast<Vert*>(b->map(0, sizeof(Vert) * 3, BufferMapAccessBit::WRITE));
 	ANKI_TEST_EXPECT_NEQ(ptr, nullptr);
@@ -794,8 +797,7 @@ ANKI_TEST(Gr, DrawWithVertex)
 	ptr[2].m_color = {{0, 0, 255}};
 	b->unmap();
 
-	BufferPtr c =
-		gr->newInstance<Buffer>(BufferInitInfo(sizeof(Vec3) * 3, BufferUsageBit::VERTEX, BufferMapAccessBit::WRITE));
+	BufferPtr c = gr->newBuffer(BufferInitInfo(sizeof(Vec3) * 3, BufferUsageBit::VERTEX, BufferMapAccessBit::WRITE));
 
 	Vec3* otherColor = static_cast<Vec3*>(c->map(0, sizeof(Vec3) * 3, BufferMapAccessBit::WRITE));
 
@@ -820,7 +822,7 @@ ANKI_TEST(Gr, DrawWithVertex)
 
 		CommandBufferInitInfo cinit;
 		cinit.m_flags = CommandBufferFlag::GRAPHICS_WORK;
-		CommandBufferPtr cmdb = gr->newInstance<CommandBuffer>(cinit);
+		CommandBufferPtr cmdb = gr->newCommandBuffer(cinit);
 
 		cmdb->bindVertexBuffer(0, b, 0, sizeof(Vert));
 		cmdb->bindVertexBuffer(1, c, 0, sizeof(Vec3));
@@ -855,7 +857,7 @@ ANKI_TEST(Gr, Sampler)
 
 	SamplerInitInfo init;
 
-	SamplerPtr b = gr->newInstance<Sampler>(init);
+	SamplerPtr b = gr->newSampler(init);
 
 	COMMON_END()
 }
@@ -878,7 +880,7 @@ ANKI_TEST(Gr, Texture)
 	init.m_sampling.m_mipmapFilter = SamplingFilter::LINEAR;
 	init.m_type = TextureType::_2D;
 
-	TexturePtr b = gr->newInstance<Texture>(init);
+	TexturePtr b = gr->newTexture(init);
 
 	COMMON_END()
 }
@@ -906,7 +908,7 @@ ANKI_TEST(Gr, DrawWithTexture)
 	init.m_sampling.m_mipmapFilter = SamplingFilter::LINEAR;
 	init.m_type = TextureType::_2D;
 
-	TexturePtr a = gr->newInstance<Texture>(init);
+	TexturePtr a = gr->newTexture(init);
 
 	//
 	// Create texture B
@@ -918,7 +920,7 @@ ANKI_TEST(Gr, DrawWithTexture)
 		TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::TRANSFER_DESTINATION | TextureUsageBit::GENERATE_MIPMAPS;
 	init.m_initialUsage = TextureUsageBit::NONE;
 
-	TexturePtr b = gr->newInstance<Texture>(init);
+	TexturePtr b = gr->newTexture(init);
 
 	//
 	// Upload all textures
@@ -978,7 +980,7 @@ ANKI_TEST(Gr, DrawWithTexture)
 
 	CommandBufferInitInfo cmdbinit;
 	cmdbinit.m_flags = CommandBufferFlag::TRANSFER_WORK;
-	CommandBufferPtr cmdb = gr->newInstance<CommandBuffer>(cmdbinit);
+	CommandBufferPtr cmdb = gr->newCommandBuffer(cmdbinit);
 
 	// Set barriers
 	cmdb->setTextureSurfaceBarrier(
@@ -1046,7 +1048,7 @@ ANKI_TEST(Gr, DrawWithTexture)
 
 		CommandBufferInitInfo cinit;
 		cinit.m_flags = CommandBufferFlag::GRAPHICS_WORK;
-		CommandBufferPtr cmdb = gr->newInstance<CommandBuffer>(cinit);
+		CommandBufferPtr cmdb = gr->newCommandBuffer(cinit);
 
 		cmdb->setViewport(0, 0, WIDTH, HEIGHT);
 		cmdb->bindShaderProgram(prog);
@@ -1137,11 +1139,11 @@ static void drawOffscreen(GrManager& gr, Bool useSecondLevel)
 	init.m_sampling.m_mipmapFilter = SamplingFilter::LINEAR;
 	init.m_type = TextureType::_2D;
 
-	TexturePtr col0 = gr.newInstance<Texture>(init);
-	TexturePtr col1 = gr.newInstance<Texture>(init);
+	TexturePtr col0 = gr.newTexture(init);
+	TexturePtr col1 = gr.newTexture(init);
 
 	init.m_format = DS_FORMAT;
-	TexturePtr dp = gr.newInstance<Texture>(init);
+	TexturePtr dp = gr.newTexture(init);
 
 	//
 	// Create FB
@@ -1156,7 +1158,7 @@ static void drawOffscreen(GrManager& gr, Bool useSecondLevel)
 	fbinit.m_depthStencilAttachment.m_aspect = DepthStencilAspectBit::DEPTH;
 	fbinit.m_depthStencilAttachment.m_clearValue.m_depthStencil.m_depth = 1.0;
 
-	FramebufferPtr fb = gr.newInstance<Framebuffer>(fbinit);
+	FramebufferPtr fb = gr.newFramebuffer(fbinit);
 
 	//
 	// Create default FB
@@ -1188,7 +1190,7 @@ static void drawOffscreen(GrManager& gr, Bool useSecondLevel)
 
 		CommandBufferInitInfo cinit;
 		cinit.m_flags = CommandBufferFlag::GRAPHICS_WORK;
-		CommandBufferPtr cmdb = gr.newInstance<CommandBuffer>(cinit);
+		CommandBufferPtr cmdb = gr.newCommandBuffer(cinit);
 
 		cmdb->setPolygonOffset(0.0, 0.0);
 
@@ -1213,7 +1215,7 @@ static void drawOffscreen(GrManager& gr, Bool useSecondLevel)
 			CommandBufferInitInfo cinit;
 			cinit.m_flags = CommandBufferFlag::SECOND_LEVEL | CommandBufferFlag::GRAPHICS_WORK;
 			cinit.m_framebuffer = fb;
-			CommandBufferPtr cmdb2 = gr.newInstance<CommandBuffer>(cinit);
+			CommandBufferPtr cmdb2 = gr.newCommandBuffer(cinit);
 
 			drawOffscreenDrawcalls(gr, prog, cmdb2, TEX_SIZE, indices, verts);
 
@@ -1290,21 +1292,23 @@ ANKI_TEST(Gr, ImageLoadStore)
 	init.m_format = PixelFormat(ComponentFormat::R8G8B8A8, TransformFormat::UNORM);
 	init.m_sampling.m_mipmapFilter = SamplingFilter::LINEAR;
 
-	TexturePtr tex = gr->newInstance<Texture>(init);
+	TexturePtr tex = gr->newTexture(init);
 
 	// Prog
 	ShaderProgramPtr prog = createProgram(VERT_QUAD_SRC, FRAG_SIMPLE_TEX_SRC, *gr);
 
 	// Create shader & compute prog
-	ShaderPtr shader = gr->newInstance<Shader>(ShaderType::COMPUTE, COMP_WRITE_IMAGE_SRC);
-	ShaderProgramPtr compProg = gr->newInstance<ShaderProgram>(shader);
+	ShaderPtr shader = gr->newShader({ShaderType::COMPUTE, COMP_WRITE_IMAGE_SRC});
+	ShaderProgramInitInfo sprogInit;
+	sprogInit.m_shaders[ShaderType::COMPUTE] = shader;
+	ShaderProgramPtr compProg = gr->newShaderProgram(sprogInit);
 
 	// FB
 	FramebufferPtr dfb = createDefaultFb(*gr);
 
 	// Write texture data
 	CommandBufferInitInfo cmdbinit;
-	CommandBufferPtr cmdb = gr->newInstance<CommandBuffer>(cmdbinit);
+	CommandBufferPtr cmdb = gr->newCommandBuffer(cmdbinit);
 
 	cmdb->setTextureSurfaceBarrier(tex, TextureUsageBit::NONE, TextureUsageBit::CLEAR, TextureSurfaceInfo(0, 0, 0, 0));
 
@@ -1335,7 +1339,7 @@ ANKI_TEST(Gr, ImageLoadStore)
 
 		CommandBufferInitInfo cinit;
 		cinit.m_flags = CommandBufferFlag::GRAPHICS_WORK | CommandBufferFlag::COMPUTE_WORK;
-		CommandBufferPtr cmdb = gr->newInstance<CommandBuffer>(cinit);
+		CommandBufferPtr cmdb = gr->newCommandBuffer(cinit);
 
 		// Write image
 		Vec4* col = SET_STORAGE(Vec4*, sizeof(*col), cmdb, 1, 0);
@@ -1388,7 +1392,6 @@ ANKI_TEST(Gr, 3DTextures)
 	init.m_format = PixelFormat(ComponentFormat::R8G8B8A8, TransformFormat::UNORM);
 	init.m_usage = TextureUsageBit::SAMPLED_FRAGMENT | TextureUsageBit::TRANSFER_DESTINATION;
 	init.m_initialUsage = TextureUsageBit::TRANSFER_DESTINATION;
-	init.m_usageWhenEncountered = TextureUsageBit::SAMPLED_FRAGMENT;
 	init.m_height = 2;
 	init.m_width = 2;
 	init.m_mipmapsCount = 2;
@@ -1400,7 +1403,7 @@ ANKI_TEST(Gr, 3DTextures)
 	init.m_sampling.m_mipmapFilter = SamplingFilter::NEAREST;
 	init.m_type = TextureType::_3D;
 
-	TexturePtr a = gr->newInstance<Texture>(init);
+	TexturePtr a = gr->newTexture(init);
 
 	//
 	// Upload all textures
@@ -1442,7 +1445,7 @@ ANKI_TEST(Gr, 3DTextures)
 
 	CommandBufferInitInfo cmdbinit;
 	cmdbinit.m_flags = CommandBufferFlag::TRANSFER_WORK | CommandBufferFlag::SMALL_BATCH;
-	CommandBufferPtr cmdb = gr->newInstance<CommandBuffer>(cmdbinit);
+	CommandBufferPtr cmdb = gr->newCommandBuffer(cmdbinit);
 
 	cmdb->setTextureVolumeBarrier(
 		a, TextureUsageBit::NONE, TextureUsageBit::TRANSFER_DESTINATION, TextureVolumeInfo(0));
@@ -1493,7 +1496,7 @@ ANKI_TEST(Gr, 3DTextures)
 
 		CommandBufferInitInfo cinit;
 		cinit.m_flags = CommandBufferFlag::GRAPHICS_WORK | CommandBufferFlag::SMALL_BATCH;
-		CommandBufferPtr cmdb = gr->newInstance<CommandBuffer>(cinit);
+		CommandBufferPtr cmdb = gr->newCommandBuffer(cinit);
 
 		cmdb->setViewport(0, 0, WIDTH, HEIGHT);
 		cmdb->beginRenderPass(dfb, {}, {});
@@ -1542,7 +1545,7 @@ ANKI_TEST(Gr, RenderGraph)
 
 	StackAllocator<U8> alloc(allocAligned, nullptr, 2_MB);
 	RenderGraphDescription descr(alloc);
-	RenderGraphPtr rgraph = gr->newInstance<RenderGraph>();
+	RenderGraphPtr rgraph = gr->newRenderGraph();
 
 	const U GI_MIP_COUNT = 4;
 
@@ -1550,7 +1553,7 @@ ANKI_TEST(Gr, RenderGraph)
 	texI.m_width = texI.m_height = 16;
 	texI.m_usage = TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE | TextureUsageBit::SAMPLED_FRAGMENT;
 	texI.m_format = PixelFormat(ComponentFormat::R8G8B8A8, TransformFormat::UNORM);
-	TexturePtr dummyTex = gr->newInstance<Texture>(texI);
+	TexturePtr dummyTex = gr->newTexture(texI);
 
 	// SM
 	RenderTargetHandle smScratchRt = descr.newRenderTarget(newRTDescr("SM scratch"));

Some files were not shown because too many files changed in this diff