Browse Source

Refactor graphics API. It will serve as a clean abstraction of GL and Vulkan

Panagiotis Christopoulos Charitos 10 years ago
parent
commit
74e6fbae1d
72 changed files with 2035 additions and 3264 deletions
  1. 45 0
      include/anki/gr/Buffer.h
  2. 0 28
      include/anki/gr/BufferCommon.h
  3. 0 80
      include/anki/gr/BufferPtr.h
  4. 168 0
      include/anki/gr/CommandBuffer.h
  5. 0 96
      include/anki/gr/CommandBufferPtr.h
  6. 19 116
      include/anki/gr/Common.h
  7. 14 8
      include/anki/gr/Enums.h
  8. 29 6
      include/anki/gr/Framebuffer.h
  9. 0 54
      include/anki/gr/FramebufferPtr.h
  10. 15 16
      include/anki/gr/GrManager.h
  11. 3 6
      include/anki/gr/GrObject.h
  12. 0 52
      include/anki/gr/GrPtr.h
  13. 40 0
      include/anki/gr/OcclusionQuery.h
  14. 0 41
      include/anki/gr/OcclusionQueryPtr.h
  15. 25 3
      include/anki/gr/Pipeline.h
  16. 0 35
      include/anki/gr/PipelinePtr.h
  17. 29 8
      include/anki/gr/ResourceGroup.h
  18. 0 36
      include/anki/gr/ResourceGroupPtr.h
  19. 40 0
      include/anki/gr/Sampler.h
  20. 0 43
      include/anki/gr/SamplerPtr.h
  21. 25 5
      include/anki/gr/Shader.h
  22. 0 36
      include/anki/gr/ShaderPtr.h
  23. 24 18
      include/anki/gr/Texture.h
  24. 0 42
      include/anki/gr/TexturePtr.h
  25. 20 88
      include/anki/gr/gl/BufferImpl.h
  26. 24 33
      include/anki/gr/gl/CommandBufferImpl.h
  27. 20 0
      include/anki/gr/gl/Common.h
  28. 3 5
      include/anki/gr/gl/Error.h
  29. 10 19
      include/anki/gr/gl/FramebufferImpl.h
  30. 15 14
      include/anki/gr/gl/GlObject.h
  31. 4 11
      include/anki/gr/gl/GlState.h
  32. 4 5
      include/anki/gr/gl/GrManagerImpl.h
  33. 6 14
      include/anki/gr/gl/OcclusionQueryImpl.h
  34. 5 13
      include/anki/gr/gl/PipelineImpl.h
  35. 6 14
      include/anki/gr/gl/RenderingThread.h
  36. 23 22
      include/anki/gr/gl/ResourceGroupImpl.h
  37. 5 29
      include/anki/gr/gl/SamplerImpl.h
  38. 12 35
      include/anki/gr/gl/ShaderImpl.h
  39. 20 57
      include/anki/gr/gl/TextureImpl.h
  40. 1 1
      src/gr/Shader.cpp
  41. 98 0
      src/gr/gl/Buffer.cpp
  42. 66 67
      src/gr/gl/BufferImpl.cpp
  43. 0 298
      src/gr/gl/BufferPtr.cpp
  44. 489 0
      src/gr/gl/CommandBuffer.cpp
  45. 10 6
      src/gr/gl/CommandBufferImpl.cpp
  46. 0 658
      src/gr/gl/CommandBufferPtr.cpp
  47. 60 0
      src/gr/gl/Framebuffer.cpp
  48. 29 53
      src/gr/gl/FramebufferImpl.cpp
  49. 0 140
      src/gr/gl/FramebufferPtr.cpp
  50. 28 12
      src/gr/gl/GlObject.cpp
  51. 1 11
      src/gr/gl/GlState.cpp
  52. 7 28
      src/gr/gl/GrManager.cpp
  53. 9 3
      src/gr/gl/GrManagerImpl.cpp
  54. 60 0
      src/gr/gl/OcclusionQuery.cpp
  55. 6 13
      src/gr/gl/OcclusionQueryImpl.cpp
  56. 0 117
      src/gr/gl/OcclusionQueryPtr.cpp
  57. 60 0
      src/gr/gl/Pipeline.cpp
  58. 9 17
      src/gr/gl/PipelineImpl.cpp
  59. 0 105
      src/gr/gl/PipelinePtr.cpp
  60. 49 34
      src/gr/gl/RenderingThread.cpp
  61. 11 8
      src/gr/gl/ResourceGroup.cpp
  62. 59 63
      src/gr/gl/ResourceGroupImpl.cpp
  63. 60 0
      src/gr/gl/Sampler.cpp
  64. 5 7
      src/gr/gl/SamplerImpl.cpp
  65. 0 116
      src/gr/gl/SamplerPtr.cpp
  66. 79 0
      src/gr/gl/Shader.cpp
  67. 7 10
      src/gr/gl/ShaderImpl.cpp
  68. 0 85
      src/gr/gl/ShaderPtr.cpp
  69. 59 0
      src/gr/gl/Texture.cpp
  70. 119 159
      src/gr/gl/TextureImpl.cpp
  71. 0 164
      src/gr/gl/TexturePtr.cpp
  72. 1 1
      thirdparty

+ 45 - 0
include/anki/gr/Buffer.h

@@ -0,0 +1,45 @@
+// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include "anki/gr/GrObject.h"
+
+namespace anki {
+
+/// @addtogroup graphics
+/// @{
+
+/// GPU buffer.
+class Buffer: public GrObject
+{
+public:
+	/// Construct.
+	Buffer(GrManager* manager);
+
+	/// Destroy.
+	~Buffer();
+
+	/// Access the implementation.
+	BufferImpl& getImplementation()
+	{
+		return *m_impl;
+	}
+
+	/// Allocate the buffer.
+	void create(PtrSize size, BufferUsageBit usage, BufferAccessBit access);
+
+	/// Map the buffer.
+	void* map(PtrSize offset, PtrSize range, BufferAccessBit access);
+
+	/// Unmap the buffer.
+	void unmap();
+
+private:
+	UniquePtr<BufferImpl> m_impl;
+};
+/// @}
+
+} // end namespace anki

+ 0 - 28
include/anki/gr/BufferCommon.h

@@ -1,28 +0,0 @@
-// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#ifndef ANKI_GR_BUFFER_COMMON_H
-#define ANKI_GR_BUFFER_COMMON_H
-
-#include "anki/gr/Common.h"
-
-namespace anki {
-
-/// @addtogroup graphics
-/// @{
-
-/// Buffer initializer.
-class BufferInitializer
-{
-public:
-	U32 m_size = 0;
-	void* m_data = nullptr;
-	BufferUsageBit m_usage = BufferUsageBit::UNIFORM_BUFFER;
-};
-/// @}
-
-} // end namespace anki
-
-#endif

+ 0 - 80
include/anki/gr/BufferPtr.h

@@ -1,80 +0,0 @@
-// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#ifndef ANKI_GR_BUFFER_HANDLE_H
-#define ANKI_GR_BUFFER_HANDLE_H
-
-#include "anki/gr/GrPtr.h"
-
-namespace anki {
-
-/// @addtogroup opengl_containers
-/// @{
-
-/// GPU buffer.
-class BufferPtr: public GrPtr<BufferImpl>
-{
-public:
-	using Base = GrPtr<BufferImpl>;
-
-	BufferPtr();
-
-	~BufferPtr();
-
-	/// Create the buffer with data
-	void create(GrManager* manager, GLenum target,
-		const void* data, PtrSize size, GLbitfield flags);
-
-	/// Get buffer size. It may serialize
-	PtrSize getSize() const;
-
-	/// Get buffer's current target. It may serialize
-	GLenum getTarget() const;
-
-	/// Get persistent mapping address. It may serialize
-	void* getPersistentMappingAddress();
-
-	/// Write data to the buffer
-	void write(
-		CommandBufferPtr& commands,
-		const void* data, PtrSize dataSize, PtrSize readOffset,
-		PtrSize writeOffset, PtrSize size);
-
-	/// Bind to the state as uniform/shader storage buffer
-	void bindShaderBuffer(CommandBufferPtr& commands, U32 bindingPoint)
-	{
-		bindShaderBufferInternal(commands, -1, -1, bindingPoint);
-	}
-
-	/// Bind to the state as uniform/shader storage buffer
-	void bindShaderBuffer(CommandBufferPtr& commands,
-		U32 offset, U32 size, U32 bindingPoint)
-	{
-		bindShaderBufferInternal(commands, offset, size, bindingPoint);
-	}
-
-	/// Bind to the state as vertex buffer
-	void bindVertexBuffer(
-		CommandBufferPtr& commands,
-		U32 elementSize,
-		GLenum type,
-		Bool normalized,
-		PtrSize stride,
-		PtrSize offset,
-		U32 attribLocation);
-
-	/// Bind to the state as index buffer
-	void bindIndexBuffer(CommandBufferPtr& commands);
-
-private:
-	void bindShaderBufferInternal(CommandBufferPtr& commands,
-		I32 offset, I32 size, U32 bindingPoint);
-};
-/// @}
-
-} // end namespace anki
-
-#endif
-

+ 168 - 0
include/anki/gr/CommandBuffer.h

@@ -0,0 +1,168 @@
+// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include "anki/gr/GrObject.h"
+
+namespace anki {
+
+/// @addtogroup graphics
+/// @{
+
+/// The draw indirect structure for index drawing, also the parameters of a
+/// regular drawcall
+class DrawElementsIndirectInfo
+{
+public:
+	DrawElementsIndirectInfo()
+	{}
+
+	DrawElementsIndirectInfo(U32 count, U32 instanceCount, U32 firstIndex,
+		U32 baseVertex, U32 baseInstance)
+		: m_count(count)
+		, m_instanceCount(instanceCount)
+		, m_firstIndex(firstIndex)
+		, m_baseVertex(baseVertex)
+		, m_baseInstance(baseInstance)
+	{}
+
+	U32 m_count = MAX_U32;
+	U32 m_instanceCount = 1;
+	U32 m_firstIndex = 0;
+	U32 m_baseVertex = 0;
+	U32 m_baseInstance = 0;
+};
+
+/// The draw indirect structure for arrays drawing, also the parameters of a
+/// regular drawcall
+class DrawArraysIndirectInfo
+{
+public:
+	DrawArraysIndirectInfo()
+	{}
+
+	DrawArraysIndirectInfo(U32 count, U32 instanceCount, U32 first,
+		U32 baseInstance)
+		: m_count(count)
+		, m_instanceCount(instanceCount)
+		, m_first(first)
+		, m_baseInstance(baseInstance)
+	{}
+
+	U32 m_count = MAX_U32;
+	U32 m_instanceCount = 1;
+	U32 m_first = 0;
+	U32 m_baseInstance = 0;
+};
+
+/// Command buffer initialization hints. They are used to optimize the
+/// allocators of a command buffer.
+class CommandBufferInitHints
+{
+	friend class CommandBufferImpl;
+
+private:
+	enum
+	{
+		MAX_CHUNK_SIZE = 4 * 1024 * 1024 // 4MB
+	};
+
+	PtrSize m_chunkSize = 1024;
+};
+
+/// Command buffer.
+class CommandBuffer: public GrObject
+{
+public:
+	/// Construct.
+	CommandBuffer(GrManager* manager);
+
+	/// Destroy.
+	~CommandBuffer();
+
+	/// Access the implementation.
+	CommandBufferImpl& getImplementation()
+	{
+		return *m_impl;
+	}
+
+	/// Create command buffer.
+	void create(CommandBufferInitHints hints = CommandBufferInitHints());
+
+	/// Compute initialization hints.
+	CommandBufferInitHints computeInitHints() const;
+
+	/// Flush command buffer for deferred execution.
+	void flush();
+
+	/// Flush and wait to finish.
+	void finish();
+
+	/// @name State manipulation
+	/// @{
+
+	/// Set the viewport.
+	void setViewport(U16 minx, U16 miny, U16 maxx, U16 maxy);
+
+	/// Bind pipeline.
+	void bindPipeline(PipelinePtr ppline);
+
+	/// Bind framebuffer.
+	void bindFramebuffer(FramebufferPtr fb);
+
+	/// Bind resources.
+	void bindResourceGroup(ResourceGroupPtr rc);
+	/// @}
+
+	/// @name Drawcalls
+	/// @{
+	void drawElements(U32 count, U32 instanceCount = 1, U32 firstIndex = 0,
+		U32 baseVertex = 0, U32 baseInstance = 0);
+
+	void drawArrays(U32 count, U32 instanceCount = 1, U32 first = 0,
+		U32 baseInstance = 0);
+
+	void drawElementsConditional(OcclusionQueryPtr query, U32 count,
+		U32 instanceCount = 1, U32 firstIndex = 0, U32 baseVertex = 0,
+		U32 baseInstance = 0);
+
+	void drawArraysConditional(OcclusionQueryPtr query, U32 count,
+		U32 instanceCount = 1, U32 first = 0, U32 baseInstance = 0);
+
+	void dispatchCompute(U32 groupCountX, U32 groupCountY, U32 groupCountZ);
+	/// @}
+
+	/// @name Resource upload
+	/// @{
+
+	/// Used to upload data to a texture.
+	void textureUpload(TexturePtr tex, U32 mipmap, U32 slice, PtrSize dataSize,
+		void*& data);
+
+	/// Write data to a buffer.
+	void writeBuffer(BufferPtr buff, PtrSize offset, PtrSize range,
+		void*& data);
+
+	/// Update dynamic uniforms.
+	void updateDynamicUniforms(void* data, U32 size);
+	/// @}
+
+	/// @name Other
+	/// @{
+
+	/// Begin query.
+	void beginOcclusionQuery(OcclusionQueryPtr query);
+
+	/// End query.
+	void endOcclusionQuery(OcclusionQueryPtr query);
+	/// @}
+
+private:
+	UniquePtr<CommandBufferImpl> m_impl;
+};
+/// @}
+
+} // end namespace anki

+ 0 - 96
include/anki/gr/CommandBufferPtr.h

@@ -1,96 +0,0 @@
-// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#pragma once
-
-#include "anki/gr/GrPtr.h"
-
-namespace anki {
-
-/// @addtogroup graphics
-/// @{
-
-/// Command buffer.
-class CommandBufferPtr: public GrPtr<CommandBufferImpl>
-{
-public:
-	using Base = GrPtr<CommandBufferImpl>;
-	using UserCallback = Error(*)(void*);
-
-	CommandBufferPtr();
-
-	~CommandBufferPtr();
-
-	/// Create command buffer
-	void create(GrManager* manager,
-		CommandBufferInitHints hints = CommandBufferInitHints());
-
-	/// Add a user command at the end of the command buffer
-	void pushBackUserCommand(UserCallback callback, void* data);
-
-	/// Add another command buffer for execution
-	void pushBackOtherCommandBuffer(CommandBufferPtr& commands);
-
-	/// Flush command buffer for deferred execution.
-	void flush();
-
-	/// Flush and wait to finish
-	void finish();
-
-	/// Compute initialization hints
-	CommandBufferInitHints computeInitHints() const;
-
-	/// Update dynamic uniforms.
-	void updateDynamicUniforms(void* data, U32 size);
-
-	/// @name State manipulation
-	/// @{
-
-	/// Bind vertex buffer.
-	void bindVertexBuffer(U32 bindingPoint, BufferPtr buff, PtrSize offset);
-
-	/// Bind index buffer.
-	void bindIndexBuffer(BufferPtr buff, U32 indexSize);
-
-	/// Set the viewport
-	void setViewport(U16 minx, U16 miny, U16 maxx, U16 maxy);
-
-	/// Bind many textures
-	/// @param first The unit where the first texture will be bound.
-	/// @param textures The array of textures.
-	/// @param count The count of textures
-	void bindTextures(U32 first, TexturePtr textures[], U32 count);
-	/// @}
-
-	/// @name Drawcalls
-	/// @{
-	void drawElements(GLenum mode, U8 indexSize,
-		U32 count, U32 instanceCount = 1, U32 firstIndex = 0,
-		U32 baseVertex = 0, U32 baseInstance = 0);
-
-	void drawArrays(GLenum mode, U32 count, U32 instanceCount = 1,
-		U32 first = 0, U32 baseInstance = 0);
-
-	void drawElementsConditional(OcclusionQueryPtr& query,
-		GLenum mode, U8 indexSize,
-		U32 count, U32 instanceCount = 1, U32 firstIndex = 0,
-		U32 baseVertex = 0, U32 baseInstance = 0);
-
-	void drawArraysConditional(OcclusionQueryPtr& query,
-		GLenum mode, U32 count, U32 instanceCount = 1,
-		U32 first = 0, U32 baseInstance = 0);
-
-	void dispatchCompute(U32 groupCountX, U32 groupCountY, U32 groupCountZ);
-	/// @}
-
-	/// @name Other operations
-	/// @{
-	void copyTextureToBuffer(TexturePtr& from, BufferPtr& To);
-	/// @}
-};
-/// @}
-
-} // end namespace anki
-

+ 19 - 116
include/anki/gr/Common.h

@@ -3,65 +3,41 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_GR_COMMON_H
-#define ANKI_GR_COMMON_H
+#pragma once
 
 #include "anki/gr/Enums.h"
 #include "anki/util/Allocator.h"
-#include "anki/util/NonCopyable.h"
-#include "anki/util/Assert.h"
-#include "anki/util/Array.h"
-
-#if ANKI_GL == ANKI_GL_DESKTOP
-#	if ANKI_OS == ANKI_OS_WINDOWS && !defined(GLEW_STATIC)
-#		define GLEW_STATIC
-#	endif
-#	include <GL/glew.h>
-#	if !defined(ANKI_GLEW_H)
-#		error "Wrong GLEW included"
-#	endif
-#elif ANKI_GL == ANKI_GL_ES
-#	include <GLES3/gl3.h>
-#else
-#	error "See file"
-#endif
+#include "anki/util/Ptr.h"
 
 namespace anki {
 
 // Forward
-class BufferImpl;
-class BufferPtr;
-class ShaderImpl;
-class ShaderPtr;
-class PipelineImpl;
-class PipelinePtr;
-class PipelineInitializer;
-class FramebufferImpl;
-class FramebufferPtr;
-class FramebufferInitializer;
-class TextureImpl;
-class TexturePtr;
-class SamplerImpl;
-class SamplerPtr;
-class OcclusionQueryImpl;
-class OcclusionQueryPtr;
-class CommandBufferImpl;
-class CommandBufferPtr;
-class ResourceGroupImpl;
-class ResourceGroupPtr;
 class GrManager;
 class GrManagerImpl;
 class TextureInitializer;
 class SamplerInitializer;
 class GrManagerInitializer;
+class PipelineInitializer;
+class FramebufferInitializer;
+
+#define ANKI_GR_CLASS(x_) \
+	class x_##Impl; \
+	class x_; \
+	using x_##Ptr = IntrusivePtr<x_>;
+
+ANKI_GR_CLASS(Buffer)
+ANKI_GR_CLASS(Texture)
+ANKI_GR_CLASS(Sampler)
+ANKI_GR_CLASS(CommandBuffer)
+ANKI_GR_CLASS(Shader)
+ANKI_GR_CLASS(Pipeline)
+ANKI_GR_CLASS(Framebuffer)
+ANKI_GR_CLASS(OcclusionQuery)
+ANKI_GR_CLASS(ResourceGroup)
 
 /// @addtogroup graphics
 /// @{
 
-/// The type of the allocator of CommandBuffer
-template<typename T>
-using CommandBufferAllocator = ChainAllocator<T>;
-
 /// The type of the allocator for heap allocations
 template<typename T>
 using GrAllocator = HeapAllocator<T>;
@@ -78,80 +54,7 @@ const U MAX_STORAGE_BUFFER_BINDINGS = 4;
 /// GL generic callback
 using SwapBuffersCallback = void(*)(void*);
 using MakeCurrentCallback = void(*)(void*, void*);
-
-/// Command buffer initialization hints. They are used to optimize the
-/// allocators of a command buffer
-class CommandBufferInitHints
-{
-	friend class CommandBufferImpl;
-
-private:
-	enum
-	{
-		MAX_CHUNK_SIZE = 4 * 1024 * 1024 // 4MB
-	};
-
-	PtrSize m_chunkSize = 1024;
-};
-/// @}
-
-/// @addtogroup opengl_other
-/// @{
-
-/// The draw indirect structure for index drawing, also the parameters of a
-/// regular drawcall
-class GlDrawElementsIndirectInfo
-{
-public:
-	GlDrawElementsIndirectInfo()
-	{}
-
-	GlDrawElementsIndirectInfo(
-		U32 count,
-		U32 instanceCount,
-		U32 firstIndex,
-		U32 baseVertex,
-		U32 baseInstance)
-	:	m_count(count),
-		m_instanceCount(instanceCount),
-		m_firstIndex(firstIndex),
-		m_baseVertex(baseVertex),
-		m_baseInstance(baseInstance)
-	{}
-
-	U32 m_count = MAX_U32;
-	U32 m_instanceCount = 1;
-	U32 m_firstIndex = 0;
-	U32 m_baseVertex = 0;
-	U32 m_baseInstance = 0;
-};
-
-/// The draw indirect structure for arrays drawing, also the parameters of a
-/// regular drawcall
-class GlDrawArraysIndirectInfo
-{
-public:
-	GlDrawArraysIndirectInfo()
-	{}
-
-	GlDrawArraysIndirectInfo(
-		U32 count,
-		U32 instanceCount,
-		U32 first,
-		U32 baseInstance)
-	:	m_count(count),
-		m_instanceCount(instanceCount),
-		m_first(first),
-		m_baseInstance(baseInstance)
-	{}
-
-	U32 m_count = MAX_U32;
-	U32 m_instanceCount = 1;
-	U32 m_first = 0;
-	U32 m_baseInstance = 0;
-};
 /// @}
 
 } // end namespace anki
 
-#endif

+ 14 - 8
include/anki/gr/Enums.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_GR_ENUMS_H
-#define ANKI_GR_ENUMS_H
+#pragma once
 
 #include "anki/util/StdTypes.h"
 #include "anki/util/Enum.h"
@@ -258,21 +257,28 @@ enum class AttachmentStoreOperation: U8
 	DONT_CARE
 };
 
-/// Buffer access mode.
+/// Buffer usage modes.
 enum class BufferUsageBit: U8
 {
+	NONE = 0,
 	UNIFORM_BUFFER = 1 << 0,
 	STORAGE_BUFFER = 1 << 1,
 	INDEX_BUFFER = 1 << 2,
 	VERTEX_BUFFER = 1 << 3,
-	INDIRECT_BUFFER = 1 << 4,
-	CLIENT_READ = 1 << 5,
-	CLIENT_WRITE = 1 << 6
+	INDIRECT_BUFFER = 1 << 4
 };
 ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(BufferUsageBit, inline)
+
+/// Buffer access from client modes.
+enum class BufferAccessBit: U8
+{
+	NONE = 0,
+	CLIENT_MAP_READ = 1 << 0,
+	CLIENT_MAP_WRITE = 1 << 1,
+	CLIENT_WRITE = 1 << 2,
+};
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(BufferAccessBit, inline)
 /// @}
 
 } // end namespace anki
 
-#endif
-

+ 29 - 6
include/anki/gr/FramebufferCommon.h → include/anki/gr/Framebuffer.h

@@ -3,16 +3,18 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_GR_FRAMEBUFFER_COMMON_H
-#define ANKI_GR_FRAMEBUFFER_COMMON_H
+#pragma once
 
-#include "anki/gr/Common.h"
-#include "anki/gr/TexturePtr.h"
+#include "anki/gr/GrObject.h"
+#include "anki/gr/Texture.h"
+#include <cstring>
 
 namespace anki {
 
 /// @addtogroup graphics
 /// @{
+
+/// Framebuffer attachment.
 class Attachment
 {
 public:
@@ -85,9 +87,30 @@ public:
 		return *this;
 	}
 };
+
+/// GPU framebuffer.
+class Framebuffer: public GrObject
+{
+public:
+	/// Construct.
+	Framebuffer(GrManager* manager);
+
+	/// Destroy.
+	~Framebuffer();
+
+	/// Access the implementation.
+	FramebufferImpl& getImplementation()
+	{
+		return *m_impl;
+	}
+
+	/// Create.
+	void create(const FramebufferInitializer& init);
+
+private:
+	UniquePtr<FramebufferImpl> m_impl;
+};
 /// @}
 
 } // end namespace anki
 
-#endif
-

+ 0 - 54
include/anki/gr/FramebufferPtr.h

@@ -1,54 +0,0 @@
-// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#ifndef ANKI_GR_FRAMEBUFFER_HANDLE_H
-#define ANKI_GR_FRAMEBUFFER_HANDLE_H
-
-#include "anki/gr/GrPtr.h"
-#include "anki/gr/FramebufferCommon.h"
-
-namespace anki {
-
-/// @addtogroup graphics
-/// @{
-
-/// Framebuffer.
-class FramebufferPtr: public GrPtr<FramebufferImpl>
-{
-public:
-	using Base = GrPtr<FramebufferImpl>;
-	using Initializer = FramebufferInitializer;
-
-	FramebufferPtr();
-
-	~FramebufferPtr();
-
-	/// Create a framebuffer.
-	void create(GrManager* manager, Initializer& attachments);
-
-	/// Bind it to the command buffer
-	/// @param commands The command buffer
-	void bind(CommandBufferPtr& commands);
-
-	/// Blit another framebuffer to this
-	/// @param[in, out] commands The command buffer
-	/// @param[in] b The sorce framebuffer
-	/// @param[in] sourceRect The source rectangle
-	/// @param[in] destRect The destination rectangle
-	/// @param attachmentMask The attachments to blit
-	/// @param linear Perform linean filtering
-	void blit(CommandBufferPtr& commands,
-		const FramebufferPtr& b,
-		const Array<U32, 4>& sourceRect,
-		const Array<U32, 4>& destRect,
-		GLbitfield attachmentMask,
-		Bool linear);
-};
-/// @}
-
-} // end namespace anki
-
-#endif
-

+ 15 - 16
include/anki/gr/GrManager.h

@@ -3,15 +3,14 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_GR_GR_MANAGER_H
-#define ANKI_GR_GR_MANAGER_H
+#pragma once
 
 #include "anki/gr/Common.h"
 #include "anki/util/String.h"
 
 namespace anki {
 
-/// @addtogroup graphics_other
+/// @addtogroup graphics
 /// @{
 
 /// Manager initializer.
@@ -43,22 +42,17 @@ public:
 	/// Default constructor
 	GrManager() = default;
 
-	~GrManager()
-	{
-		destroy();
-	}
+	~GrManager();
 
 	/// Create.
 	ANKI_USE_RESULT Error create(Initializer& init);
 
-	/// Synchronize client and server
-	void syncClientServer();
-
 	/// Swap buffers
 	void swapBuffers();
 
-	/// Return the alignment of a buffer target
-	PtrSize getBufferOffsetAlignment(GLenum target) const;
+	/// Create a new graphics object.
+	template<typename T, typename... Args>
+	IntrusivePtr<T> newInstance(Args&&... args);
 
 	/// @privatesection
 	/// @{
@@ -84,14 +78,19 @@ public:
 	/// @}
 
 private:
-	GrManagerImpl* m_impl = nullptr;
+	UniquePtr<GrManagerImpl> m_impl;
 	String m_cacheDir;
 	GrAllocator<U8> m_alloc; ///< Keep it last to deleted last
-
-	void destroy();
 };
+
+template<typename T, typename... Args>
+IntrusivePtr<T> GrManager::newInstance(Args&&... args)
+{
+	T* ptr = m_alloc.newInstance<T>(this);
+	ptr->create(std::forward(args)...);
+	return IntrusivePtr<T>(ptr);
+}
 /// @}
 
 } // end namespace anki
 
-#endif

+ 3 - 6
include/anki/gr/GrObject.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_GR_GR_OBJECT_H
-#define ANKI_GR_GR_OBJECT_H
+#pragma once
 
 #include "anki/gr/Common.h"
 #include "anki/util/Atomic.h"
@@ -20,8 +19,8 @@ class GrObject: public NonCopyable
 {
 public:
 	GrObject(GrManager* manager)
-	:	m_refcount(0),
-		m_manager(manager)
+		: m_refcount(0)
+		, m_manager(manager)
 	{}
 
 	virtual ~GrObject()
@@ -52,5 +51,3 @@ private:
 
 } // end namespace anki
 
-#endif
-

+ 0 - 52
include/anki/gr/GrPtr.h

@@ -1,52 +0,0 @@
-// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#ifndef ANKI_GR_GR_HANDLE_H
-#define ANKI_GR_GR_HANDLE_H
-
-#include "anki/gr/GrObject.h"
-#include "anki/gr/GrManager.h"
-#include "anki/util/Ptr.h"
-
-namespace anki {
-
-/// @addtogroup graphics
-/// @{
-
-/// Shared pointer for graphics objects.
-///
-/// @tparam T The type of the pointer
-template<typename T>
-class GrPtr: public IntrusivePtr<GrObject>
-{
-public:
-	using Base = IntrusivePtr<GrObject>;
-
-	/// Create an object and initialize the handle with that.
-	/// @param manager The manager.
-	void create(GrManager& manager)
-	{
-		// Create the object
-		auto alloc = manager.getAllocator();
-		T* ptr = alloc.template newInstance<T>(&manager);
-		Base::reset(ptr);
-	}
-
-	const T& get() const
-	{
-		return static_cast<const T&>(Base::get());
-	}
-
-	T& get()
-	{
-		return static_cast<T&>(Base::get());
-	}
-};
-/// @}
-
-} // end namespace anki
-
-#endif
-

+ 40 - 0
include/anki/gr/OcclusionQuery.h

@@ -0,0 +1,40 @@
+// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include "anki/gr/GrObject.h"
+
+namespace anki {
+
+/// @addtogroup graphics
+/// @{
+
+/// Occlusion query.
+class OcclusionQuery: public GrObject
+{
+public:
+	/// Construct.
+	OcclusionQuery(GrManager* manager);
+
+	/// Destroy.
+	~OcclusionQuery();
+
+	/// Access the implementation.
+	OcclusionQueryImpl& getImplementation()
+	{
+		return *m_impl;
+	}
+
+	/// Create a query.
+	void create(OcclusionQueryResultBit condRenderingBit);
+
+private:
+	UniquePtr<OcclusionQueryImpl> m_impl;
+};
+/// @}
+
+} // end namespace anki
+

+ 0 - 41
include/anki/gr/OcclusionQueryPtr.h

@@ -1,41 +0,0 @@
-// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#ifndef ANKI_GR_OCCLUSION_QUERY_HANDLE_H
-#define ANKI_GR_OCCLUSION_QUERY_HANDLE_H
-
-#include "anki/gr/GrPtr.h"
-
-namespace anki {
-
-/// @addtogroup graphics
-/// @{
-
-/// Occlusion query.
-class OcclusionQueryPtr: public GrPtr<OcclusionQueryImpl>
-{
-public:
-	using Base = GrPtr<OcclusionQueryImpl>;
-	using ResultBit = OcclusionQueryResultBit;
-
-	OcclusionQueryPtr();
-
-	~OcclusionQueryPtr();
-
-	/// Create a query.
-	void create(GrManager* manager, ResultBit condRenderingBit);
-
-	/// Begin query.
-	void begin(CommandBufferPtr& commands);
-
-	/// End query.
-	void end(CommandBufferPtr& commands);
-};
-/// @}
-
-} // end namespace anki
-
-#endif
-

+ 25 - 3
include/anki/gr/PipelineCommon.h → include/anki/gr/Pipeline.h

@@ -5,9 +5,8 @@
 
 #pragma once
 
-#include "anki/gr/Common.h"
-#include "anki/gr/ShaderPtr.h"
-#include "anki/gr/PipelinePtr.h"
+#include "anki/gr/GrObject.h"
+#include "anki/gr/Shader.h"
 
 namespace anki {
 
@@ -121,6 +120,29 @@ public:
 
 	Array<ShaderPtr, 6> m_shaders;
 };
+
+/// Graphics and compute pipeline. Contains the static state.
+class Pipeline: public GrObject
+{
+public:
+	/// Construct.
+	Pipeline(GrManager* manager);
+
+	/// Destroy.
+	~Pipeline();
+
+	/// Access the implementation.
+	PipelineImpl& getImplementation()
+	{
+		return *m_impl;
+	}
+
+	/// Create.
+	void create(const PipelineInitializer& init);
+
+private:
+	UniquePtr<PipelineImpl> m_impl;
+};
 /// @}
 
 } // end namespace anki

+ 0 - 35
include/anki/gr/PipelinePtr.h

@@ -1,35 +0,0 @@
-// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#pragma once
-
-#include "anki/gr/GrPtr.h"
-
-namespace anki {
-
-/// @addtogroup graphics
-/// @{
-
-/// Program pipeline.
-class PipelinePtr: public GrPtr<PipelineImpl>
-{
-public:
-	using Base = GrPtr<PipelineImpl>;
-	using Initializer = PipelineInitializer;
-
-	PipelinePtr();
-
-	~PipelinePtr();
-
-	/// Create a pipeline
-	void create(GrManager* manager, const Initializer& init);
-
-	/// Bind it to the state
-	void bind(CommandBufferPtr& commands);
-};
-/// @}
-
-} // end namespace anki
-

+ 29 - 8
include/anki/gr/ResourceGroupCommon.h → include/anki/gr/ResourceGroup.h

@@ -3,13 +3,12 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_GR_RESOURCE_GROUP_COMMON_H
-#define ANKI_GR_RESOURCE_GROUP_COMMON_H
+#pragma once
 
-#include "anki/gr/Common.h"
-#include "anki/gr/TexturePtr.h"
-#include "anki/gr/SamplerPtr.h"
-#include "anki/gr/BufferPtr.h"
+#include "anki/gr/GrObject.h"
+#include "anki/gr/Texture.h"
+#include "anki/gr/Sampler.h"
+#include "anki/gr/Buffer.h"
 
 namespace anki {
 
@@ -42,10 +41,32 @@ public:
 	Array<BufferBinding, MAX_STORAGE_BUFFER_BINDINGS> m_storageBuffers;
 	Array<BufferBinding, MAX_VERTEX_ATTRIBUTES> m_vertexBuffers;
 	BufferBinding m_indexBuffer;
+	I8 m_indexSize = -1; ///< Index size in bytes. 2 or 4
+};
+
+/// Resource group.
+class ResourceGroup: public GrObject
+{
+public:
+	/// Construct.
+	ResourceGroup(GrManager* manager);
+
+	/// Destroy.
+	~ResourceGroup();
+
+	/// Access the implementation.
+	ResourceGroupImpl& getImplementation()
+	{
+		return *m_impl;
+	}
+
+	/// Create.
+	void create(const ResourceGroupInitializer& init);
+
+private:
+	UniquePtr<ResourceGroupImpl> m_impl;
 };
 /// @}
 
 } // end namespace anki
 
-#endif
-

+ 0 - 36
include/anki/gr/ResourceGroupPtr.h

@@ -1,36 +0,0 @@
-// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#ifndef ANKI_GR_RESOURCE_GROUP_HANDLE_H
-#define ANKI_GR_RESOURCE_GROUP_HANDLE_H
-
-#include "anki/gr/GrPtr.h"
-#include "anki/gr/ResourceGroupCommon.h"
-
-namespace anki {
-
-/// @addtogroup graphics
-/// @{
-
-/// A collection of resource bindings.
-class ResourceGroupPtr: public GrPtr<ResourceGroupImpl>
-{
-public:
-	using Base = GrPtr<ResourceGroupImpl>;
-	using Initializer = ResourceGroupInitializer;
-
-	ResourceGroupPtr();
-
-	~ResourceGroupPtr();
-
-	/// Create resource group.
-	ANKI_USE_RESULT Error create(GrManager* manager, const Initializer& init);
-};
-/// @}
-
-} // end namespace anki
-
-#endif
-

+ 40 - 0
include/anki/gr/Sampler.h

@@ -0,0 +1,40 @@
+// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include "anki/gr/GrObject.h"
+#include "anki/gr/Texture.h"
+
+namespace anki {
+
+/// @addtogroup graphics
+/// @{
+
+/// GPU sampler.
+class Sampler: public GrObject
+{
+public:
+    /// Construct.
+	Sampler(GrManager* manager);
+
+	/// Destroy.
+	~Sampler();
+
+	/// Access the implementation.
+	SamplerImpl& getImplementation()
+	{
+		return *m_impl;
+	}
+
+    /// Create it.
+	void create(const SamplerInitializer& init);
+
+private:
+    UniquePtr<SamplerImpl> m_impl;
+};
+/// @}
+
+} // end namespace anki

+ 0 - 43
include/anki/gr/SamplerPtr.h

@@ -1,43 +0,0 @@
-// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#ifndef ANKI_GR_SAMPLER_HANDLE_H
-#define ANKI_GR_SAMPLER_HANDLE_H
-
-#include "anki/gr/TextureSamplerCommon.h"
-#include "anki/gr/GrPtr.h"
-
-namespace anki {
-
-/// @addtogroup graphics
-/// @{
-
-/// Sampler.
-class SamplerPtr: public GrPtr<SamplerImpl>
-{
-public:
-	using Base = GrPtr<SamplerImpl>;
-	using Initializer = SamplerInitializer;
-
-	/// Create husk.
-	SamplerPtr();
-
-	~SamplerPtr();
-
-	/// Create the sampler
-	void create(CommandBufferPtr& commands, const Initializer& init);
-
-	/// Bind to a unit
-	void bind(CommandBufferPtr& commands, U32 unit);
-
-	/// Bind default sampler
-	static void bindDefault(CommandBufferPtr& commands, U32 unit);
-};
-/// @}
-
-} // end namespace anki
-
-#endif
-

+ 25 - 5
include/anki/gr/ShaderCommon.h → include/anki/gr/Shader.h

@@ -3,10 +3,9 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_GR_SHADER_COMMON_H
-#define ANKI_GR_SHADER_COMMON_H
+#pragma once
 
-#include "anki/gr/Common.h"
+#include "anki/gr/GrObject.h"
 #include "anki/Math.h"
 
 namespace anki {
@@ -58,9 +57,30 @@ void writeShaderBlockMemory(
 	U32 elementsCount,
 	void* buffBegin,
 	const void* buffEnd);
+
+/// GPU shader.
+class Shader: public GrObject
+{
+public:
+	/// Construct.
+	Shader(GrManager* manager);
+
+	/// Destroy.
+	~Shader();
+
+	/// Access the implementation.
+	ShaderImpl& getImplementation()
+	{
+		return *m_impl;
+	}
+
+	/// Create shader.
+	void create(ShaderType shaderType, const void* source, PtrSize sourceSize);
+
+private:
+	UniquePtr<ShaderImpl> m_impl;
+};
 /// @}
 
 } // end namespace anki
 
-#endif
-

+ 0 - 36
include/anki/gr/ShaderPtr.h

@@ -1,36 +0,0 @@
-// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#ifndef ANKI_GR_SHADER_HANDLE_H
-#define ANKI_GR_SHADER_HANDLE_H
-
-#include "anki/gr/ShaderCommon.h"
-#include "anki/gr/GrPtr.h"
-
-namespace anki {
-
-/// @addtogroup graphics
-/// @{
-
-/// Shader.
-class ShaderPtr: public GrPtr<ShaderImpl>
-{
-public:
-	using Base = GrPtr<ShaderImpl>;
-
-	ShaderPtr();
-
-	~ShaderPtr();
-
-	/// Create shader program.
-	void create(GrManager* manager,
-		ShaderType shaderType, const void* source, PtrSize sourceSize);
-};
-/// @}
-
-} // end namespace anki
-
-#endif
-

+ 24 - 18
include/anki/gr/TextureSamplerCommon.h → include/anki/gr/Texture.h

@@ -3,16 +3,16 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_GR_TEXTURE_SAMPLER_COMMON_H
-#define ANKI_GR_TEXTURE_SAMPLER_COMMON_H
+#pragma once
 
-#include "anki/gr/Common.h"
+#include "anki/gr/GrObject.h"
 
 namespace anki {
 
 /// @addtogroup graphics
 /// @{
 
+/// Sampler initializer.
 class SamplerInitializer
 {
 public:
@@ -25,13 +25,6 @@ public:
 	Bool8 m_repeat = true;
 };
 
-class SurfaceData
-{
-public:
-	const void* m_ptr = nullptr;
-	PtrSize m_size = 0;
-};
-
 /// Texture initializer.
 class TextureInitializer
 {
@@ -45,17 +38,30 @@ public:
 	U8 m_samples = 1;
 
 	SamplerInitializer m_sampling;
+};
+
+/// GPU texture
+class Texture: public GrObject
+{
+public:
+	/// Construct.
+	Texture(GrManager* manager);
+
+	/// Destroy.
+	~Texture();
 
-	/// In some backends it may copy the m_data to a temp buffer for async 
-	/// operations.
-	Bool8 m_copyDataBeforeReturn = true;
+	/// Access the implementation.
+	TextureImpl& getImplementation()
+	{
+		return *m_impl;
+	}
 
-	/// [level][slice]
-	Array2d<SurfaceData, MAX_MIPMAPS, MAX_TEXTURE_LAYERS> m_data;
+	/// Create it.
+	void create(const TextureInitializer& init);
+
+private:
+	UniquePtr<TextureImpl> m_impl;
 };
 /// @}
 
 } // end namespace anki
-
-#endif
-

+ 0 - 42
include/anki/gr/TexturePtr.h

@@ -1,42 +0,0 @@
-// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#ifndef ANKI_GR_TEXTURE_HANDLE_H
-#define ANKI_GR_TEXTURE_HANDLE_H
-
-#include "anki/gr/GrPtr.h"
-#include "anki/gr/TextureSamplerCommon.h"
-
-namespace anki {
-
-/// @addtogroup graphics
-/// @{
-
-/// Texture.
-class TexturePtr: public GrPtr<TextureImpl>
-{
-public:
-	using Base = GrPtr<TextureImpl>;
-	using Initializer = TextureInitializer;
-
-	/// Create husk
-	TexturePtr();
-
-	~TexturePtr();
-
-	/// Create the texture
-	void create(CommandBufferPtr& commands, const Initializer& init);
-
-	/// Bind to a unit
-	void bind(CommandBufferPtr& commands, U32 unit);
-
-	/// Generate mips
-	void generateMipmaps(CommandBufferPtr& commands);
-};
-/// @}
-
-} // end namespace anki
-
-#endif

+ 20 - 88
include/anki/gr/gl/BufferImpl.h

@@ -3,120 +3,52 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_GR_GL_BUFFER_H
-#define ANKI_GR_GL_BUFFER_H
+#pragma once
 
 #include "anki/gr/gl/GlObject.h"
 
 namespace anki {
 
-/// @addtogroup opengl_private
+/// @addtogroup opengl
 /// @{
-	
-/// A wrapper for OpenGL buffer objects (vertex arrays, texture buffers etc)
-/// to prevent us from making idiotic errors. It's storage immutable
+
+/// Buffer implementation
 class BufferImpl: public GlObject
 {
 public:
-	using Base = GlObject;
+	U32 m_size = 0; ///< The size of the buffer
+	void* m_persistentMapping = nullptr;
+	BufferUsageBit m_usage;
+#if ANKI_ASSERTIONS
+	Bool m_mapped = false;
+#endif
 
-	/// Default
 	BufferImpl(GrManager* manager)
-	:	GlObject(manager)
+		: GlObject(manager)
 	{}
 
-	/// It deletes the BO
 	~BufferImpl()
 	{
-		destroy();
-	}
-
-	/// Creates a new BO with the given parameters and checks if everything
-	/// went OK. Throws exception if fails
-	/// @param target Depends on the BO
-	/// @param dataPtr Points to the data buffer to copy to the VGA memory.
-	///		   Put NULL if you want just to allocate memory
-	/// @param sizeInBytes The size of the buffer that we will allocate in bytes
-	/// @param flags GL access flags
-	void create(
-		GLenum target, const void* dataPtr, U32 sizeInBytes, GLbitfield flags);
-
-	GLenum getTarget() const
-	{
-		ANKI_ASSERT(isCreated());
-		return m_target;
-	}
-
-	void setTarget(GLenum target)
-	{
-		ANKI_ASSERT(isCreated());
-		unbind(); // Unbind from the previous target
-		m_target = target;
+		destroyDeferred(glDeleteBuffers);
 	}
 
-	U32 getSize() const
-	{
-		ANKI_ASSERT(isCreated());
-		return m_size;
-	}
+	void create(PtrSize size, BufferUsageBit usage, BufferAccessBit access);
 
-	/// Return the prersistent mapped address
-	void* getPersistentMappingAddress()
+	void bind(GLenum target, U32 binding, PtrSize offset, PtrSize size) const
 	{
 		ANKI_ASSERT(isCreated());
-		ANKI_ASSERT(m_persistentMapping);
-		return m_persistentMapping;
+		ANKI_ASSERT(offset + size <= m_size);
+		ANKI_ASSERT(size > 0);
+		glBindBufferRange(target, binding, m_glName, offset, size);
 	}
 
-	/// Bind
-	void bind() const
+	void write(const void* buff, U32 offset, U32 size) const
 	{
 		ANKI_ASSERT(isCreated());
-		glBindBuffer(m_target, m_glName);
+		ANKI_ASSERT(offset + size <= m_size);
+		glNamedBufferSubData(m_glName, offset, size, buff);
 	}
-
-	/// Unbind BO
-	void unbind() const
-	{
-		ANKI_ASSERT(isCreated());
-		bindDefault(m_target);
-	}
-
-	/// Bind the default to a target
-	static void bindDefault(GLenum target)
-	{
-		glBindBuffer(target, 0);
-	}
-
-	/// Write data to buffer. 
-	/// @param[in] buff The buffer to copy to BO
-	void write(const void* buff)
-	{
-		write(buff, 0, m_size);
-	}
-
-	/// The same as the other write but it maps only a subset of the data
-	/// @param[in] buff The buffer to copy to BO
-	/// @param[in] offset The offset
-	/// @param[in] size The size in bytes we want to write
-	void write(const void* buff, U32 offset, U32 size);
-
-	/// Set the binding for this buffer
-	void setBinding(GLuint binding) const;
-
-	/// Set the binding point of this buffer with range
-	void setBindingRange(GLuint binding, PtrSize offset, PtrSize size) const;
-
-private:
-	GLenum m_target = GL_NONE; ///< eg GL_TEXTURE_BUFFER 
-	U32 m_size = 0; ///< The size of the buffer
-	void* m_persistentMapping = nullptr;
-
-	/// Delete the BO
-	void destroy();
 };
 /// @}
 
 } // end namespace anki
-
-#endif

+ 24 - 33
include/anki/gr/gl/CommandBufferImpl.h

@@ -3,20 +3,25 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_GR_GL_COMMAND_BUFFER_IMPL_H
-#define ANKI_GR_GL_COMMAND_BUFFER_IMPL_H
+#pragma once
 
-#include "anki/gr/GrObject.h"
 #include "anki/gr/GrManager.h"
+#include "anki/gr/CommandBuffer.h"
 #include "anki/util/Assert.h"
 #include "anki/util/Allocator.h"
 
 namespace anki {
 
+// Forward
+class GlState;
+
 /// @addtogroup opengl
 /// @{
 
-/// The base of all GL commands
+template<typename T>
+using CommandBufferAllocator = ChainAllocator<T>;
+
+/// The base of all GL commands.
 class GlCommand
 {
 public:
@@ -26,18 +31,18 @@ public:
 	{}
 
 	/// Execute command
-	virtual ANKI_USE_RESULT Error operator()(CommandBufferImpl*) = 0;
+	virtual ANKI_USE_RESULT Error operator()(GlState& state) = 0;
 };
 
 /// A number of GL commands organized in a chain
-class CommandBufferImpl: public GrObject
+class CommandBufferImpl
 {
 public:
 	using InitHints = CommandBufferInitHints;
 
 	/// Default constructor
 	CommandBufferImpl(GrManager* manager)
-	:	GrObject(manager)
+		: m_manager(manager)
 	{}
 
 	~CommandBufferImpl()
@@ -56,10 +61,12 @@ public:
 		return m_alloc;
 	}
 
-	/// Compute initialization hints
+	GrAllocator<U8> getAllocator() const;
+
+	/// Compute initialization hints.
 	InitHints computeInitHints() const;
 
-	/// Create a new command and add it to the chain
+	/// Create a new command and add it to the chain.
 	template<typename TCommand, typename... TArgs>
 	void pushBackNewCommand(TArgs&&... args);
 
@@ -80,7 +87,13 @@ public:
 		m_immutable = true;
 	}
 
+	GrManager& getManager()
+	{
+		return *m_manager;
+	}
+
 private:
+	GrManager* m_manager = nullptr;
 	GlCommand* m_firstCommand = nullptr;
 	GlCommand* m_lastCommand = nullptr;
 	CommandBufferAllocator<U8> m_alloc;
@@ -95,9 +108,9 @@ private:
 
 //==============================================================================
 template<typename TCommand, typename... TArgs>
-void CommandBufferImpl::pushBackNewCommand(TArgs&&... args)
+inline void CommandBufferImpl::pushBackNewCommand(TArgs&&... args)
 {
-	ANKI_ASSERT(m_immutable == false);
+	ANKI_ASSERT(!m_immutable);
 	TCommand* newCommand = m_alloc.template newInstance<TCommand>(
 		std::forward<TArgs>(args)...);
 
@@ -115,29 +128,7 @@ void CommandBufferImpl::pushBackNewCommand(TArgs&&... args)
 		m_lastCommand = newCommand;
 	}
 }
-
-/// A common command that deletes an object.
-template<typename T>
-class DeleteObjectCommand: public GlCommand
-{
-public:
-	T* m_ptr;
-
-	DeleteObjectCommand(T* ptr)
-	:	m_ptr(ptr)
-	{
-		ANKI_ASSERT(m_ptr);
-	}
-
-	Error operator()(CommandBufferImpl* cmdb) override
-	{
-		cmdb->getManager().getAllocator().deleteInstance(m_ptr);
-		return ErrorCode::NONE;
-	}
-};
 /// @}
 
 } // end namespace anki
 
-#endif
-

+ 20 - 0
include/anki/gr/gl/Common.h

@@ -3,10 +3,30 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
+#pragma once
+
 #include "anki/gr/Common.h"
 
+#if ANKI_GL == ANKI_GL_DESKTOP
+#	if ANKI_OS == ANKI_OS_WINDOWS && !defined(GLEW_STATIC)
+#		define GLEW_STATIC
+#	endif
+#	include <GL/glew.h>
+#	if !defined(ANKI_GLEW_H)
+#		error "Wrong GLEW included"
+#	endif
+#elif ANKI_GL == ANKI_GL_ES
+#	include <GLES3/gl3.h>
+#else
+#	error "See file"
+#endif
+
 namespace anki {
 
+// Forward
+class GlState;
+class RenderingThread;
+
 /// @addtogroup opengl
 /// @{
 

+ 3 - 5
include/anki/gr/gl/Error.h

@@ -3,10 +3,9 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_GR_GL_ERROR_H
-#define ANKI_GR_GL_ERROR_H
+#pragma once
 
-#include "anki/gr/Common.h"
+#include "anki/gr/gl/Common.h"
 
 namespace anki {
 
@@ -17,7 +16,7 @@ namespace anki {
 
 #if ANKI_DEBUG
 
-/// The function exits if there is an OpenGL error. Use it with the 
+/// The function exits if there is an OpenGL error. Use it with the
 /// ANKI_CHECK_GL_ERROR macro
 void glConditionalCheckError(const char* file, int line, const char* func);
 
@@ -30,4 +29,3 @@ void glConditionalCheckError(const char* file, int line, const char* func);
 
 } // end namespace anki
 
-#endif

+ 10 - 19
include/anki/gr/gl/FramebufferImpl.h

@@ -3,11 +3,10 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_GR_GL_FRAMEBUFFER_IMPL_H
-#define ANKI_GR_GL_FRAMEBUFFER_IMPL_H
+#pragma once
 
 #include "anki/gr/gl/GlObject.h"
-#include "anki/gr/FramebufferCommon.h"
+#include "anki/gr/Framebuffer.h"
 
 namespace anki {
 
@@ -15,51 +14,43 @@ namespace anki {
 /// @{
 
 /// Framebuffer implementation.
-class FramebufferImpl: public GlObject, private FramebufferInitializer
+class FramebufferImpl: public GlObject
 {
 public:
-	using Base = GlObject;
-	using Initializer = FramebufferInitializer;
-
 	FramebufferImpl(GrManager* manager)
-	:	Base(manager)
+		: GlObject(manager)
 	{}
 
 	~FramebufferImpl()
 	{
-		destroy();
+		destroyDeferred(glDeleteFramebuffers);
 	}
 
 	/// Set all the attachments. It will overwrite the previous state. If the
 	/// initalizer list is empty the it will bind the default framebuffer
-	ANKI_USE_RESULT Error create(Initializer& init);
+	ANKI_USE_RESULT Error create(const FramebufferInitializer& init);
 
 	/// Bind it to the state. Call it in rendering thread
-	void bind();
-
-	/// Blit another framebuffer to this
-	void blit(const FramebufferImpl& fb, const Array<U32, 4>& sourceRect,
-		const Array<U32, 4>& destRect, GLbitfield attachmentMask, Bool linear);
+	void bind(const GlState& state);
 
 private:
+	FramebufferInitializer m_in;
+
 	Array<GLenum, MAX_COLOR_ATTACHMENTS> m_drawBuffers;
 	Array<GLenum, MAX_COLOR_ATTACHMENTS + 1> m_invalidateBuffers;
 	U8 m_invalidateBuffersCount = 0;
 	Bool8 m_bindDefault = false;
 
 	/// Attach a texture
-	static void attachTextureInternal(GLenum attachment, const TextureImpl& tex, 
+	static void attachTextureInternal(GLenum attachment, const TextureImpl& tex,
 		const U32 layer);
 
 	/// Create the FBO
 	ANKI_USE_RESULT Error createFbo(
 		const Array<U, MAX_COLOR_ATTACHMENTS + 1>& layers,
 		GLenum depthStencilBindingPoint);
-
-	void destroy();
 };
 /// @}
 
 } // end namespace anki
 
-#endif

+ 15 - 14
include/anki/gr/gl/GlObject.h

@@ -3,10 +3,8 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_GR_GL_OBJECT_H
-#define ANKI_GR_GL_OBJECT_H
+#pragma once
 
-#include "anki/gr/GrObject.h"
 #include "anki/gr/gl/Common.h"
 
 namespace anki {
@@ -26,18 +24,14 @@ enum class GlObjectState: U32
 };
 
 /// A GL object
-class GlObject: public GrObject
+class GlObject
 {
 public:
 	using State = GlObjectState;
 	using GlDeleteFunction = void (*)(GLsizei, const GLuint*);
 
 	/// Default
-	GlObject(GrManager* manager)
-	:	GrObject(manager),
-		m_glName(0),
-		m_state(I32(State::NEW))
-	{}
+	GlObject(GrManager* manager);
 
 	~GlObject()
 	{
@@ -52,7 +46,7 @@ public:
 		return m_glName;
 	}
 
-	/// GL object is created
+	/// GL object is created.
 	Bool isCreated() const
 	{
 		return m_glName != 0;
@@ -64,17 +58,24 @@ public:
 	}
 
 	/// Check if the object has been created and if not serialize the thread.
-	ANKI_USE_RESULT Error serializeOnGetter() const;
+	ANKI_USE_RESULT Error serializeRenderingThread();
 
 	/// 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;
+	}
+
 protected:
-	GLuint m_glName; ///< OpenGL name
+	GrManager* m_manager = nullptr;
+	GLuint m_glName = 0; ///< OpenGL name
 	mutable Atomic<I32> m_state;
 };
 /// @}
 
 } // end namespace anki
-
-#endif

+ 4 - 11
include/anki/gr/gl/GlState.h

@@ -3,11 +3,10 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_GR_GL_STATE_H
-#define ANKI_GR_GL_STATE_H
+#pragma once
 
-#include "anki/gr/Common.h"
-#include "anki/gr/PipelinePtr.h"
+#include "anki/gr/gl/Common.h"
+#include "anki/util/DArray.h"
 
 namespace anki {
 
@@ -31,7 +30,6 @@ public:
 
 	I32 m_version = -1; ///< Minor major GL version. Something like 430
 	GpuVendor m_gpu = GpuVendor::UNKNOWN;
-	U32 m_texUnitsCount = 0;
 	Bool8 m_registerMessages = false;
 	U32 m_uniBuffOffsetAlignment = 0;
 	U32 m_ssBuffOffsetAlignment = 0;
@@ -44,16 +42,13 @@ public:
 	GLenum m_blendDfunc = GL_ZERO;
 
 	GLuint m_crntPpline = 0;
-
-	Array<GLuint, 256> m_texUnits;
-
-	GLenum m_indexSize = GL_NONE;
 	/// @}
 
 	/// @name Pipeline state
 	/// @{
 	Array<GLsizei, MAX_VERTEX_ATTRIBUTES> m_vertexBindingStrides;
 	GLenum m_topology = 0;
+	U8 m_indexSize = 4;
 
 	class
 	{
@@ -102,5 +97,3 @@ private:
 
 } // end namespace anki
 
-#endif
-

+ 4 - 5
include/anki/gr/gl/GrManagerImpl.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_GR_GL_GR_MANAGER_IMPL_H
-#define ANKI_GR_GL_GR_MANAGER_IMPL_H
+#pragma once
 
 #include "anki/gr/Common.h"
 
@@ -21,7 +20,7 @@ class GrManagerImpl
 {
 public:
 	GrManagerImpl(GrManager* manager)
-	:	m_manager(manager)
+		: m_manager(manager)
 	{
 		ANKI_ASSERT(manager);
 	}
@@ -40,6 +39,8 @@ public:
 		return *m_thread;
 	}
 
+	GrAllocator<U8> getAllocator() const;
+
 private:
 	GrManager* m_manager;
 	RenderingThread* m_thread = nullptr;
@@ -48,5 +49,3 @@ private:
 
 } // end namespace anki
 
-#endif
-

+ 6 - 14
include/anki/gr/gl/OcclusionQueryImpl.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_GR_GL_OCCLUSION_QUERY_IMPL_H
-#define ANKI_GR_GL_OCCLUSION_QUERY_IMPL_H
+#pragma once
 
 #include "anki/gr/gl/GlObject.h"
 
@@ -17,24 +16,20 @@ namespace anki {
 class OcclusionQueryImpl: public GlObject
 {
 public:
-	using Base = GlObject;
-	using ResultBit = OcclusionQueryResultBit;
-	using Result = OcclusionQueryResult;
-
 	OcclusionQueryImpl(GrManager* manager)
-	:	Base(manager)
+		: GlObject(manager)
 	{}
 
 	~OcclusionQueryImpl()
 	{
-		destroy();
+		destroyDeferred(glDeleteQueries);
 	}
 
 	/// Create the query.
 	/// @param condRenderingBit If the query is used in conditional rendering
 	///        the result will be checked against this mask. If the result
 	///        contains any of the bits then the dracall will not be skipped.
-	void create(ResultBit condRenderingBit);
+	void create(OcclusionQueryResultBit condRenderingBit);
 
 	/// Begin query.
 	void begin();
@@ -43,7 +38,7 @@ public:
 	void end();
 
 	/// Get query result.
-	Result getResult() const;
+	OcclusionQueryResult getResult() const;
 
 	/// Return true if the drawcall should be skipped.
 	Bool skipDrawcall() const
@@ -54,12 +49,9 @@ public:
 	}
 
 private:
-	ResultBit m_condRenderingBit;
-	void destroy();
+	OcclusionQueryResultBit m_condRenderingBit;
 };
 /// @}
 
 } // end namespace anki
 
-#endif
-

+ 5 - 13
include/anki/gr/gl/PipelineImpl.h

@@ -6,13 +6,10 @@
 #pragma once
 
 #include "anki/gr/gl/GlObject.h"
-#include "anki/gr/PipelineCommon.h"
+#include "anki/gr/Pipeline.h"
 
 namespace anki {
 
-// Forward
-class GlState;
-
 /// @addtogroup opengl
 /// @{
 
@@ -20,22 +17,19 @@ class GlState;
 class PipelineImpl: public GlObject
 {
 public:
-	using Base = GlObject;
-	using Initializer = PipelineInitializer;
-
 	PipelineImpl(GrManager* manager)
-		: Base(manager)
+		: GlObject(manager)
 	{}
 
 	~PipelineImpl()
 	{
-		destroy();
+		destroyDeferred(glDeleteProgramPipelines);
 	}
 
-	ANKI_USE_RESULT Error create(const Initializer& init);
+	ANKI_USE_RESULT Error create(const PipelineInitializer& init);
 
 	/// Bind the pipeline to the state
-	void bind();
+	void bind(GlState& state);
 
 private:
 	class Attribute
@@ -91,8 +85,6 @@ private:
 	/// Attach all the programs
 	ANKI_USE_RESULT Error createGlPipeline();
 
-	void destroy();
-
 	void initVertexState();
 	void initInputAssemblerState();
 	void initTessellationState();

+ 6 - 14
include/anki/gr/gl/RenderingThread.h

@@ -3,10 +3,9 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_GR_GL_RENDERING_THREAD_H
-#define ANKI_GR_GL_RENDERING_THREAD_H
+#pragma once
 
-#include "anki/gr/CommandBufferPtr.h"
+#include "anki/gr/CommandBuffer.h"
 #include "anki/gr/gl/GlState.h"
 #include "anki/util/Thread.h"
 
@@ -22,6 +21,7 @@ namespace anki {
 class RenderingThread
 {
 	friend class SyncCommand;
+	friend class SwapBuffersCommand;
 
 public:
 	RenderingThread(GrManager* device);
@@ -38,11 +38,6 @@ public:
 		return m_state;
 	}
 
-	GLuint getCopyFbo() const
-	{
-		return m_copyFbo;
-	}
-
 	/// Start the working thread
 	/// @note Don't free the context before calling #stop
 	ANKI_USE_RESULT Error start(
@@ -54,10 +49,10 @@ public:
 	void stop();
 
 	/// Push a command buffer to the queue for deferred execution
-	void flushCommandBuffer(CommandBufferPtr& commands);
+	void flushCommandBuffer(CommandBufferPtr commands);
 
 	/// Push a command buffer to the queue and wait for it
-	void finishCommandBuffer(CommandBufferPtr& commands);
+	void finishCommandBuffer(CommandBufferPtr commands);
 
 	/// Sync the client and server
 	void syncClientServer();
@@ -103,18 +98,15 @@ private:
 	CommandBufferPtr m_syncCommands;
 	Barrier m_syncBarrier{2};
 
-	GLuint m_copyFbo = MAX_U32; ///< FBO for copying from tex to buffer.
-
 	/// The function that the thread runs
 	static ANKI_USE_RESULT Error threadCallback(Thread::Info&);
 	void threadLoop();
 	void prepare();
 	void finish();
 
-	static Error swapBuffersInternal(void* self);
+	void swapBuffersInternal();
 };
 /// @}
 
 } // end namespace anki
 
-#endif

+ 23 - 22
include/anki/gr/gl/ResourceGroupImpl.h

@@ -3,11 +3,10 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_GR_GL_RESOURCE_GROUP_IMPL_H
-#define ANKI_GR_GL_RESOURCE_GROUP_IMPL_H
+#pragma once
 
 #include "anki/gr/gl/GlObject.h"
-#include "anki/gr/ResourceGroupCommon.h"
+#include "anki/gr/ResourceGroup.h"
 
 namespace anki {
 
@@ -15,39 +14,41 @@ namespace anki {
 /// @{
 
 /// Resource group implementation.
-class ResourceGroupImpl: public GlObject, private ResourceGroupInitializer
+class ResourceGroupImpl: public GlObject
 {
 public:
-	using Base = GlObject;
-	using Initializer = ResourceGroupInitializer;
-
 	ResourceGroupImpl(GrManager* manager)
-	:	Base(manager)
+		: GlObject(manager)
 	{}
 
 	~ResourceGroupImpl()
 	{}
 
-	ANKI_USE_RESULT Error create(const Initializer& init);
+	void create(const ResourceGroupInitializer& init);
 
 	/// Set state.
-	void bind();
+	void bind(GlState& state);
 
 private:
-	Array<GLuint, MAX_TEXTURE_BINDINGS> m_textureNames;
-	Array<GLuint, MAX_TEXTURE_BINDINGS> m_samplerNames;
-	U8 m_textureNamesCount = 0;
-	Bool8 m_allSamplersZero = false;
-
-	U8 m_ubosCount = 0;
-	U8 m_ssbosCount = 0;
-
-	Array<GLuint, MAX_VERTEX_ATTRIBUTES> m_vertBuffNames;
-	Array<GLintptr, MAX_VERTEX_ATTRIBUTES> m_vertBuffOffsets;
-	U8 m_vertBindingsCount = 0;
+	ResourceGroupInitializer m_in; ///< That will hold the references
+
+	class
+	{
+	public:
+		Array<GLuint, MAX_TEXTURE_BINDINGS> m_textureNames;
+		Array<GLuint, MAX_TEXTURE_BINDINGS> m_samplerNames;
+		U8 m_textureNamesCount = 0;
+		Bool8 m_allSamplersZero = false;
+
+		U8 m_ubosCount = 0;
+		U8 m_ssbosCount = 0;
+
+		Array<GLuint, MAX_VERTEX_ATTRIBUTES> m_vertBuffNames;
+		Array<GLintptr, MAX_VERTEX_ATTRIBUTES> m_vertBuffOffsets;
+		U8 m_vertBindingsCount = 0;
+	} m_cache;
 };
 /// @}
 
 } // end namespace anki
 
-#endif

+ 5 - 29
include/anki/gr/gl/SamplerImpl.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_GR_GL_SAMPLER_IMPL_H
-#define ANKI_GR_GL_SAMPLER_IMPL_H
+#pragma once
 
 #include "anki/gr/gl/GlObject.h"
 
@@ -17,43 +16,20 @@ namespace anki {
 class SamplerImpl: public GlObject
 {
 public:
-	using Base = GlObject;
-
 	SamplerImpl(GrManager* manager)
-	:	Base(manager)
+		: GlObject(manager)
 	{}
 
 	~SamplerImpl()
 	{
-		destroy();
-	}
-
-	ANKI_USE_RESULT Error create(const SamplerInitializer& sinit);
-
-	/// Bind the texture to a specified unit
-	void bind(U32 unit) const
-	{
-		ANKI_ASSERT(isCreated());
-		glBindSampler(unit, m_glName);
+		destroyDeferred(glDeleteSamplers);
 	}
 
-	/// Unbind sampler from unit
-	static void unbind(U32 unit)
-	{
-		glBindSampler(unit, 0);
-	}
+	void create(const SamplerInitializer& sinit);
 
 private:
-	void destroy()
-	{
-		if(m_glName)
-		{
-			destroyDeferred(glDeleteSamplers);
-		}
-	}
+	void createInternal(const SamplerInitializer& sinit);
 };
 /// @}
 
 } // end namespace anki
-
-#endif

+ 12 - 35
include/anki/gr/gl/ShaderImpl.h

@@ -3,66 +3,43 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_GR_GL_SHADER_IMPL_H
-#define ANKI_GR_GL_SHADER_IMPL_H
+#pragma once
 
-#include "anki/gr/ShaderCommon.h"
+#include "anki/gr/Shader.h"
 #include "anki/gr/gl/GlObject.h"
 
 namespace anki {
 
+// Forward
+class CString;
+class String;
+
 /// @addtogroup opengl
 /// @{
 
-/// Shader program. It only contains a single shader and it can be combined 
+/// Shader program. It only contains a single shader and it can be combined
 /// with other programs in a program pipiline.
 class ShaderImpl: public GlObject
 {
-	friend class GlProgramVariable;
-	friend class GlProgramBlock;
-
 public:
-	using Base = GlObject;
+	GLenum m_glType = 0;
+	ShaderType m_type;
 
 	ShaderImpl(GrManager* manager)
-	:	Base(manager)
+		: GlObject(manager)
 	{}
 
-	~ShaderImpl()
-	{
-		destroy();
-	}
+	~ShaderImpl();
 
 	/// Create the shader.
 	/// @param shaderType The type of the shader in the program
 	/// @param source The shader's source
-	ANKI_USE_RESULT Error create(
-		ShaderType shaderType, 
-		const CString& source);
-
-	GLenum getGlType() const
-	{
-		ANKI_ASSERT(isCreated());
-		return m_glType;
-	}
-
-	ShaderType getType() const
-	{
-		ANKI_ASSERT(isCreated());
-		return m_type;
-	}
+	ANKI_USE_RESULT Error create(ShaderType shaderType, const CString& source);
 
 private:
-	GLenum m_glType = 0;
-	ShaderType m_type;
-
-	void destroy();
-
 	void handleError(String& src);
 };
 /// @}
 
 } // end namespace anki
 
-#endif
-

+ 20 - 57
include/anki/gr/gl/TextureImpl.h

@@ -3,89 +3,52 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_GR_GL_TEXTURE_IMPL_H
-#define ANKI_GR_GL_TEXTURE_IMPL_H
+#pragma once
 
 #include "anki/gr/gl/GlObject.h"
-#include "anki/util/Array.h"
 
 namespace anki {
 
 /// @addtogroup opengl
 /// @{
 
-/// Texture container
+/// Texture container.
 class TextureImpl: public GlObject
 {
 public:
-	using Base = GlObject;
-	using Initializer = TextureInitializer;
+	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;
+	U32 m_width = 0;
+	U32 m_height = 0;
+	U32 m_depth = 0;
+	U8 m_mipsCount = 0;
+	Bool8 m_compressed = false;
 
 	TextureImpl(GrManager* manager)
-	:	Base(manager)
+		: GlObject(manager)
 	{}
 
 	~TextureImpl()
 	{
-		destroy();
+		destroyDeferred(glDeleteTextures);
 	}
 
-	/// Create a texture
-	void create(const Initializer& init);
+	/// Create the texture storage.
+	void create(const TextureInitializer& init);
 
-	GLenum getInternalFormat() const
-	{
-		ANKI_ASSERT(isCreated());
-		return m_internalFormat;
-	}
+	/// Write texture data.
+	void write(U32 mipmap, U32 slice, void* data, PtrSize dataSize);
 
-	GLenum getTarget() const
-	{
-		ANKI_ASSERT(isCreated());
-		return m_target;
-	}
-
-	U32 getWidth() const
-	{
-		ANKI_ASSERT(isCreated());
-		return m_width;
-	}
-
-	U32 getHeight() const
-	{
-		ANKI_ASSERT(isCreated());
-		return m_height;
-	}
-
-	U32 getDepth() const
-	{
-		ANKI_ASSERT(isCreated());
-		return m_depth;
-	}
-
-	/// Bind the texture to a specified unit
-	void bind(U32 unit) const;
-
-	/// Generate mipmaps
+	/// Generate mipmaps.
 	void generateMipmaps();
 
-private:
-	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;
-	U32 m_width = 0;
-	U32 m_height = 0;
-	U32 m_depth = 0;
-	U8 m_mipsCount = 0;
-	Bool8 m_compressed = false;
-
-	void destroy();
+	void bind();
 
+private:
 	static U32 computeMaxMipmapCount(U32 w, U32 h);
 };
 /// @}
 
 } // end namespace anki
-
-#endif

+ 1 - 1
src/gr/ShaderCommon.cpp → src/gr/Shader.cpp

@@ -3,7 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#include "anki/gr/ShaderCommon.h"
+#include "anki/gr/Shader.h"
 
 namespace anki {
 

+ 98 - 0
src/gr/gl/Buffer.cpp

@@ -0,0 +1,98 @@
+// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include "anki/gr/Buffer.h"
+#include "anki/gr/gl/BufferImpl.h"
+#include "anki/gr/gl/CommandBufferImpl.h"
+
+namespace anki {
+
+//==============================================================================
+Buffer::Buffer(GrManager* manager)
+	: GrObject(manager)
+{}
+
+//==============================================================================
+Buffer::~Buffer()
+{}
+
+//==============================================================================
+class BufferCreateCommand final: public GlCommand
+{
+public:
+	BufferPtr m_buff;
+	PtrSize m_size;
+	BufferUsageBit m_usage;
+	BufferAccessBit m_access;
+
+	BufferCreateCommand(Buffer* buff, PtrSize size, BufferUsageBit usage,
+		BufferAccessBit access)
+		: m_buff(buff)
+		, m_size(size)
+		, m_usage(usage)
+		, m_access(access)
+	{}
+
+	Error operator()(GlState&)
+	{
+		BufferImpl& impl = m_buff->getImplementation();
+
+		impl.create(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 ErrorCode::NONE;
+	}
+};
+
+void Buffer::create(PtrSize size, BufferUsageBit usage, BufferAccessBit access)
+{
+	m_impl.reset(getAllocator().newInstance<BufferImpl>(&getManager()));
+
+	CommandBufferPtr cmdb = getManager().newInstance<CommandBuffer>();
+
+	cmdb->getImplementation().pushBackNewCommand<BufferCreateCommand>(
+		this, size, usage, access);
+	cmdb->flush();
+}
+
+//==============================================================================
+void* Buffer::map(PtrSize offset, PtrSize range, BufferAccessBit access)
+{
+	// Wait for it's 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_ASSERTIONS
+	ANKI_ASSERT(!m_impl->m_mapped);
+	m_impl->m_mapped = true;
+#endif
+
+	return static_cast<void*>(ptr);
+}
+
+//==============================================================================
+void Buffer::unmap()
+{
+#if ANKI_ASSERTIONS
+	ANKI_ASSERT(m_impl->m_mapped);
+	m_impl->m_mapped = false;
+#endif
+}
+
+} // end namespace anki

+ 66 - 67
src/gr/gl/BufferImpl.cpp

@@ -4,116 +4,115 @@
 // http://www.anki3d.org/LICENSE
 
 #include "anki/gr/gl/BufferImpl.h"
-#include "anki/gr/gl/Error.h"
 #include "anki/util/Logger.h"
-#include <cstring>
 #include <cmath>
 
 namespace anki {
 
 //==============================================================================
-void BufferImpl::destroy()
-{
-	if(isCreated())
-	{
-		destroyDeferred(glDeleteBuffers);
-	}
-}
-
-//==============================================================================
-void BufferImpl::create(GLenum target, const void* dataPtr,
-	U32 sizeInBytes, GLbitfield flags)
+void BufferImpl::create(
+	PtrSize size, BufferUsageBit usage, BufferAccessBit access)
 {
 	ANKI_ASSERT(!isCreated());
+	m_usage = usage;
+
+	///
+	// Check size
+	//
+
+	ANKI_ASSERT(size > 0 && "Unacceptable size");
 
-	if(target == GL_UNIFORM_BUFFER)
+	// This is a guess, not very important since DSA doesn't care about it on
+	// creation
+	GLenum target = GL_ARRAY_BUFFER;
+
+	if((usage & BufferUsageBit::UNIFORM_BUFFER) != BufferUsageBit::NONE)
 	{
 		GLint64 maxBufferSize;
 		glGetInteger64v(GL_MAX_UNIFORM_BLOCK_SIZE, &maxBufferSize);
 
-		if(sizeInBytes > 16384)
+		if(size > 16384)
 		{
 			ANKI_LOGW("The size (%u) of the uniform buffer is greater "
-				"than the spec's min", sizeInBytes);
+				"than the spec's min", size);
 		}
-		else if(sizeInBytes > (PtrSize)maxBufferSize)
+		else if(size > PtrSize(maxBufferSize))
 		{
 			ANKI_LOGW("The size (%u) of the uniform buffer is greater "
-				"than the implementation's min (%u)", sizeInBytes,
-				maxBufferSize);
+				"than the implementation's min (%u)", size, maxBufferSize);
 		}
+
+		target = GL_UNIFORM_BUFFER;
 	}
-	else if(target == GL_SHADER_STORAGE_BUFFER)
+
+	if((usage & BufferUsageBit::STORAGE_BUFFER) != BufferUsageBit::NONE)
 	{
 		GLint64 maxBufferSize;
 		glGetInteger64v(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &maxBufferSize);
 
-		if(sizeInBytes > pow(2, 24))
+		if(size > pow(2, 24))
 		{
 			ANKI_LOGW("The size (%u) of the uniform buffer is greater "
-				"than the spec's min", sizeInBytes);
+				"than the spec's min", size);
 		}
-		else if(sizeInBytes > (PtrSize)maxBufferSize)
+		else if(size > PtrSize(maxBufferSize))
 		{
 			ANKI_LOGW("The size (%u) of the shader storage buffer is greater "
-				"than the implementation's min (%u)", sizeInBytes,
-				maxBufferSize);
+				"than the implementation's min (%u)", size, maxBufferSize);
 		}
+
+		target = GL_SHADER_STORAGE_BUFFER;
 	}
 
-	m_target = target;
-	m_size = sizeInBytes;
+	m_size = size;
 
-	ANKI_ASSERT(m_size > 0 && "Unacceptable size");
+	//
+	// Determine the creation flags
+	//
+	GLbitfield flags = 0;
+	Bool shouldMap = false;
+	if((access & BufferAccessBit::CLIENT_WRITE) != BufferAccessBit::NONE)
+	{
+		flags |= GL_DYNAMIC_STORAGE_BIT;
+	}
 
+	if((access & BufferAccessBit::CLIENT_MAP_WRITE) != BufferAccessBit::NONE)
+	{
+		flags |= GL_MAP_WRITE_BIT;
+		flags |= GL_MAP_PERSISTENT_BIT;
+		flags |= GL_MAP_COHERENT_BIT;
+
+		shouldMap = true;
+	}
+
+	if((access & BufferAccessBit::CLIENT_MAP_READ) != BufferAccessBit::NONE)
+	{
+		flags |= GL_MAP_READ_BIT;
+		flags |= GL_MAP_PERSISTENT_BIT;
+		flags |= GL_MAP_COHERENT_BIT;
+
+		shouldMap = true;
+	}
+
+	//
 	// Create
+	//
 	glGenBuffers(1, &m_glName);
+	glBindBuffer(target, m_glName);
+	glBufferStorage(target, size, nullptr, flags);
 
-	glBindBuffer(m_target, m_glName);
-	glBufferStorage(m_target, m_size, dataPtr, flags);
-
-	// Map if needed
-	if((flags & GL_MAP_PERSISTENT_BIT) && (flags & GL_MAP_COHERENT_BIT))
+	//
+	// Map
+	//
+	if(shouldMap)
 	{
-		const GLbitfield mapbits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT
+		const GLbitfield MAP_BITS = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT
 			| GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;
 
 		m_persistentMapping =
-			glMapBufferRange(m_target, 0, sizeInBytes, flags & mapbits);
+			glMapBufferRange(target, 0, size, flags & MAP_BITS);
 		ANKI_ASSERT(m_persistentMapping != nullptr);
 	}
 }
 
-//==============================================================================
-void BufferImpl::write(const void* buff, U32 offset, U32 size)
-{
-	ANKI_ASSERT(isCreated());
-	ANKI_ASSERT(offset + size <= size);
-
-	bind();
-	glBufferSubData(m_target, offset, size, buff);
-}
-
-//==============================================================================
-void BufferImpl::setBinding(GLuint binding) const
-{
-	ANKI_ASSERT(isCreated());
-	ANKI_ASSERT(m_target == GL_SHADER_STORAGE_BUFFER
-		|| m_target == GL_UNIFORM_BUFFER);
-	glBindBufferBase(m_target, binding, m_glName);
-}
-
-//==============================================================================
-void BufferImpl::setBindingRange(
-	GLuint binding, PtrSize offset, PtrSize size) const
-{
-	ANKI_ASSERT(isCreated());
-	ANKI_ASSERT(offset + size <= m_size);
-	ANKI_ASSERT(size > 0);
-	ANKI_ASSERT(m_target == GL_SHADER_STORAGE_BUFFER
-		|| m_target == GL_UNIFORM_BUFFER);
-
-	glBindBufferRange(m_target, binding, m_glName, offset, size);
-}
-
 } // end namespace anki

+ 0 - 298
src/gr/gl/BufferPtr.cpp

@@ -1,298 +0,0 @@
-// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#include "anki/gr/BufferPtr.h"
-#include "anki/gr/gl/BufferImpl.h"
-#include "anki/gr/GrManager.h"
-#include "anki/gr/gl/CommandBufferImpl.h"
-#include "anki/gr/CommandBufferPtr.h"
-
-namespace anki {
-
-//==============================================================================
-// Commands                                                                    =
-//==============================================================================
-
-//==============================================================================
-/// Create buffer command
-class BufferCreateCommand final: public GlCommand
-{
-public:
-	BufferPtr m_buff;
-	GLenum m_target;
-	const void* m_data;
-	PtrSize m_size;
-	GLbitfield m_flags;
-	Bool8 m_cleanup;
-
-	BufferCreateCommand(
-		BufferPtr buff, GLenum target, const void* data, PtrSize size,
-		GLenum flags, Bool cleanup)
-	:	m_buff(buff),
-		m_target(target),
-		m_data(data),
-		m_size(size),
-		m_flags(flags),
-		m_cleanup(cleanup)
-	{}
-
-	Error operator()(CommandBufferImpl* cmdb)
-	{
-		m_buff.get().create(m_target, m_data, m_size, m_flags);
-
-		GlObject::State oldState =
-			m_buff.get().setStateAtomically(GlObject::State::CREATED);
-
-		(void)oldState;
-		ANKI_ASSERT(oldState == GlObject::State::TO_BE_CREATED);
-
-		if(m_cleanup)
-		{
-			cmdb->getInternalAllocator().deallocate(
-				const_cast<void*>(m_data), 1);
-		}
-
-		return ErrorCode::NONE;
-	}
-};
-
-//==============================================================================
-class BufferWriteCommand: public GlCommand
-{
-public:
-	BufferPtr m_buff;
-	const void* m_data;
-	PtrSize m_dataSize;
-	PtrSize m_readOffset;
-	PtrSize m_writeOffset;
-	PtrSize m_size;
-
-	BufferWriteCommand(BufferPtr& buff, const void* data, PtrSize dataSize,
-		PtrSize readOffset, PtrSize writeOffset, PtrSize size)
-	:	m_buff(buff),
-		m_data(data),
-		m_dataSize(dataSize),
-		m_readOffset(readOffset),
-		m_writeOffset(writeOffset),
-		m_size(size)
-	{}
-
-	Error operator()(CommandBufferImpl* cmdb) final
-	{
-		ANKI_ASSERT(m_readOffset + m_size <= m_dataSize);
-
-		m_buff.get().write(
-			static_cast<const U8*>(m_data) + m_readOffset,
-			m_writeOffset,
-			m_size);
-
-		ANKI_ASSERT(cmdb);
-		cmdb->getInternalAllocator().deallocate(const_cast<void*>(m_data), 1);
-
-		return ErrorCode::NONE;
-	}
-};
-
-//==============================================================================
-class BufferBindVertexCommand: public GlCommand
-{
-public:
-	BufferPtr m_buff;
-	U32 m_elementSize;
-	GLenum m_type;
-	Bool8 m_normalized;
-	U32 m_stride;
-	U32 m_offset;
-	U32 m_attribLocation;
-
-	BufferBindVertexCommand(BufferPtr& buff, U32 elementSize, GLenum type,
-		Bool8 normalized, U32 stride, U32 offset, U32 attribLocation)
-	:	m_buff(buff),
-		m_elementSize(elementSize),
-		m_type(type),
-		m_normalized(normalized),
-		m_stride(stride),
-		m_offset(offset),
-		m_attribLocation(attribLocation)
-	{
-		ANKI_ASSERT(m_elementSize != 0);
-	}
-
-	Error operator()(CommandBufferImpl*)
-	{
-		BufferImpl& buff = m_buff.get();
-		ANKI_ASSERT(m_offset < m_buff.getSize());
-
-		buff.setTarget(GL_ARRAY_BUFFER);
-		buff.bind();
-
-		glEnableVertexAttribArray(m_attribLocation);
-		glVertexAttribPointer(
-			m_attribLocation,
-			m_elementSize,
-			m_type,
-			m_normalized,
-			m_stride,
-			reinterpret_cast<const GLvoid*>(m_offset));
-
-		return ErrorCode::NONE;
-	}
-};
-
-//==============================================================================
-class BindShaderBufferCommand: public GlCommand
-{
-public:
-	BufferPtr m_buff;
-	I32 m_offset;
-	I32 m_size;
-	U8 m_binding;
-
-	BindShaderBufferCommand(BufferPtr& buff,
-		I32 offset, I32 size, U8 binding)
-	:
-		m_buff(buff),
-		m_offset(offset),
-		m_size(size),
-		m_binding(binding)
-	{}
-
-	Error operator()(CommandBufferImpl*) final
-	{
-		U32 offset = (m_offset != -1) ? m_offset : 0;
-		U32 size = (m_size != -1) ? m_size : m_buff.get().getSize();
-
-		m_buff.get().setBindingRange(m_binding, offset, size);
-
-		return ErrorCode::NONE;
-	}
-};
-
-//==============================================================================
-class BindIndexBufferCommand: public GlCommand
-{
-public:
-	BufferPtr m_buff;
-
-	BindIndexBufferCommand(BufferPtr& buff)
-	:	m_buff(buff)
-	{}
-
-	Error operator()(CommandBufferImpl*)
-	{
-		BufferImpl& buff = m_buff.get();
-		buff.setTarget(GL_ELEMENT_ARRAY_BUFFER);
-		buff.bind();
-
-		return ErrorCode::NONE;
-	}
-};
-
-//==============================================================================
-// BufferPtr                                                                =
-//==============================================================================
-
-//==============================================================================
-BufferPtr::BufferPtr()
-{}
-
-//==============================================================================
-BufferPtr::~BufferPtr()
-{}
-
-//==============================================================================
-void BufferPtr::create(GrManager* manager,
-	GLenum target, const void* data, PtrSize size, GLenum flags)
-{
-	ANKI_ASSERT(!isCreated());
-
-	CommandBufferPtr cmdb;
-	cmdb.create(manager);
-
-	Base::create(cmdb.get().getManager());
-	get().setStateAtomically(GlObject::State::TO_BE_CREATED);
-
-	// Allocate temp memory for the data
-	Bool cleanup = false;
-	if(data)
-	{
-		void* newData = cmdb.get().getInternalAllocator().allocate(size);
-		memcpy(newData, data, size);
-		data = newData;
-		cleanup = true;
-	}
-
-	// Fire the command
-	cmdb.get().pushBackNewCommand<BufferCreateCommand>(
-		*this, target, data, size, flags, cleanup);
-	cmdb.flush();
-}
-
-//==============================================================================
-void BufferPtr::write(CommandBufferPtr& commands,
-	const void* data, PtrSize dataSize, PtrSize readOffset, PtrSize writeOffset,
-	PtrSize size)
-{
-	ANKI_ASSERT(isCreated());
-
-	void* newData = commands.get().getInternalAllocator().allocate(size);
-	memcpy(newData, static_cast<const U8*>(data) + readOffset, size);
-	data = newData;
-
-	commands.get().pushBackNewCommand<BufferWriteCommand>(
-		*this, data, dataSize, readOffset, writeOffset, size);
-}
-
-//==============================================================================
-void BufferPtr::bindShaderBufferInternal(CommandBufferPtr& commands,
-	I32 offset, I32 size, U32 bindingPoint)
-{
-	ANKI_ASSERT(isCreated());
-	commands.get().pushBackNewCommand<BindShaderBufferCommand>(
-		*this, offset, size, bindingPoint);
-}
-
-//==============================================================================
-void BufferPtr::bindVertexBuffer(
-	CommandBufferPtr& commands,
-	U32 elementSize,
-	GLenum type,
-	Bool normalized,
-	PtrSize stride,
-	PtrSize offset,
-	U32 attribLocation)
-{
-	ANKI_ASSERT(isCreated());
-	commands.get().pushBackNewCommand<BufferBindVertexCommand>(
-		*this, elementSize, type, normalized, stride, offset, attribLocation);
-}
-
-//==============================================================================
-void BufferPtr::bindIndexBuffer(CommandBufferPtr& commands)
-{
-	ANKI_ASSERT(isCreated());
-	commands.get().pushBackNewCommand<BindIndexBufferCommand>(*this);
-}
-
-//==============================================================================
-PtrSize BufferPtr::getSize() const
-{
-	return (get().serializeOnGetter()) ? 0 : get().getSize();
-}
-
-//==============================================================================
-GLenum BufferPtr::getTarget() const
-{
-	return (get().serializeOnGetter()) ? GL_NONE : get().getTarget();
-}
-
-//==============================================================================
-void* BufferPtr::getPersistentMappingAddress()
-{
-	return (get().serializeOnGetter())
-		? nullptr : get().getPersistentMappingAddress();
-}
-
-} // end namespace anki

+ 489 - 0
src/gr/gl/CommandBuffer.cpp

@@ -0,0 +1,489 @@
+// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include "anki/gr/CommandBuffer.h"
+#include "anki/gr/gl/CommandBufferImpl.h"
+#include "anki/gr/GrManager.h"
+#include "anki/gr/gl/GrManagerImpl.h"
+#include "anki/gr/gl/RenderingThread.h"
+#include "anki/gr/Pipeline.h"
+#include "anki/gr/gl/PipelineImpl.h"
+#include "anki/gr/Framebuffer.h"
+#include "anki/gr/gl/FramebufferImpl.h"
+#include "anki/gr/ResourceGroup.h"
+#include "anki/gr/gl/ResourceGroupImpl.h"
+#include "anki/gr/OcclusionQuery.h"
+#include "anki/gr/gl/OcclusionQueryImpl.h"
+#include "anki/gr/Texture.h"
+#include "anki/gr/gl/TextureImpl.h"
+#include "anki/gr/Buffer.h"
+#include "anki/gr/gl/BufferImpl.h"
+#include "anki/core/Counters.h"
+
+namespace anki {
+
+//==============================================================================
+CommandBuffer::CommandBuffer(GrManager* manager)
+	: GrObject(manager)
+{}
+
+//==============================================================================
+CommandBuffer::~CommandBuffer()
+{}
+
+//==============================================================================
+void CommandBuffer::create(CommandBufferInitHints hints)
+{
+	m_impl.reset(getAllocator().newInstance<CommandBufferImpl>(&getManager()));
+	m_impl->create(hints);
+}
+
+//==============================================================================
+void CommandBuffer::flush()
+{
+	getManager().getImplementation().
+		getRenderingThread().flushCommandBuffer(this);
+}
+
+//==============================================================================
+void CommandBuffer::finish()
+{
+	getManager().getImplementation().
+		getRenderingThread().finishCommandBuffer(this);
+}
+
+//==============================================================================
+class ViewportCommand final: public GlCommand
+{
+public:
+	Array<U16, 4> m_value;
+
+	ViewportCommand(U16 a, U16 b, U16 c, U16 d)
+	{
+		m_value = {{a, b, c, d}};
+	}
+
+	Error operator()(GlState& state)
+	{
+		if(state.m_viewport[0] != m_value[0]
+			|| state.m_viewport[1] != m_value[1]
+			|| state.m_viewport[2] != m_value[2]
+			|| state.m_viewport[3] != m_value[3])
+		{
+			glViewport(m_value[0], m_value[1], m_value[2], m_value[3]);
+
+			state.m_viewport = m_value;
+		}
+
+		return ErrorCode::NONE;
+	}
+};
+
+void CommandBuffer::setViewport(U16 minx, U16 miny, U16 maxx, U16 maxy)
+{
+	m_impl->pushBackNewCommand<ViewportCommand>(minx, miny, maxx, maxy);
+}
+
+//==============================================================================
+class BindPipelineCommand final: public GlCommand
+{
+public:
+	PipelinePtr m_ppline;
+
+	BindPipelineCommand(PipelinePtr& ppline)
+		: m_ppline(ppline)
+	{}
+
+	Error operator()(GlState& state)
+	{
+		PipelineImpl& impl = m_ppline->getImplementation();
+
+		auto name = impl.getGlName();
+		if(state.m_crntPpline != name)
+		{
+			impl.bind(state);
+			state.m_crntPpline = name;
+		}
+
+		return ErrorCode::NONE;
+	}
+};
+
+void CommandBuffer::bindPipeline(PipelinePtr ppline)
+{
+	m_impl->pushBackNewCommand<BindPipelineCommand>(ppline);
+}
+
+//==============================================================================
+class BindFramebufferCommand final: public GlCommand
+{
+public:
+	FramebufferPtr m_fb;
+
+	BindFramebufferCommand(FramebufferPtr fb)
+		: m_fb(fb)
+	{}
+
+	Error operator()(GlState& state)
+	{
+		m_fb->getImplementation().bind(state);
+		return ErrorCode::NONE;
+	}
+};
+
+void CommandBuffer::bindFramebuffer(FramebufferPtr fb)
+{
+	m_impl->pushBackNewCommand<BindFramebufferCommand>(fb);
+}
+
+//==============================================================================
+class BindResourcesCommand final: public GlCommand
+{
+public:
+	ResourceGroupPtr m_rc;
+
+	BindResourcesCommand(ResourceGroupPtr rc)
+		: m_rc(rc)
+	{}
+
+	Error operator()(GlState& state)
+	{
+		m_rc->getImplementation().bind(state);
+		return ErrorCode::NONE;
+	}
+};
+
+void CommandBuffer::bindResourceGroup(ResourceGroupPtr rc)
+{
+	m_impl->pushBackNewCommand<BindResourcesCommand>(rc);
+}
+
+//==============================================================================
+class DrawElementsCondCommand: public GlCommand
+{
+public:
+	DrawElementsIndirectInfo m_info;
+	OcclusionQueryPtr m_query;
+
+	DrawElementsCondCommand(
+		const DrawElementsIndirectInfo& info,
+		OcclusionQueryPtr query = OcclusionQueryPtr())
+		: m_info(info)
+		, m_query(query)
+	{}
+
+	Error operator()(GlState& state)
+	{
+		GLenum indicesType = 0;
+		switch(state.m_indexSize)
+		{
+		case 2:
+			indicesType = GL_UNSIGNED_SHORT;
+			break;
+		case 4:
+			indicesType = GL_UNSIGNED_INT;
+			break;
+		default:
+			ANKI_ASSERT(0);
+			break;
+		};
+
+		if(!m_query.isCreated() || !m_query->getImplementation().skipDrawcall())
+		{
+			glDrawElementsInstancedBaseVertexBaseInstance(
+				state.m_topology,
+				m_info.m_count,
+				indicesType,
+				(const void*)(PtrSize)(m_info.m_firstIndex * state.m_indexSize),
+				m_info.m_instanceCount,
+				m_info.m_baseVertex,
+				m_info.m_baseInstance);
+
+			ANKI_COUNTER_INC(GL_DRAWCALLS_COUNT, U64(1));
+		}
+
+		return ErrorCode::NONE;
+	}
+};
+
+void CommandBuffer::drawElements(U32 count, U32 instanceCount, U32 firstIndex,
+	U32 baseVertex, U32 baseInstance)
+{
+	DrawElementsIndirectInfo info(count, instanceCount, firstIndex,
+		baseVertex, baseInstance);
+
+	m_impl->pushBackNewCommand<DrawElementsCondCommand>(info);
+}
+
+//==============================================================================
+class DrawArraysCondCommand final: public GlCommand
+{
+public:
+	DrawArraysIndirectInfo m_info;
+	OcclusionQueryPtr m_query;
+
+	DrawArraysCondCommand(
+		const DrawArraysIndirectInfo& info,
+		OcclusionQueryPtr query = OcclusionQueryPtr())
+		: m_info(info)
+		, m_query(query)
+	{}
+
+	Error operator()(GlState& state)
+	{
+		if(!m_query.isCreated() || !m_query->getImplementation().skipDrawcall())
+		{
+			glDrawArraysInstancedBaseInstance(
+				state.m_topology,
+				m_info.m_first,
+				m_info.m_count,
+				m_info.m_instanceCount,
+				m_info.m_baseInstance);
+
+			ANKI_COUNTER_INC(GL_DRAWCALLS_COUNT, U64(1));
+		}
+
+		return ErrorCode::NONE;
+	}
+};
+
+void CommandBuffer::drawArrays(U32 count, U32 instanceCount, U32 first,
+	U32 baseInstance)
+{
+	DrawArraysIndirectInfo info(count, instanceCount, first, baseInstance);
+
+	m_impl->pushBackNewCommand<DrawArraysCondCommand>(info);
+}
+
+//==============================================================================
+void CommandBuffer::drawElementsConditional(OcclusionQueryPtr query, U32 count,
+	U32 instanceCount, U32 firstIndex, U32 baseVertex, U32 baseInstance)
+{
+	DrawElementsIndirectInfo info(count, instanceCount, firstIndex,
+		baseVertex, baseInstance);
+
+	m_impl->pushBackNewCommand<DrawElementsCondCommand>(info, query);
+}
+
+//==============================================================================
+void CommandBuffer::drawArraysConditional(OcclusionQueryPtr query, U32 count,
+	U32 instanceCount, U32 first, U32 baseInstance)
+{
+	DrawArraysIndirectInfo info(count, instanceCount, first, baseInstance);
+
+	m_impl->pushBackNewCommand<DrawArraysCondCommand>(info, query);
+}
+
+//==============================================================================
+class DispatchCommand final: public GlCommand
+{
+public:
+	Array<U32, 3> m_size;
+
+	DispatchCommand(U32 x, U32 y, U32 z)
+		: m_size({x, y, z})
+	{}
+
+	Error operator()(GlState&)
+	{
+		glDispatchCompute(m_size[0], m_size[1], m_size[2]);
+		return ErrorCode::NONE;
+	}
+};
+
+void CommandBuffer::dispatchCompute(
+	U32 groupCountX, U32 groupCountY, U32 groupCountZ)
+{
+	m_impl->pushBackNewCommand<DispatchCommand>(
+		groupCountX, groupCountY, groupCountZ);
+}
+
+//==============================================================================
+class UpdateUniformsCommand final: public GlCommand
+{
+public:
+	GLuint m_uboName;
+	U32 m_offset;
+	U16 m_range;
+
+	UpdateUniformsCommand(GLuint ubo, U32 offset, U16 range)
+		: m_uboName(ubo)
+		, m_offset(offset)
+		, m_range(range)
+	{}
+
+	Error operator()(GlState&)
+	{
+		const U binding = 0;
+		glBindBufferRange(
+			GL_UNIFORM_BUFFER, binding, m_uboName, m_offset, m_range);
+
+		return ErrorCode::NONE;
+	}
+};
+
+void CommandBuffer::updateDynamicUniforms(void* data, U32 originalSize)
+{
+	ANKI_ASSERT(data);
+	ANKI_ASSERT(originalSize > 0);
+	ANKI_ASSERT(originalSize <= 1024 * 4 && "Too high?");
+
+	// Will be used in a thread safe way
+	GlState& state =
+		getManager().getImplementation().getRenderingThread().getState();
+
+	const U uboSize = state.m_globalUboSize;
+	const U subUboSize = GlState::MAX_UBO_SIZE;
+
+	// Get offset in the contiguous buffer
+	U size = getAlignedRoundUp(state.m_uniBuffOffsetAlignment, originalSize);
+	U offset = state.m_globalUboCurrentOffset.fetchAdd(size);
+	offset = offset % uboSize;
+
+	while((offset % subUboSize) + size > subUboSize)
+	{
+		// Update area will fall between UBOs, need to start over
+		offset = state.m_globalUboCurrentOffset.fetchAdd(size);
+		offset = offset % uboSize;
+	}
+
+	ANKI_ASSERT(isAligned(state.m_uniBuffOffsetAlignment, offset));
+	ANKI_ASSERT(offset + size <= uboSize);
+
+	// Get actual UBO address to write
+	U uboIdx = offset / subUboSize;
+	U subUboOffset = offset % subUboSize;
+	ANKI_ASSERT(isAligned(state.m_uniBuffOffsetAlignment, subUboOffset));
+
+	U8* addressToWrite = state.m_globalUboAddresses[uboIdx] + subUboOffset;
+
+	// Write
+	memcpy(addressToWrite, data, originalSize);
+
+	// Push bind command
+	m_impl->pushBackNewCommand<UpdateUniformsCommand>(
+		state.m_globalUbos[uboIdx], subUboOffset, originalSize);
+}
+
+//==============================================================================
+class OqBeginCommand final: public GlCommand
+{
+public:
+	OcclusionQueryPtr m_handle;
+
+	OqBeginCommand(const OcclusionQueryPtr& handle)
+		: m_handle(handle)
+	{}
+
+	Error operator()(GlState&)
+	{
+		m_handle->getImplementation().begin();
+		return ErrorCode::NONE;
+	}
+};
+
+void CommandBuffer::beginOcclusionQuery(OcclusionQueryPtr query)
+{
+	m_impl->pushBackNewCommand<OqBeginCommand>(query);
+}
+
+//==============================================================================
+class OqEndCommand final: public GlCommand
+{
+public:
+	OcclusionQueryPtr m_handle;
+
+	OqEndCommand(const OcclusionQueryPtr& handle)
+		: m_handle(handle)
+	{}
+
+	Error operator()(GlState&)
+	{
+		m_handle->getImplementation().end();
+		return ErrorCode::NONE;
+	}
+};
+
+void CommandBuffer::endOcclusionQuery(OcclusionQueryPtr query)
+{
+	m_impl->pushBackNewCommand<OqEndCommand>(query);
+}
+
+//==============================================================================
+class TexUploadCommand final: public GlCommand
+{
+public:
+	TexturePtr m_handle;
+	U32 m_mipmap;
+	U32 m_slice;
+	PtrSize m_dataSize;
+	void* m_data;
+
+	TexUploadCommand(const TexturePtr& handle, U32 mipmap, U32 slice,
+		PtrSize dataSize, void* data)
+		: m_handle(handle)
+		, m_mipmap(mipmap)
+		, m_slice(slice)
+		, m_data(data)
+	{}
+
+	Error operator()(GlState&)
+	{
+		m_handle->getImplementation().write(
+			m_mipmap, m_slice, m_data, m_dataSize);
+		return ErrorCode::NONE;
+	}
+};
+
+void CommandBuffer::textureUpload(TexturePtr tex, U32 mipmap, U32 slice,
+	PtrSize dataSize, void*& data)
+{
+	ANKI_ASSERT(dataSize > 0);
+
+	// Allocate memory to write
+	data = m_impl->getInternalAllocator().allocate(dataSize);
+
+	m_impl->pushBackNewCommand<TexUploadCommand>(
+		tex, mipmap, slice, dataSize, data);
+}
+
+//==============================================================================
+class BuffWriteCommand final: public GlCommand
+{
+public:
+	BufferPtr m_handle;
+	PtrSize m_offset;
+	PtrSize m_range;
+	void* m_data;
+
+	BuffWriteCommand(const BufferPtr& handle, PtrSize offset, PtrSize range,
+		void* data)
+		: m_handle(handle)
+		, m_offset(offset)
+		, m_range(range)
+		, m_data(data)
+	{}
+
+	Error operator()(GlState&)
+	{
+		m_handle->getImplementation().write(m_data, m_offset, m_range);
+		return ErrorCode::NONE;
+	}
+};
+
+void CommandBuffer::writeBuffer(BufferPtr buff, PtrSize offset, PtrSize range,
+	void*& data)
+{
+	ANKI_ASSERT(range > 0);
+
+	// Allocate memory to write
+	data = m_impl->getInternalAllocator().allocate(range);
+
+	m_impl->pushBackNewCommand<BuffWriteCommand>(
+		buff, offset, range, data);
+}
+
+} // end namespace anki
+

+ 10 - 6
src/gr/gl/CommandBufferImpl.cpp

@@ -5,6 +5,8 @@
 
 #include "anki/gr/gl/CommandBufferImpl.h"
 #include "anki/gr/GrManager.h"
+#include "anki/gr/gl/GrManagerImpl.h"
+#include "anki/gr/gl/RenderingThread.h"
 #include "anki/gr/gl/Error.h"
 #include "anki/util/Logger.h"
 #include "anki/core/Counters.h"
@@ -15,12 +17,12 @@ namespace anki {
 //==============================================================================
 void CommandBufferImpl::create(const InitHints& hints)
 {
-	auto& pool = getManager().getAllocator().getMemoryPool();
+	auto& pool = m_manager->getAllocator().getMemoryPool();
 
 	m_alloc = CommandBufferAllocator<GlCommand*>(
 		pool.getAllocationCallback(),
 		pool.getAllocationCallbackUserData(),
-		hints.m_chunkSize, 
+		hints.m_chunkSize,
 		1.0,
 		hints.m_chunkSize);
 }
@@ -44,7 +46,7 @@ void CommandBufferImpl::destroy()
 		command = next;
 	}
 
-	ANKI_ASSERT(m_alloc.getMemoryPool().getUsersCount() == 1 
+	ANKI_ASSERT(m_alloc.getMemoryPool().getUsersCount() == 1
 		&& "Someone is holding a reference to the command buffer's allocator");
 
 	m_alloc = CommandBufferAllocator<U8>();
@@ -58,14 +60,16 @@ Error CommandBufferImpl::executeAllCommands()
 #if ANKI_DEBUG
 	m_executed = true;
 #endif
-	
+
 	Error err = ErrorCode::NONE;
+	GlState& state =
+		m_manager->getImplementation().getRenderingThread().getState();
 
 	GlCommand* command = m_firstCommand;
 
 	while(command != nullptr && !err)
 	{
-		err = (*command)(this);
+		err = (*command)(state);
 		ANKI_CHECK_GL_ERROR();
 
 		command = command->m_nextCommand;
@@ -80,7 +84,7 @@ CommandBufferImpl::InitHints CommandBufferImpl::computeInitHints() const
 	InitHints out;
 	out.m_chunkSize = m_alloc.getMemoryPool().getAllocatedSize() + 16;
 
-	ANKI_COUNTER_INC(GL_QUEUES_SIZE, 
+	ANKI_COUNTER_INC(GL_QUEUES_SIZE,
 		U64(m_alloc.getMemoryPool().getAllocatedSize()));
 
 	return out;

+ 0 - 658
src/gr/gl/CommandBufferPtr.cpp

@@ -1,658 +0,0 @@
-// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#include "anki/gr/CommandBufferPtr.h"
-#include "anki/gr/gl/CommandBufferImpl.h"
-#include "anki/gr/GrManager.h"
-#include "anki/gr/gl/GrManagerImpl.h"
-#include "anki/gr/gl/RenderingThread.h"
-#include "anki/gr/gl/FramebufferImpl.h"
-#include "anki/gr/TexturePtr.h"
-#include "anki/gr/gl/TextureImpl.h"
-#include "anki/gr/BufferPtr.h"
-#include "anki/gr/gl/BufferImpl.h"
-#include "anki/gr/OcclusionQueryPtr.h"
-#include "anki/gr/gl/OcclusionQueryImpl.h"
-#include "anki/core/Counters.h"
-#include <utility>
-
-namespace anki {
-
-//==============================================================================
-// Macros because we are bored to type
-#define ANKI_STATE_CMD_0(type_, glfunc_) \
-	class Command final: public GlCommand \
-	{ \
-	public: \
-		Command() = default \
-		Error operator()(CommandBufferImpl*) \
-		{ \
-			glfunc_(); \
-			return ErrorCode::NONE; \
-		} \
-	}; \
-	get().pushBackNewCommand<Command>(value_)
-
-#define ANKI_STATE_CMD_1(type_, glfunc_, value_) \
-	class Command: public GlCommand \
-	{ \
-	public: \
-		type_ m_value; \
-		Command(type_ v) \
-		:	m_value(v) \
-		{} \
-		Error operator()(CommandBufferImpl*) \
-		{ \
-			glfunc_(m_value); \
-			return ErrorCode::NONE; \
-		} \
-	}; \
-	get().pushBackNewCommand<Command>(value_)
-
-#define ANKI_STATE_CMD_2(type_, glfunc_, a_, b_) \
-	class Command: public GlCommand \
-	{ \
-	public: \
-		Array<type_, 2> m_value; \
-		Command(type_ a, type_ b) \
-		{ \
-			m_value = {{a, b}}; \
-		} \
-		Error operator()(CommandBufferImpl*) \
-		{ \
-			glfunc_(m_value[0], m_value[1]); \
-			return ErrorCode::NONE; \
-		} \
-	}; \
-	get().pushBackNewCommand<Command>(a_, b_)
-
-#define ANKI_STATE_CMD_3(type_, glfunc_, a_, b_, c_) \
-	class Command: public GlCommand \
-	{ \
-	public: \
-		Array<type_, 3> m_value; \
-		Command(type_ a, type_ b, type_ c) \
-		{ \
-			m_value = {{a, b, c}}; \
-		} \
-		Error operator()(CommandBufferImpl*) \
-		{ \
-			glfunc_(m_value[0], m_value[1], m_value[2]); \
-			return ErrorCode::NONE; \
-		} \
-	}; \
-	get().pushBackNewCommand<Command>(a_, b_, c_)
-
-#define ANKI_STATE_CMD_4(type_, glfunc_, a_, b_, c_, d_) \
-	class Command: public GlCommand \
-	{ \
-	public: \
-		Array<type_, 4> m_value; \
-		Command(type_ a, type_ b, type_ c, type_ d) \
-		{ \
-			m_value = {{a, b, c, d}}; \
-		} \
-		Error operator()(CommandBufferImpl*) \
-		{ \
-			glfunc_(m_value[0], m_value[1], m_value[2], m_value[3]); \
-			return ErrorCode::NONE; \
-		} \
-	}; \
-	get().pushBackNewCommand<Command>(a_, b_, c_, d_)
-
-#define ANKI_STATE_CMD_ENABLE(enum_, enable_) \
-	class Command: public GlCommand \
-	{ \
-	public: \
-		Bool8 m_enable; \
-		Command(Bool enable) \
-		:	m_enable(enable) \
-		{} \
-		Error operator()(CommandBufferImpl*) \
-		{ \
-			if(m_enable) \
-			{ \
-				glEnable(enum_); \
-			} \
-			else \
-			{ \
-				glDisable(enum_); \
-			} \
-			return ErrorCode::NONE; \
-		} \
-	}; \
-	get().pushBackNewCommand<Command>(enable_)
-
-//==============================================================================
-CommandBufferPtr::CommandBufferPtr()
-{}
-
-//==============================================================================
-CommandBufferPtr::~CommandBufferPtr()
-{}
-
-//==============================================================================
-void CommandBufferPtr::create(GrManager* manager, CommandBufferInitHints hints)
-{
-	ANKI_ASSERT(!isCreated());
-	ANKI_ASSERT(manager);
-
-	Base::create(*manager);
-	get().create(hints);
-}
-
-//==============================================================================
-CommandBufferInitHints CommandBufferPtr::computeInitHints() const
-{
-	return get().computeInitHints();
-}
-
-//==============================================================================
-void CommandBufferPtr::pushBackUserCommand(
-	UserCallback callback, void* data)
-{
-	class Command: public GlCommand
-	{
-	public:
-		UserCallback m_callback;
-		void* m_userData;
-
-		Command(UserCallback callback, void* userData)
-		:	m_callback(callback),
-			m_userData(userData)
-		{
-			ANKI_ASSERT(m_callback);
-		}
-
-		Error operator()(CommandBufferImpl* commands)
-		{
-			return (*m_callback)(m_userData);
-		}
-	};
-
-	get().pushBackNewCommand<Command>(callback, data);
-}
-
-//==============================================================================
-void CommandBufferPtr::pushBackOtherCommandBuffer(
-	CommandBufferPtr& commands)
-{
-	class Command: public GlCommand
-	{
-	public:
-		CommandBufferPtr m_commands;
-
-		Command(CommandBufferPtr& commands)
-		:	m_commands(commands)
-		{}
-
-		Error operator()(CommandBufferImpl*)
-		{
-			return m_commands.get().executeAllCommands();
-		}
-	};
-
-	commands.get().makeImmutable();
-	get().pushBackNewCommand<Command>(commands);
-}
-
-//==============================================================================
-void CommandBufferPtr::flush()
-{
-	get().getManager().getImplementation().
-		getRenderingThread().flushCommandBuffer(*this);
-}
-
-//==============================================================================
-void CommandBufferPtr::finish()
-{
-	get().getManager().getImplementation().getRenderingThread().
-		finishCommandBuffer(*this);
-}
-
-//==============================================================================
-void CommandBufferPtr::setViewport(U16 minx, U16 miny, U16 maxx, U16 maxy)
-{
-	class Command: public GlCommand
-	{
-	public:
-		Array<U16, 4> m_value;
-
-		Command(U16 a, U16 b, U16 c, U16 d)
-		{
-			m_value = {{a, b, c, d}};
-		}
-
-		Error operator()(CommandBufferImpl* commands)
-		{
-			GlState& state = commands->getManager().getImplementation().
-				getRenderingThread().getState();
-
-			if(state.m_viewport[0] != m_value[0]
-				|| state.m_viewport[1] != m_value[1]
-				|| state.m_viewport[2] != m_value[2]
-				|| state.m_viewport[3] != m_value[3])
-			{
-				glViewport(m_value[0], m_value[1], m_value[2], m_value[3]);
-
-				state.m_viewport = m_value;
-			}
-
-			return ErrorCode::NONE;
-		}
-	};
-
-	get().pushBackNewCommand<Command>(minx, miny, maxx, maxy);
-}
-
-//==============================================================================
-class BindTexturesCommand: public GlCommand
-{
-public:
-	static const U MAX_BIND_TEXTURES = 8;
-
-	Array<TexturePtr, MAX_BIND_TEXTURES> m_texes;
-	U32 m_texCount;
-	U32 m_first;
-
-	BindTexturesCommand(
-		TexturePtr textures[], U count, U32 first)
-	:	m_first(first)
-	{
-		m_texCount = count;
-		TexturePtr* t = textures;
-		while(count-- != 0)
-		{
-			m_texes[count] = *t;
-			++t;
-		}
-	}
-
-	Error operator()(CommandBufferImpl* commands)
-	{
-		Array<GLuint, MAX_BIND_TEXTURES> names;
-
-		U count = m_texCount;
-		U i = 0;
-		while(count-- != 0)
-		{
-			names[i++] = m_texes[count].get().getGlName();
-		}
-
-		glBindTextures(m_first, m_texCount, &names[0]);
-
-		return ErrorCode::NONE;
-	}
-};
-
-void CommandBufferPtr::bindTextures(U32 first,
-	TexturePtr textures[], U32 count)
-{
-	ANKI_ASSERT(count > 0);
-
-	get().pushBackNewCommand<BindTexturesCommand>(&textures[0], count, first);
-}
-
-//==============================================================================
-class DrawElementsCondCommand: public GlCommand
-{
-public:
-	GLenum m_mode;
-	U8 m_indexSize;
-	GlDrawElementsIndirectInfo m_info;
-	OcclusionQueryPtr m_query;
-
-	DrawElementsCondCommand(
-		GLenum mode,
-		U8 indexSize,
-		GlDrawElementsIndirectInfo& info,
-		OcclusionQueryPtr query = OcclusionQueryPtr())
-	:	m_mode(mode),
-		m_indexSize(indexSize),
-		m_info(info),
-		m_query(query)
-	{}
-
-	Error operator()(CommandBufferImpl*)
-	{
-		ANKI_ASSERT(m_indexSize != 0);
-
-		GLenum indicesType = 0;
-		switch(m_indexSize)
-		{
-		case 1:
-			indicesType = GL_UNSIGNED_BYTE;
-			break;
-		case 2:
-			indicesType = GL_UNSIGNED_SHORT;
-			break;
-		case 4:
-			indicesType = GL_UNSIGNED_INT;
-			break;
-		default:
-			ANKI_ASSERT(0);
-			break;
-		};
-
-		if(!m_query.isCreated() || !m_query.get().skipDrawcall())
-		{
-			glDrawElementsInstancedBaseVertexBaseInstance(
-				m_mode,
-				m_info.m_count,
-				indicesType,
-				(const void*)(PtrSize)(m_info.m_firstIndex * m_indexSize),
-				m_info.m_instanceCount,
-				m_info.m_baseVertex,
-				m_info.m_baseInstance);
-
-			ANKI_COUNTER_INC(GL_DRAWCALLS_COUNT, (U64)1);
-		}
-
-		return ErrorCode::NONE;
-	}
-};
-
-void CommandBufferPtr::drawElements(
-	GLenum mode, U8 indexSize, U32 count, U32 instanceCount, U32 firstIndex,
-	U32 baseVertex, U32 baseInstance)
-{
-	GlDrawElementsIndirectInfo info(count, instanceCount, firstIndex,
-		baseVertex, baseInstance);
-
-	get().pushBackNewCommand<DrawElementsCondCommand>(mode, indexSize, info);
-}
-
-//==============================================================================
-class DrawArraysCondCommand: public GlCommand
-{
-public:
-	GLenum m_mode;
-	GlDrawArraysIndirectInfo m_info;
-	OcclusionQueryPtr m_query;
-
-	DrawArraysCondCommand(
-		GLenum mode,
-		GlDrawArraysIndirectInfo& info,
-		OcclusionQueryPtr query = OcclusionQueryPtr())
-	:	m_mode(mode),
-		m_info(info),
-		m_query(query)
-	{}
-
-	Error operator()(CommandBufferImpl*)
-	{
-		if(!m_query.isCreated() || !m_query.get().skipDrawcall())
-		{
-			glDrawArraysInstancedBaseInstance(
-				m_mode,
-				m_info.m_first,
-				m_info.m_count,
-				m_info.m_instanceCount,
-				m_info.m_baseInstance);
-
-			ANKI_COUNTER_INC(GL_DRAWCALLS_COUNT, (U64)1);
-		}
-
-		return ErrorCode::NONE;
-	}
-};
-
-void CommandBufferPtr::drawArrays(
-	GLenum mode, U32 count, U32 instanceCount, U32 first, U32 baseInstance)
-{
-	GlDrawArraysIndirectInfo info(count, instanceCount, first, baseInstance);
-
-	get().pushBackNewCommand<DrawArraysCondCommand>(mode, info);
-}
-
-//==============================================================================
-void CommandBufferPtr::drawElementsConditional(
-	OcclusionQueryPtr& query,
-	GLenum mode, U8 indexSize, U32 count, U32 instanceCount, U32 firstIndex,
-	U32 baseVertex, U32 baseInstance)
-{
-	GlDrawElementsIndirectInfo info(count, instanceCount, firstIndex,
-		baseVertex, baseInstance);
-
-	get().pushBackNewCommand<DrawElementsCondCommand>(mode, indexSize, info, query);
-}
-
-//==============================================================================
-void CommandBufferPtr::drawArraysConditional(
-	OcclusionQueryPtr& query,
-	GLenum mode, U32 count, U32 instanceCount, U32 first, U32 baseInstance)
-{
-	GlDrawArraysIndirectInfo info(count, instanceCount, first, baseInstance);
-
-	get().pushBackNewCommand<DrawArraysCondCommand>(mode, info, query);
-}
-
-//==============================================================================
-class CopyBuffTex: public GlCommand
-{
-public:
-	TexturePtr m_tex;
-	BufferPtr m_buff;
-
-	CopyBuffTex(TexturePtr& from, BufferPtr& to)
-	:	m_tex(from),
-		m_buff(to)
-	{}
-
-	Error operator()(CommandBufferImpl* cmd)
-	{
-		TextureImpl& tex = m_tex.get();
-		BufferImpl& buff = m_buff.get();
-
-		// Bind
-		GLuint copyFbo = cmd->getManager().getImplementation().
-			getRenderingThread().getCopyFbo();
-		glBindFramebuffer(GL_FRAMEBUFFER, copyFbo);
-
-		// Attach texture
-		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-			tex.getTarget(), tex.getGlName(), 0);
-
-		// Set draw buffers
-		GLuint drawBuff = GL_COLOR_ATTACHMENT0;
-		glDrawBuffers(1, &drawBuff);
-
-		// Bind buffer
-		ANKI_ASSERT(m_buff.getTarget() == GL_PIXEL_PACK_BUFFER);
-		buff.bind();
-
-		// Read pixels
-		GLuint format = GL_NONE, type = GL_NONE;
-		if(tex.getInternalFormat() == GL_RG32UI)
-		{
-			format = GL_RG_INTEGER;
-			type = GL_UNSIGNED_INT;
-		}
-		else if(tex.getInternalFormat() == GL_RG32F)
-		{
-			format = GL_RG;
-			type = GL_FLOAT;
-		}
-		else
-		{
-			ANKI_ASSERT(0 && "Not implemented");
-		}
-
-		glReadPixels(0, 0, tex.getWidth(), tex.getHeight(),
-			format, type, nullptr);
-
-		// End
-		buff.unbind();
-		glBindFramebuffer(GL_FRAMEBUFFER, 0);
-
-		return ErrorCode::NONE;
-	}
-};
-
-void CommandBufferPtr::copyTextureToBuffer(
-	TexturePtr& from, BufferPtr& to)
-{
-	get().pushBackNewCommand<CopyBuffTex>(from, to);
-}
-
-//==============================================================================
-class DispatchCommand: public GlCommand
-{
-public:
-	Array<U32, 3> m_size;
-
-	DispatchCommand(U32 x, U32 y, U32 z)
-	:	m_size({x, y, z})
-	{}
-
-	Error operator()(CommandBufferImpl*)
-	{
-		glDispatchCompute(m_size[0], m_size[1], m_size[2]);
-		return ErrorCode::NONE;
-	}
-};
-
-void CommandBufferPtr::dispatchCompute(
-	U32 groupCountX, U32 groupCountY, U32 groupCountZ)
-{
-	get().pushBackNewCommand<DispatchCommand>(
-		groupCountX, groupCountY, groupCountZ);
-}
-
-//==============================================================================
-class UpdateUniformsCommand final: public GlCommand
-{
-public:
-	GLuint m_uboName;
-	U32 m_offset;
-	U16 m_range;
-
-	UpdateUniformsCommand(GLuint ubo, U32 offset, U16 range)
-	:	m_uboName(ubo),
-		m_offset(offset),
-		m_range(range)
-	{}
-
-	Error operator()(CommandBufferImpl*)
-	{
-		const U binding = 0;
-		glBindBufferRange(
-			GL_UNIFORM_BUFFER, binding, m_uboName, m_offset, m_range);
-
-		return ErrorCode::NONE;
-	}
-};
-
-void CommandBufferPtr::updateDynamicUniforms(void* data, U32 originalSize)
-{
-	ANKI_ASSERT(data);
-	ANKI_ASSERT(originalSize > 0);
-	ANKI_ASSERT(originalSize <= 1024 * 4 && "Too high?");
-
-	GlState& state =
-		get().getManager().getImplementation().getRenderingThread().getState();
-
-	const U uboSize = state.m_globalUboSize;
-	const U subUboSize = GlState::MAX_UBO_SIZE;
-
-	// Get offset in the contiguous buffer
-	U size = getAlignedRoundUp(state.m_uniBuffOffsetAlignment, originalSize);
-	U offset = state.m_globalUboCurrentOffset.fetchAdd(size);
-	offset = offset % uboSize;
-
-	while((offset % subUboSize) + size > subUboSize)
-	{
-		// Update area will fall between UBOs, need to start over
-		offset = state.m_globalUboCurrentOffset.fetchAdd(size);
-		offset = offset % uboSize;
-	}
-
-	ANKI_ASSERT(isAligned(state.m_uniBuffOffsetAlignment, offset));
-	ANKI_ASSERT(offset + size <= uboSize);
-
-	// Get actual UBO address to write
-	U uboIdx = offset / subUboSize;
-	U subUboOffset = offset % subUboSize;
-	ANKI_ASSERT(isAligned(state.m_uniBuffOffsetAlignment, subUboOffset));
-
-	U8* addressToWrite = state.m_globalUboAddresses[uboIdx] + subUboOffset;
-
-	// Write
-	memcpy(addressToWrite, data, originalSize);
-
-	// Push bind command
-	get().pushBackNewCommand<UpdateUniformsCommand>(
-		state.m_globalUbos[uboIdx], subUboOffset, originalSize);
-}
-
-//==============================================================================
-class BindVertexCommand final: public GlCommand
-{
-public:
-	BufferPtr m_buff;
-	PtrSize m_offset;
-	U32 m_binding;
-
-	BindVertexCommand(U32 bindingPoint, BufferPtr buff, PtrSize offset)
-		: m_buff(buff)
-		, m_offset(offset)
-		, m_binding(bindingPoint)
-	{}
-
-	Error operator()(CommandBufferImpl* cmdb)
-	{
-		GlState& state = cmdb->getManager().getImplementation().
-			getRenderingThread().getState();
-		ANKI_ASSERT(state.m_vertexBindingStrides[m_binding] > 0);
-
-		glBindVertexBuffer(m_binding, m_buff.get().getGlName(),
-			m_offset, state.m_vertexBindingStrides[m_binding]);
-
-		return ErrorCode::NONE;
-	}
-};
-
-void CommandBufferPtr::bindVertexBuffer(
-	U32 bindingPoint, BufferPtr buff, PtrSize offset)
-{
-	get().pushBackNewCommand<BindVertexCommand>(bindingPoint, buff, offset);
-}
-
-//==============================================================================
-class BindIndexCommand final: public GlCommand
-{
-public:
-	BufferPtr m_buff;
-	U8 m_indexSize;
-
-	BindIndexCommand(BufferPtr buff, U32 indexSize)
-		: m_buff(buff)
-		, m_indexSize(indexSize)
-	{}
-
-	Error operator()(CommandBufferImpl* cmdb)
-	{
-		// Update the state...
-		ANKI_ASSERT(m_indexSize == 2 || m_indexSize == 4);
-		GLenum type = m_indexSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
-
-		GlState& state = cmdb->getManager().getImplementation().
-			getRenderingThread().getState();
-
-		state.m_indexSize = type;
-
-		// ...and bind
-		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buff.get().getGlName());
-
-		return ErrorCode::NONE;
-	}
-};
-
-void CommandBufferPtr::bindIndexBuffer(BufferPtr buff, U32 indexSize)
-{
-	get().pushBackNewCommand<BindIndexCommand>(buff, indexSize);
-}
-
-} // end namespace anki

+ 60 - 0
src/gr/gl/Framebuffer.cpp

@@ -0,0 +1,60 @@
+// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include "anki/gr/Framebuffer.h"
+#include "anki/gr/gl/FramebufferImpl.h"
+#include "anki/gr/gl/CommandBufferImpl.h"
+
+namespace anki {
+
+//==============================================================================
+Framebuffer::Framebuffer(GrManager* manager)
+	: GrObject(manager)
+{}
+
+//==============================================================================
+Framebuffer::~Framebuffer()
+{}
+
+//==============================================================================
+class CreateFramebufferCommand final: public GlCommand
+{
+public:
+	FramebufferPtr m_fb;
+	FramebufferInitializer m_init;
+
+	CreateFramebufferCommand(Framebuffer* handle,
+		const FramebufferInitializer& init)
+		: m_fb(handle)
+		, m_init(init)
+	{}
+
+	Error operator()(GlState&)
+	{
+		FramebufferImpl& impl = m_fb->getImplementation();
+		Error err = impl.create(m_init);
+
+		GlObject::State oldState = impl.setStateAtomically(
+			(err) ? GlObject::State::ERROR : GlObject::State::CREATED);
+		ANKI_ASSERT(oldState == GlObject::State::TO_BE_CREATED);
+		(void)oldState;
+
+		return err;
+	}
+};
+
+void Framebuffer::create(const FramebufferInitializer& init)
+{
+	m_impl.reset(getAllocator().newInstance<FramebufferImpl>(&getManager()));
+
+	CommandBufferPtr cmdb = getManager().newInstance<CommandBuffer>();
+
+	cmdb->getImplementation().pushBackNewCommand<CreateFramebufferCommand>(
+		this, init);
+	cmdb->flush();
+}
+
+} // end namespace anki
+

+ 29 - 53
src/gr/gl/FramebufferImpl.cpp

@@ -4,9 +4,10 @@
 // http://www.anki3d.org/LICENSE
 
 #include "anki/gr/gl/FramebufferImpl.h"
-#include "anki/gr/FramebufferCommon.h"
+#include "anki/gr/Texture.h"
 #include "anki/gr/gl/TextureImpl.h"
 #include "anki/gr/gl/GlState.h"
+#include "anki/gr/GrManager.h"
 #include "anki/gr/gl/GrManagerImpl.h"
 #include "anki/gr/gl/RenderingThread.h"
 #include "anki/util/Logger.h"
@@ -14,12 +15,13 @@
 namespace anki {
 
 //==============================================================================
-Error FramebufferImpl::create(Initializer& init)
+Error FramebufferImpl::create(const FramebufferInitializer& init)
 {
-	*static_cast<FramebufferInitializer*>(this) = init;
+	ANKI_ASSERT(!isCreated());
+	m_in = init;
 
-	if(m_colorAttachmentsCount == 0
-		&& !m_depthStencilAttachment.m_texture.isCreated())
+	if(m_in.m_colorAttachmentsCount == 0
+		&& !m_in.m_depthStencilAttachment.m_texture.isCreated())
 	{
 		m_bindDefault = true;
 		return ErrorCode::NONE;
@@ -33,12 +35,13 @@ Error FramebufferImpl::create(Initializer& init)
 	glBindFramebuffer(target, m_glName);
 
 	// Attach color
-	for(U i = 0; i < m_colorAttachmentsCount; i++)
+	for(U i = 0; i < m_in.m_colorAttachmentsCount; i++)
 	{
-		const Attachment& att = m_colorAttachments[i];
+		const Attachment& att = m_in.m_colorAttachments[i];
 		const GLenum binding = GL_COLOR_ATTACHMENT0 + i;
 
-		attachTextureInternal(binding, att.m_texture.get(), att.m_layer);
+		attachTextureInternal(
+			binding, att.m_texture->getImplementation(), att.m_layer);
 
 		m_drawBuffers[i] = binding;
 
@@ -49,12 +52,13 @@ Error FramebufferImpl::create(Initializer& init)
 	}
 
 	// Attach depth/stencil
-	if(m_depthStencilAttachment.m_texture.isCreated())
+	if(m_in.m_depthStencilAttachment.m_texture.isCreated())
 	{
-		const Attachment& att = m_depthStencilAttachment;
+		const Attachment& att = m_in.m_depthStencilAttachment;
 		const GLenum binding = GL_DEPTH_ATTACHMENT;
 
-		attachTextureInternal(binding, att.m_texture.get(), att.m_layer);
+		attachTextureInternal(
+			binding, att.m_texture->getImplementation(), att.m_layer);
 
 		if(att.m_loadOperation == AttachmentLoadOperation::DONT_CARE)
 		{
@@ -67,7 +71,6 @@ Error FramebufferImpl::create(Initializer& init)
 	if(status != GL_FRAMEBUFFER_COMPLETE)
 	{
 		ANKI_LOGE("FBO is incomplete: 0x%x", status);
-		destroy();
 		return ErrorCode::FUNCTION_FAILED;
 	}
 
@@ -75,21 +78,12 @@ Error FramebufferImpl::create(Initializer& init)
 	return ErrorCode::NONE;
 }
 
-//==============================================================================
-void FramebufferImpl::destroy()
-{
-	if(m_glName != 0)
-	{
-		destroyDeferred(glDeleteFramebuffers);
-	}
-}
-
 //==============================================================================
 void FramebufferImpl::attachTextureInternal(
 	GLenum attachment, const TextureImpl& tex, const U32 layer)
 {
 	const GLenum target = GL_FRAMEBUFFER;
-	switch(tex.getTarget())
+	switch(tex.m_target)
 	{
 	case GL_TEXTURE_2D:
 #if ANKI_GL == ANKI_GL_DESKTOP
@@ -97,18 +91,17 @@ void FramebufferImpl::attachTextureInternal(
 #endif
 		ANKI_ASSERT(layer == 0);
 		glFramebufferTexture2D(target, attachment,
-			tex.getTarget(), tex.getGlName(), 0);
+			tex.m_target, tex.getGlName(), 0);
 		break;
 	case GL_TEXTURE_CUBE_MAP:
 		ANKI_ASSERT(layer < 6);
 		glFramebufferTexture2D(target, attachment,
-			GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer, tex.getGlName(), 0);
+			GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer, tex.m_target, 0);
 		break;
 	case GL_TEXTURE_2D_ARRAY:
 	case GL_TEXTURE_3D:
-		ANKI_ASSERT((GLuint)layer < tex.getDepth());
-		glFramebufferTextureLayer(target, attachment,
-			tex.getGlName(), 0, layer);
+		ANKI_ASSERT((GLuint)layer < tex.m_depth);
+		glFramebufferTextureLayer(target, attachment, tex.m_target, 0, layer);
 		break;
 	default:
 		ANKI_ASSERT(0);
@@ -117,7 +110,7 @@ void FramebufferImpl::attachTextureInternal(
 }
 
 //==============================================================================
-void FramebufferImpl::bind()
+void FramebufferImpl::bind(const GlState& state)
 {
 	if(m_bindDefault)
 	{
@@ -129,9 +122,9 @@ void FramebufferImpl::bind()
 		glBindFramebuffer(GL_FRAMEBUFFER, m_glName);
 
 		// Set the draw buffers
-		if(m_colorAttachmentsCount)
+		if(m_in.m_colorAttachmentsCount)
 		{
-			glDrawBuffers(m_colorAttachmentsCount, &m_drawBuffers[0]);
+			glDrawBuffers(m_in.m_colorAttachmentsCount, &m_drawBuffers[0]);
 		}
 
 		// Invalidate
@@ -142,11 +135,9 @@ void FramebufferImpl::bind()
 		}
 
 		// Clear buffers
-		GlState& state =
-			getManager().getImplementation().getRenderingThread().getState();
-		for(U i = 0; i < m_colorAttachmentsCount; i++)
+		for(U i = 0; i < m_in.m_colorAttachmentsCount; i++)
 		{
-			const Attachment& att = m_colorAttachments[i];
+			const Attachment& att = m_in.m_colorAttachments[i];
 
 			if(att.m_loadOperation == AttachmentLoadOperation::CLEAR)
 			{
@@ -174,8 +165,8 @@ void FramebufferImpl::bind()
 			}
 		}
 
-		if(m_depthStencilAttachment.m_texture.isCreated()
-			&& m_depthStencilAttachment.m_loadOperation
+		if(m_in.m_depthStencilAttachment.m_texture.isCreated()
+			&& m_in.m_depthStencilAttachment.m_loadOperation
 				== AttachmentLoadOperation::CLEAR)
 		{
 			// Enable write mask in case a pipeline changed it (else no
@@ -185,8 +176,8 @@ void FramebufferImpl::bind()
 				glDepthMask(true);
 			}
 
-			glClearBufferfv(GL_DEPTH, 0,
-				&m_depthStencilAttachment.m_clearValue.m_depthStencil.m_depth);
+			glClearBufferfv(GL_DEPTH, 0, &m_in.m_depthStencilAttachment
+				.m_clearValue.m_depthStencil.m_depth);
 
 			if(state.m_depthWriteMask == false)
 			{
@@ -196,21 +187,6 @@ void FramebufferImpl::bind()
 	}
 }
 
-//==============================================================================
-void FramebufferImpl::blit(const FramebufferImpl& b,
-	const Array<U32, 4>& sourceRect,
-	const Array<U32, 4>& destRect,
-	GLbitfield attachmentMask, Bool linear)
-{
-	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_glName);
-	glBindFramebuffer(GL_READ_FRAMEBUFFER, b.m_glName);
-	glBlitFramebuffer(
-		sourceRect[0], sourceRect[1], sourceRect[2], sourceRect[3],
-		destRect[0], destRect[1], destRect[2], destRect[3],
-		attachmentMask,
-		linear ? GL_LINEAR : GL_NEAREST);
-}
-
 } // end namespace anki
 
 

+ 0 - 140
src/gr/gl/FramebufferPtr.cpp

@@ -1,140 +0,0 @@
-// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#include "anki/gr/FramebufferPtr.h"
-#include "anki/gr/gl/FramebufferImpl.h"
-#include "anki/gr/gl/TextureImpl.h"
-#include "anki/gr/gl/CommandBufferImpl.h"
-#include "anki/gr/CommandBufferPtr.h"
-
-namespace anki {
-
-//==============================================================================
-// Commands                                                                    =
-//==============================================================================
-
-/// Create framebuffer command.
-class CreateFramebufferCommand: public GlCommand
-{
-public:
-	FramebufferPtr m_fb;
-	FramebufferPtr::Initializer m_init;
-
-	CreateFramebufferCommand(const FramebufferPtr& handle,
-		const FramebufferPtr::Initializer& init)
-	:	m_fb(handle),
-		m_init(init)
-	{}
-
-	Error operator()(CommandBufferImpl*)
-	{
-		Error err = m_fb.get().create(m_init);
-
-		GlObject::State oldState = m_fb.get().setStateAtomically(
-			(err) ? GlObject::State::ERROR : GlObject::State::CREATED);
-		ANKI_ASSERT(oldState == GlObject::State::TO_BE_CREATED);
-		(void)oldState;
-
-		return err;
-	}
-};
-
-/// Bind framebuffer command.
-class BindFramebufferCommand: public GlCommand
-{
-public:
-	FramebufferPtr m_fb;
-
-	BindFramebufferCommand(FramebufferPtr& fb)
-	:	m_fb(fb)
-	{}
-
-	Error operator()(CommandBufferImpl*)
-	{
-		m_fb.get().bind();
-		return ErrorCode::NONE;
-	}
-};
-
-/// Blit.
-class BlitFramebufferCommand: public GlCommand
-{
-public:
-	FramebufferPtr m_fbDest;
-	FramebufferPtr m_fbSrc;
-	Array<U32, 4> m_sourceRect;
-	Array<U32, 4> m_destRect;
-	GLbitfield m_attachmentMask;
-	Bool8 m_linear;
-
-	BlitFramebufferCommand(FramebufferPtr& fbDest,
-		const FramebufferPtr& fbSrc,
-		const Array<U32, 4>& sourceRect,
-		const Array<U32, 4>& destRect,
-		GLbitfield attachmentMask,
-		Bool8 linear)
-	:	m_fbDest(fbDest),
-		m_fbSrc(fbSrc),
-		m_sourceRect(sourceRect),
-		m_destRect(destRect),
-		m_attachmentMask(attachmentMask),
-		m_linear(linear)
-	{}
-
-	Error operator()(CommandBufferImpl*)
-	{
-		m_fbDest.get().blit(m_fbSrc.get(), m_sourceRect, m_destRect,
-			m_attachmentMask, m_linear);
-
-		return ErrorCode::NONE;
-	}
-};
-
-//==============================================================================
-// FramebufferPtr                                                           =
-//==============================================================================
-
-//==============================================================================
-FramebufferPtr::FramebufferPtr()
-{}
-
-//==============================================================================
-FramebufferPtr::~FramebufferPtr()
-{}
-
-//==============================================================================
-void FramebufferPtr::create(GrManager* manager, Initializer& init)
-{
-	CommandBufferPtr cmdb;
-	cmdb.create(manager);
-
-	Base::create(cmdb.get().getManager());
-
-	get().setStateAtomically(GlObject::State::TO_BE_CREATED);
-
-	cmdb.get().pushBackNewCommand<CreateFramebufferCommand>(*this, init);
-	cmdb.flush();
-}
-
-//==============================================================================
-void FramebufferPtr::bind(CommandBufferPtr& cmdb)
-{
-	cmdb.get().pushBackNewCommand<BindFramebufferCommand>(*this);
-}
-
-//==============================================================================
-void FramebufferPtr::blit(CommandBufferPtr& cmdb,
-	const FramebufferPtr& b,
-	const Array<U32, 4>& sourceRect,
-	const Array<U32, 4>& destRect,
-	GLbitfield attachmentMask,
-	Bool linear)
-{
-	cmdb.get().pushBackNewCommand<BlitFramebufferCommand>(
-		*this, b, sourceRect, destRect, attachmentMask, linear);
-}
-
-} // end namespace anki
-

+ 28 - 12
src/gr/gl/GlObject.cpp

@@ -7,13 +7,20 @@
 #include "anki/gr/GrManager.h"
 #include "anki/gr/gl/GrManagerImpl.h"
 #include "anki/gr/gl/RenderingThread.h"
-#include "anki/gr/CommandBufferPtr.h"
+#include "anki/gr/CommandBuffer.h"
 #include "anki/gr/gl/CommandBufferImpl.h"
 
 namespace anki {
 
 //==============================================================================
-Error GlObject::serializeOnGetter() const
+GlObject::GlObject(GrManager* manager)
+	: m_manager(manager)
+	, m_glName(0)
+	, m_state(I32(State::TO_BE_CREATED))
+{}
+
+//==============================================================================
+Error GlObject::serializeRenderingThread()
 {
 	Error err = ErrorCode::NONE;
 	State state = State(m_state.load());
@@ -21,8 +28,8 @@ Error GlObject::serializeOnGetter() const
 
 	if(state == State::TO_BE_CREATED)
 	{
-		RenderingThread& thread = const_cast<RenderingThread&>(
-			getManager().getImplementation().getRenderingThread());
+		RenderingThread& thread =
+			m_manager->getImplementation().getRenderingThread();
 		thread.syncClientServer();
 
 		state = State(m_state.load());
@@ -46,11 +53,11 @@ public:
 	GLuint m_glName;
 
 	DeleteGlObjectCommand(GlObject::GlDeleteFunction callback, GLuint name)
-	:	m_callback(callback),
-		m_glName(name)
+		: m_callback(callback)
+		, m_glName(name)
 	{}
 
-	Error operator()(CommandBufferImpl*)
+	Error operator()(GlState&)
 	{
 		m_callback(1, &m_glName);
 		return ErrorCode::NONE;
@@ -59,6 +66,11 @@ public:
 
 void GlObject::destroyDeferred(GlDeleteFunction deleteCallback)
 {
+	if(m_glName == 0)
+	{
+		return;
+	}
+
 	GrManager& manager = getManager();
 	RenderingThread& thread = manager.getImplementation().getRenderingThread();
 
@@ -66,10 +78,10 @@ void GlObject::destroyDeferred(GlDeleteFunction deleteCallback)
 	{
 		CommandBufferPtr commands;
 
-		commands.create(&manager);
-		commands.get().template pushBackNewCommand<DeleteGlObjectCommand>(
+		commands = manager.newInstance<CommandBuffer>();
+		commands->getImplementation().pushBackNewCommand<DeleteGlObjectCommand>(
 			deleteCallback, m_glName);
-		commands.flush();
+		commands->flush();
 	}
 	else
 	{
@@ -79,6 +91,10 @@ void GlObject::destroyDeferred(GlDeleteFunction deleteCallback)
 	m_glName = 0;
 }
 
-} // end namespace anki
-
+//==============================================================================
+GrAllocator<U8> GlObject::getAllocator() const
+{
+	return m_manager->getAllocator();
+}
 
+} // end namespace anki

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

@@ -47,7 +47,7 @@ __stdcall
 #endif
 void oglMessagesCallback(GLenum source,
 	GLenum type, GLuint id, GLenum severity, GLsizei length,
-	const char* message, GLvoid* userParam)
+	const char* message, const GLvoid* userParam)
 {
 	using namespace anki;
 
@@ -99,16 +99,6 @@ void GlState::init()
 		m_gpu = GpuVendor::NVIDIA;
 	}
 
-	// Max tex units
-	{
-		GLint tmp;
-		glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &tmp);
-		m_texUnitsCount = (U32)tmp;
-		ANKI_ASSERT(m_texUnitsCount <= m_texUnits.size());
-
-		memset(&m_texUnits[0], 0, sizeof(m_texUnits));
-	}
-
 	// Enable debug messages
 #if ANKI_GL == ANKI_GL_DESKTOP
 	if(m_registerMessages)

+ 7 - 28
src/gr/gl/GrManager.cpp

@@ -11,6 +11,12 @@
 
 namespace anki {
 
+//==============================================================================
+GrManager::~GrManager()
+{
+	m_cacheDir.destroy(m_alloc);
+}
+
 //==============================================================================
 Error GrManager::create(Initializer& init)
 {
@@ -18,43 +24,16 @@ Error GrManager::create(Initializer& init)
 		init.m_allocCallback, init.m_allocCallbackUserData);
 
 	m_cacheDir.create(m_alloc, init.m_cacheDirectory);
-	m_impl = m_alloc.newInstance<GrManagerImpl>(this);
+	m_impl.reset(m_alloc.newInstance<GrManagerImpl>(this));
 	Error err = m_impl->create(init);
 
 	return err;
 }
 
-//==============================================================================
-void GrManager::destroy()
-{
-	m_cacheDir.destroy(m_alloc);
-
-	if(m_impl)
-	{
-		m_alloc.deleteInstance(m_impl);
-	}
-}
-
 //==============================================================================
 void GrManager::swapBuffers()
 {
 	m_impl->getRenderingThread().swapBuffers();
 }
 
-//==============================================================================
-PtrSize GrManager::getBufferOffsetAlignment(GLenum target) const
-{
-	const GlState& state = m_impl->getRenderingThread().getState();
-
-	if(target == GL_UNIFORM_BUFFER)
-	{
-		return state.m_uniBuffOffsetAlignment;
-	}
-	else
-	{
-		ANKI_ASSERT(target == GL_SHADER_STORAGE_BUFFER);
-		return state.m_ssBuffOffsetAlignment;
-	}
-}
-
 } // end namespace anki

+ 9 - 3
src/gr/gl/GrManagerImpl.cpp

@@ -22,20 +22,26 @@ GrManagerImpl::~GrManagerImpl()
 	m_manager = nullptr;
 }
 
+//==============================================================================
+GrAllocator<U8> GrManagerImpl::getAllocator() const
+{
+	return m_manager->getAllocator();
+}
+
 //==============================================================================
 Error GrManagerImpl::create(GrManagerInitializer& init)
 {
 	Error err = ErrorCode::NONE;
 
 	// Create thread
-	m_thread = 
+	m_thread =
 		m_manager->getAllocator().newInstance<RenderingThread>(m_manager);
 
 	// Start it
 	if(!err)
 	{
-		err = m_thread->start(init.m_makeCurrentCallback, 
-			init.m_makeCurrentCallbackData, init.m_ctx, 
+		err = m_thread->start(init.m_makeCurrentCallback,
+			init.m_makeCurrentCallbackData, init.m_ctx,
 			init.m_swapBuffersCallback, init.m_swapBuffersCallbackData,
 			init.m_registerDebugMessages);
 	}

+ 60 - 0
src/gr/gl/OcclusionQuery.cpp

@@ -0,0 +1,60 @@
+// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include "anki/gr/OcclusionQuery.h"
+#include "anki/gr/gl/OcclusionQueryImpl.h"
+#include "anki/gr/gl/CommandBufferImpl.h"
+
+namespace anki {
+
+//==============================================================================
+OcclusionQuery::OcclusionQuery(GrManager* manager)
+	: GrObject(manager)
+{}
+
+//==============================================================================
+OcclusionQuery::~OcclusionQuery()
+{}
+
+//==============================================================================
+class CreateOqCommand final: public GlCommand
+{
+public:
+	OcclusionQueryPtr m_q;
+	OcclusionQueryResultBit m_condRenderingBit;
+
+	CreateOqCommand(OcclusionQuery* q, OcclusionQueryResultBit condRenderingBit)
+		: m_q(q)
+		, m_condRenderingBit(condRenderingBit)
+	{}
+
+	Error operator()(GlState&)
+	{
+		OcclusionQueryImpl& impl = m_q->getImplementation();
+
+		impl.create(m_condRenderingBit);
+
+		GlObject::State oldState =
+			impl.setStateAtomically(GlObject::State::CREATED);
+
+		(void)oldState;
+		ANKI_ASSERT(oldState == GlObject::State::TO_BE_CREATED);
+
+		return ErrorCode::NONE;
+	}
+};
+
+void OcclusionQuery::create(OcclusionQueryResultBit condRenderingBit)
+{
+	m_impl.reset(getAllocator().newInstance<OcclusionQueryImpl>(&getManager()));
+
+	CommandBufferPtr cmdb = getManager().newInstance<CommandBuffer>();
+
+	cmdb->getImplementation().pushBackNewCommand<CreateOqCommand>(
+		this, condRenderingBit);
+	cmdb->flush();
+}
+
+} // end namespace anki

+ 6 - 13
src/gr/gl/OcclusionQueryImpl.cpp

@@ -8,7 +8,7 @@
 namespace anki {
 
 //==============================================================================
-void OcclusionQueryImpl::create(ResultBit condRenderingBit)
+void OcclusionQueryImpl::create(OcclusionQueryResultBit condRenderingBit)
 {
 	glGenQueries(1, &m_glName);
 	ANKI_ASSERT(m_glName != 0);
@@ -30,10 +30,10 @@ void OcclusionQueryImpl::end()
 }
 
 //==============================================================================
-OcclusionQueryImpl::Result OcclusionQueryImpl::getResult() const
+OcclusionQueryResult OcclusionQueryImpl::getResult() const
 {
 	ANKI_ASSERT(isCreated());
-	Result result = Result::NOT_AVAILABLE;
+	OcclusionQueryResult result = OcclusionQueryResult::NOT_AVAILABLE;
 	GLuint params;
 	glGetQueryObjectuiv(m_glName, GL_QUERY_RESULT_AVAILABLE, &params);
 
@@ -41,20 +41,13 @@ OcclusionQueryImpl::Result OcclusionQueryImpl::getResult() const
 	{
 		glGetQueryObjectuiv(m_glName, GL_QUERY_RESULT, &params);
 
-		result = (params == 1) ? Result::VISIBLE : Result::NOT_VISIBLE;
+		result = (params == 1)
+			? OcclusionQueryResult::VISIBLE
+			: OcclusionQueryResult::NOT_VISIBLE;
 	}
 
 	return result;
 }
 
-//==============================================================================
-void OcclusionQueryImpl::destroy()
-{
-	if(m_glName != 0)
-	{
-		destroyDeferred(glDeleteQueries);
-	}
-}
-
 } // end namespace anki
 

+ 0 - 117
src/gr/gl/OcclusionQueryPtr.cpp

@@ -1,117 +0,0 @@
-// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#include "anki/gr/OcclusionQueryPtr.h"
-#include "anki/gr/gl/OcclusionQueryImpl.h"
-#include "anki/gr/gl/CommandBufferImpl.h"
-#include "anki/gr/CommandBufferPtr.h"
-
-namespace anki {
-
-//==============================================================================
-// Commands                                                                    =
-//==============================================================================
-
-/// Create command.
-class OqCreateCommand final: public GlCommand
-{
-public:
-	OcclusionQueryPtr m_handle;
-	OcclusionQueryResultBit m_condRenderingBit;
-
-	OqCreateCommand(OcclusionQueryPtr& handle,
-		OcclusionQueryResultBit condRenderingBit)
-	:	m_handle(handle),
-		m_condRenderingBit(condRenderingBit)
-	{}
-
-	Error operator()(CommandBufferImpl*)
-	{
-		m_handle.get().create(m_condRenderingBit);
-
-		GlObject::State oldState = m_handle.get().setStateAtomically(
-			GlObject::State::CREATED);
-		ANKI_ASSERT(oldState == GlObject::State::TO_BE_CREATED);
-		(void)oldState;
-
-		return ErrorCode::NONE;
-	}
-};
-
-/// Begin query.
-class OqBeginCommand final: public GlCommand
-{
-public:
-	OcclusionQueryPtr m_handle;
-
-	OqBeginCommand(OcclusionQueryPtr& handle)
-	:	m_handle(handle)
-	{}
-
-	Error operator()(CommandBufferImpl*)
-	{
-		m_handle.get().begin();
-		return ErrorCode::NONE;
-	}
-};
-
-/// End query.
-class OqEndCommand final: public GlCommand
-{
-public:
-	OcclusionQueryPtr m_handle;
-
-	OqEndCommand(OcclusionQueryPtr& handle)
-	:	m_handle(handle)
-	{}
-
-	Error operator()(CommandBufferImpl*)
-	{
-		m_handle.get().end();
-		return ErrorCode::NONE;
-	}
-};
-
-//==============================================================================
-// OcclusionQueryPtr                                                        =
-//==============================================================================
-
-//==============================================================================
-OcclusionQueryPtr::OcclusionQueryPtr()
-{}
-
-//==============================================================================
-OcclusionQueryPtr::~OcclusionQueryPtr()
-{}
-
-//==============================================================================
-void OcclusionQueryPtr::create(GrManager* manager, ResultBit condRenderingBit)
-{
-	CommandBufferPtr cmd;
-	cmd.create(manager);
-
-	Base::create(*manager);
-	get().setStateAtomically(GlObject::State::TO_BE_CREATED);
-
-	cmd.get().pushBackNewCommand<OqCreateCommand>(*this, condRenderingBit);
-	cmd.flush();
-}
-
-//==============================================================================
-void OcclusionQueryPtr::begin(CommandBufferPtr& commands)
-{
-	ANKI_ASSERT(isCreated());
-	commands.get().pushBackNewCommand<OqBeginCommand>(*this);
-}
-
-//==============================================================================
-void OcclusionQueryPtr::end(CommandBufferPtr& commands)
-{
-	ANKI_ASSERT(isCreated());
-	commands.get().pushBackNewCommand<OqEndCommand>(*this);
-}
-
-} // end namespace anki
-

+ 60 - 0
src/gr/gl/Pipeline.cpp

@@ -0,0 +1,60 @@
+// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include "anki/gr/Pipeline.h"
+#include "anki/gr/gl/PipelineImpl.h"
+#include "anki/gr/gl/CommandBufferImpl.h"
+
+namespace anki {
+
+//==============================================================================
+Pipeline::Pipeline(GrManager* manager)
+	: GrObject(manager)
+{}
+
+//==============================================================================
+Pipeline::~Pipeline()
+{}
+
+//==============================================================================
+class CreatePipelineCommand final: public GlCommand
+{
+public:
+	PipelinePtr m_ppline;
+	PipelineInitializer m_init;
+
+	CreatePipelineCommand(Pipeline* ppline, const PipelineInitializer& init)
+		: m_ppline(ppline)
+		, m_init(init)
+	{}
+
+	Error operator()(GlState&)
+	{
+		PipelineImpl& impl = m_ppline->getImplementation();
+
+		Error err = impl.create(m_init);
+
+		GlObject::State oldState = impl.setStateAtomically(
+			err ? GlObject::State::ERROR : GlObject::State::CREATED);
+		ANKI_ASSERT(oldState == GlObject::State::TO_BE_CREATED);
+		(void)oldState;
+
+		return err;
+	}
+};
+
+void Pipeline::create(const PipelineInitializer& init)
+{
+	m_impl.reset(getAllocator().newInstance<PipelineImpl>(&getManager()));
+
+	CommandBufferPtr cmdb = getManager().newInstance<CommandBuffer>();
+
+	cmdb->getImplementation().pushBackNewCommand<CreatePipelineCommand>(
+		this, init);
+	cmdb->flush();
+}
+
+} // end namespace anki
+

+ 9 - 17
src/gr/gl/PipelineImpl.cpp

@@ -5,8 +5,10 @@
 
 #include "anki/gr/gl/PipelineImpl.h"
 #include "anki/gr/gl/ShaderImpl.h"
+#include "anki/gr/GrManager.h"
 #include "anki/gr/gl/GrManagerImpl.h"
 #include "anki/gr/gl/RenderingThread.h"
+#include "anki/gr/gl/CommandBufferImpl.h"
 #include "anki/util/Logger.h"
 #include "anki/util/Hash.h"
 
@@ -104,7 +106,7 @@ static GLenum convertBlendMethod(BlendMethod in)
 }
 
 //==============================================================================
-Error PipelineImpl::create(const Initializer& init)
+Error PipelineImpl::create(const PipelineInitializer& init)
 {
 	m_in = init;
 
@@ -122,15 +124,6 @@ Error PipelineImpl::create(const Initializer& init)
 	return ErrorCode::NONE;
 }
 
-//==============================================================================
-void PipelineImpl::destroy()
-{
-	if(m_glName)
-	{
-		destroyDeferred(glDeleteProgramPipelines);
-	}
-}
-
 //==============================================================================
 Error PipelineImpl::createGlPipeline()
 {
@@ -144,7 +137,8 @@ Error PipelineImpl::createGlPipeline()
 		const ShaderPtr& shader = m_in.m_shaders[count];
 		if(shader.isCreated())
 		{
-			ANKI_ASSERT(count == enumToType(shader.get().getType()));
+			ANKI_ASSERT(
+				count == enumToType(shader->getImplementation().m_type));
 			mask |= 1 << count;
 		}
 	}
@@ -188,7 +182,8 @@ Error PipelineImpl::createGlPipeline()
 		{
 			GLbitfield bit;
 			computeGlShaderType(static_cast<ShaderType>(i), &bit);
-			glUseProgramStages(m_glName, bit, shader.get().getGlName());
+			glUseProgramStages(
+				m_glName, bit, shader->getImplementation().getGlName());
 
 			if(i == U(ShaderType::TESSELLATION_CONTROL)
 				|| i == U(ShaderType::TESSELLATION_EVALUATION))
@@ -227,7 +222,7 @@ Error PipelineImpl::createGlPipeline()
 }
 
 //==============================================================================
-void PipelineImpl::bind()
+void PipelineImpl::bind(GlState& state)
 {
 	glBindProgramPipeline(m_glName);
 
@@ -236,10 +231,7 @@ void PipelineImpl::bind()
 		return;
 	}
 
-	// Get last pipeline
-	GlState& state =
-		getManager().getImplementation().getRenderingThread().getState();
-
+	// Set state
 	setVertexState(state);
 	setInputAssemblerState(state);
 	setTessellationState(state);

+ 0 - 105
src/gr/gl/PipelinePtr.cpp

@@ -1,105 +0,0 @@
-// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#include "anki/gr/PipelinePtr.h"
-#include "anki/gr/PipelineCommon.h"
-#include "anki/gr/gl/PipelineImpl.h"
-#include "anki/gr/gl/ShaderImpl.h"
-#include "anki/gr/gl/CommandBufferImpl.h"
-#include "anki/gr/CommandBufferPtr.h"
-#include "anki/gr/gl/GrManagerImpl.h"
-#include "anki/gr/gl/RenderingThread.h"
-
-namespace anki {
-
-//==============================================================================
-// Commands                                                                    =
-//==============================================================================
-
-class CreatePipelineCommand final: public GlCommand
-{
-public:
-	PipelinePtr m_ppline;
-	PipelineInitializer m_init;
-
-	CreatePipelineCommand(
-		const PipelinePtr& ppline,
-		const PipelineInitializer& init)
-	:	m_ppline(ppline),
-		m_init(init)
-	{}
-
-	Error operator()(CommandBufferImpl* cmdb)
-	{
-		Error err = m_ppline.get().create(m_init);
-
-		GlObject::State oldState = m_ppline.get().setStateAtomically(
-			err ? GlObject::State::ERROR : GlObject::State::CREATED);
-		ANKI_ASSERT(oldState == GlObject::State::TO_BE_CREATED);
-		(void)oldState;
-
-		return err;
-	}
-};
-
-class BindPipelineCommand final: public GlCommand
-{
-public:
-	PipelinePtr m_ppline;
-
-	BindPipelineCommand(PipelinePtr& ppline)
-	:	m_ppline(ppline)
-	{}
-
-	Error operator()(CommandBufferImpl* commands)
-	{
-		GlState& state = commands->getManager().getImplementation().
-			getRenderingThread().getState();
-
-		auto name = m_ppline.get().getGlName();
-		if(state.m_crntPpline != name)
-		{
-			m_ppline.get().bind();
-			state.m_crntPpline = name;
-		}
-
-		return ErrorCode::NONE;
-	}
-};
-
-//==============================================================================
-// PipelinePtr                                                                 =
-//==============================================================================
-
-//==============================================================================
-PipelinePtr::PipelinePtr()
-{}
-
-//==============================================================================
-PipelinePtr::~PipelinePtr()
-{}
-
-//==============================================================================
-void PipelinePtr::create(GrManager* manager, const Initializer& init)
-{
-	CommandBufferPtr cmdb;
-	cmdb.create(manager);
-
-	Base::create(cmdb.get().getManager());
-	get().setStateAtomically(GlObject::State::TO_BE_CREATED);
-	cmdb.get().pushBackNewCommand<CreatePipelineCommand>(*this, init);
-
-	cmdb.flush();
-}
-
-//==============================================================================
-void PipelinePtr::bind(CommandBufferPtr& commands)
-{
-	ANKI_ASSERT(isCreated());
-	commands.get().pushBackNewCommand<BindPipelineCommand>(*this);
-}
-
-} // end namespace anki
-

+ 49 - 34
src/gr/gl/RenderingThread.cpp

@@ -16,13 +16,36 @@ namespace anki {
 // Misc                                                                        =
 //==============================================================================
 
-//==============================================================================
+/// Sync rendering thread command.
 class SyncCommand final: public GlCommand
 {
-	ANKI_USE_RESULT Error operator()(CommandBufferImpl* cmd)
+public:
+	RenderingThread* m_renderingThread;
+
+	SyncCommand(RenderingThread* renderingThread)
+		: m_renderingThread(renderingThread)
+	{}
+
+	ANKI_USE_RESULT Error operator()(GlState&)
 	{
-		cmd->getManager().getImplementation().
-			getRenderingThread().m_syncBarrier.wait();
+		m_renderingThread->m_syncBarrier.wait();
+		return ErrorCode::NONE;
+	}
+};
+
+/// Swap buffers command.
+class SwapBuffersCommand final: public GlCommand
+{
+public:
+	RenderingThread* m_renderingThread;
+
+	SwapBuffersCommand(RenderingThread* renderingThread)
+		: m_renderingThread(renderingThread)
+	{}
+
+	ANKI_USE_RESULT Error operator()(GlState&)
+	{
+		m_renderingThread->swapBuffersInternal();
 		return ErrorCode::NONE;
 	}
 };
@@ -33,12 +56,12 @@ class SyncCommand final: public GlCommand
 
 //==============================================================================
 RenderingThread::RenderingThread(GrManager* manager)
-:	m_manager(manager),
-	m_tail(0),
-	m_head(0),
-	m_renderingThreadSignal(0),
-	m_thread("anki_gl"),
-	m_state(manager)
+	: m_manager(manager)
+	, m_tail(0)
+	, m_head(0)
+	, m_renderingThreadSignal(0)
+	, m_thread("anki_gl")
+	, m_state(manager)
 {
 	ANKI_ASSERT(m_manager);
 }
@@ -48,9 +71,9 @@ RenderingThread::~RenderingThread()
 {}
 
 //==============================================================================
-void RenderingThread::flushCommandBuffer(CommandBufferPtr& commands)
+void RenderingThread::flushCommandBuffer(CommandBufferPtr commands)
 {
-	commands.get().makeImmutable();
+	commands->getImplementation().makeImmutable();
 
 #if !ANKI_DISABLE_GL_RENDERING_THREAD
 	{
@@ -68,7 +91,7 @@ void RenderingThread::flushCommandBuffer(CommandBufferPtr& commands)
 		}
 		else
 		{
-			ANKI_LOGW("Rendering queue to small");
+			ANKI_LOGW("Rendering queue too small");
 		}
 	}
 
@@ -83,7 +106,7 @@ void RenderingThread::flushCommandBuffer(CommandBufferPtr& commands)
 }
 
 //==============================================================================
-void RenderingThread::finishCommandBuffer(CommandBufferPtr& commands)
+void RenderingThread::finishCommandBuffer(CommandBufferPtr commands)
 {
 #if !ANKI_DISABLE_GL_RENDERING_THREAD
 	flushCommandBuffer(commands);
@@ -113,17 +136,17 @@ Error RenderingThread::start(
 	ANKI_ASSERT(swapBuffersCallback != nullptr);
 	m_swapBuffersCallback = swapBuffersCallback;
 	m_swapBuffersCbData = swapBuffersCbData;
-	m_swapBuffersCommands.create(m_manager);
-	m_swapBuffersCommands.pushBackUserCommand(swapBuffersInternal, this);
+	m_swapBuffersCommands = m_manager->newInstance<CommandBuffer>();
+	m_swapBuffersCommands->getImplementation().
+		pushBackNewCommand<SwapBuffersCommand>(this);
 
 #if !ANKI_DISABLE_GL_RENDERING_THREAD
 	// Start thread
 	m_thread.start(this, threadCallback);
 
 	// Create sync command buffer
-	m_syncCommands.create(m_manager);
-
-	m_syncCommands.get().pushBackNewCommand<SyncCommand>();
+	m_syncCommands = m_manager->newInstance<CommandBuffer>();
+	m_syncCommands->getImplementation().pushBackNewCommand<SyncCommand>(this);
 #else
 	prepare();
 
@@ -175,9 +198,6 @@ void RenderingThread::prepare()
 	// Create default VAO
 	glGenVertexArrays(1, &m_defaultVao);
 	glBindVertexArray(m_defaultVao);
-
-	// Create copy FBO
-	glGenFramebuffers(1, &m_copyFbo);
 }
 
 //==============================================================================
@@ -189,7 +209,7 @@ void RenderingThread::finish()
 		if(m_queue[i].isCreated())
 		{
 			// Fake that it's executed to avoid warnings
-			m_queue[i].get().makeExecuted();
+			m_queue[i]->getImplementation().makeExecuted();
 
 			// Release
 			m_queue[i] = CommandBufferPtr();
@@ -245,7 +265,7 @@ void RenderingThread::threadLoop()
 			++m_head;
 		}
 
-		Error err = cmd.get().executeAllCommands();
+		Error err = cmd->getImplementation().executeAllCommands();
 
 		if(err)
 		{
@@ -267,23 +287,18 @@ void RenderingThread::syncClientServer()
 }
 
 //==============================================================================
-Error RenderingThread::swapBuffersInternal(void* ptr)
+void RenderingThread::swapBuffersInternal()
 {
-	ANKI_ASSERT(ptr);
-	RenderingThread& self = *static_cast<RenderingThread*>(ptr);
-
 	// Do the swap buffers
-	self.m_swapBuffersCallback(self.m_swapBuffersCbData);
+	m_swapBuffersCallback(m_swapBuffersCbData);
 
 	// Notify the main thread that we are done
 	{
-		LockGuard<Mutex> lock(self.m_frameMtx);
-		self.m_frameWait = false;
+		LockGuard<Mutex> lock(m_frameMtx);
+		m_frameWait = false;
 	}
 
-	self.m_frameCondVar.notifyOne();
-
-	return ErrorCode::NONE;
+	m_frameCondVar.notifyOne();
 }
 
 //==============================================================================

+ 11 - 8
src/gr/gl/ResourceGroupPtr.cpp → src/gr/gl/ResourceGroup.cpp

@@ -3,26 +3,29 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#include "anki/gr/ResourceGroupPtr.h"
+#include "anki/gr/ResourceGroup.h"
 #include "anki/gr/gl/ResourceGroupImpl.h"
+#include "anki/gr/gl/CommandBufferImpl.h"
+#include "anki/gr/Texture.h"
+#include "anki/gr/Sampler.h"
+#include "anki/gr/Buffer.h"
 
 namespace anki {
 
 //==============================================================================
-ResourceGroupPtr::ResourceGroupPtr()
+ResourceGroup::ResourceGroup(GrManager* manager)
+	: GrObject(manager)
 {}
 
 //==============================================================================
-ResourceGroupPtr::~ResourceGroupPtr()
+ResourceGroup::~ResourceGroup()
 {}
 
 //==============================================================================
-Error ResourceGroupPtr::create(GrManager* manager, const Initializer& init)
+void ResourceGroup::create(const ResourceGroupInitializer& init)
 {
-	Base::create(*manager);
-	ANKI_CHECK(get().create(init));
-
-	return ErrorCode::NONE;
+	m_impl.reset(getAllocator().newInstance<ResourceGroupImpl>(&getManager()));
+	m_impl->create(init);
 }
 
 } // end namespace anki

+ 59 - 63
src/gr/gl/ResourceGroupImpl.cpp

@@ -4,158 +4,154 @@
 // http://www.anki3d.org/LICENSE
 
 #include "anki/gr/gl/ResourceGroupImpl.h"
-#include "anki/gr/TexturePtr.h"
 #include "anki/gr/gl/TextureImpl.h"
+#include "anki/gr/Texture.h"
 #include "anki/gr/gl/SamplerImpl.h"
+#include "anki/gr/Sampler.h"
 #include "anki/gr/gl/BufferImpl.h"
+#include "anki/gr/Buffer.h"
 #include "anki/gr/gl/GlState.h"
 #include "anki/gr/gl/GrManagerImpl.h"
+#include "anki/gr/GrManager.h"
 #include "anki/gr/gl/RenderingThread.h"
 
 namespace anki {
 
 //==============================================================================
-Error ResourceGroupImpl::create(const Initializer& init)
+void ResourceGroupImpl::create(const ResourceGroupInitializer& init)
 {
-	static_cast<Initializer&>(*this) = init;
+	m_in = init;
 
 	// Init textures & samplers
-	m_textureNamesCount = 0;
-	m_allSamplersZero = true;
+	m_cache.m_textureNamesCount = 0;
+	m_cache.m_allSamplersZero = true;
 	for(U i = 0; i < MAX_TEXTURE_BINDINGS; ++i)
 	{
-		if(m_textures[i].m_texture.isCreated())
+		if(m_in.m_textures[i].m_texture.isCreated())
 		{
-			m_textureNames[i] = m_textures[i].m_texture.get().getGlName();
-			m_textureNamesCount = i + 1;
+			m_cache.m_textureNames[i] =
+				m_in.m_textures[i].m_texture->getImplementation().getGlName();
+			++m_cache.m_textureNamesCount;
 		}
 		else
 		{
-			m_textureNames[i] = 0;
+			m_cache.m_textureNames[i] = 0;
 		}
 
-		if(m_textures[i].m_sampler.isCreated())
+		if(m_in.m_textures[i].m_sampler.isCreated())
 		{
-			m_samplerNames[i] = m_textures[i].m_sampler.get().getGlName();
-			m_allSamplersZero = false;
+			m_cache.m_samplerNames[i] =
+				m_in.m_textures[i].m_sampler->getImplementation().getGlName();
+			m_cache.m_allSamplersZero = false;
 		}
 		else
 		{
-			m_samplerNames[i] = 0;
+			m_cache.m_samplerNames[i] = 0;
 		}
 	}
 
 	// Init buffers
-	m_ubosCount = 0;
+	m_cache.m_ubosCount = 0;
 	for(U i = 0; i < MAX_UNIFORM_BUFFER_BINDINGS; ++i)
 	{
-		if(m_uniformBuffers[i].m_buffer.isCreated())
+		if(m_in.m_uniformBuffers[i].m_buffer.isCreated())
 		{
-			m_ubosCount = i + 1;
+			++m_cache.m_ubosCount;
 		}
 	}
 
-	m_ssbosCount = 0;
+	m_cache.m_ssbosCount = 0;
 	for(U i = 0; i < MAX_STORAGE_BUFFER_BINDINGS; ++i)
 	{
-		if(m_storageBuffers[i].m_buffer.isCreated())
+		if(m_in.m_storageBuffers[i].m_buffer.isCreated())
 		{
-			m_ssbosCount = i + 1;
+			++m_cache.m_ssbosCount;
 		}
 	}
 
 	// Init vert buffers
-	m_vertBindingsCount = 0;
+	m_cache.m_vertBindingsCount = 0;
 	for(U i = 0; i < MAX_VERTEX_ATTRIBUTES; ++i)
 	{
-		const BufferBinding& binding = m_vertexBuffers[i];
+		const BufferBinding& binding = m_in.m_vertexBuffers[i];
 		if(binding.m_buffer.isCreated())
 		{
-			m_vertBuffNames[i] = binding.m_buffer.get().getGlName();
-			m_vertBuffOffsets[i] = binding.m_offset;
+			m_cache.m_vertBuffNames[i] =
+				binding.m_buffer->getImplementation().getGlName();
+			m_cache.m_vertBuffOffsets[i] = binding.m_offset;
 
-			m_vertBindingsCount = i + 1;
+			++m_cache.m_vertBindingsCount;
 		}
 		else
 		{
-			m_vertBuffNames[i] = 0;
-			m_vertBuffOffsets[i] = 0;
+			m_cache.m_vertBuffNames[i] = 0;
+			m_cache.m_vertBuffOffsets[i] = 0;
 		}
 	}
-
-	return ErrorCode::NONE;
 }
 
 //==============================================================================
-void ResourceGroupImpl::bind()
+void ResourceGroupImpl::bind(GlState& state)
 {
 	// Bind textures
-	if(m_textureNamesCount)
+	if(m_cache.m_textureNamesCount)
 	{
-		glBindTextures(0, m_textureNamesCount, &m_textureNames[0]);
+		glBindTextures(
+			0, m_cache.m_textureNamesCount, &m_cache.m_textureNames[0]);
 
-		if(m_allSamplersZero)
+		if(m_cache.m_allSamplersZero)
 		{
-			glBindSamplers(0, m_textureNamesCount, nullptr);
+			glBindSamplers(0, m_cache.m_textureNamesCount, nullptr);
 		}
 		else
 		{
-			glBindSamplers(0, m_textureNamesCount, &m_samplerNames[0]);
+			glBindSamplers(
+				0, m_cache.m_textureNamesCount, &m_cache.m_samplerNames[0]);
 		}
 	}
 
 	// Uniform buffers
-	for(U i = 0; i < m_ubosCount; ++i)
+	for(U i = 0; i < m_cache.m_ubosCount; ++i)
 	{
-		BufferBinding& binding = m_uniformBuffers[i];
+		const BufferBinding& binding = m_in.m_uniformBuffers[i];
 
 		if(binding.m_buffer.isCreated())
 		{
-			BufferImpl& buff = binding.m_buffer.get();
-			if(buff.getTarget() != GL_UNIFORM_BUFFER)
-			{
-				buff.setTarget(GL_UNIFORM_BUFFER);
-			}
-			buff.setBindingRange(i, binding.m_offset, binding.m_range);
+			const BufferImpl& buff = binding.m_buffer->getImplementation();
+			buff.bind(GL_UNIFORM_BUFFER, i, binding.m_offset, binding.m_range);
 		}
 	}
 
 	// Storage buffers
-	for(U i = 0; i < m_ssbosCount; ++i)
+	for(U i = 0; i < m_cache.m_ssbosCount; ++i)
 	{
-		BufferBinding& binding = m_storageBuffers[i];
+		BufferBinding& binding = m_in.m_storageBuffers[i];
 
 		if(binding.m_buffer.isCreated())
 		{
-			BufferImpl& buff = binding.m_buffer.get();
-			if(buff.getTarget() != GL_SHADER_STORAGE_BUFFER)
-			{
-				buff.setTarget(GL_SHADER_STORAGE_BUFFER);
-			}
-			buff.setBindingRange(i, binding.m_offset, binding.m_range);
+			BufferImpl& buff = binding.m_buffer->getImplementation();
+			buff.bind(
+				GL_SHADER_STORAGE_BUFFER, i, binding.m_offset, binding.m_range);
 		}
 	}
 
 	// Vertex buffers
-	if(m_vertBindingsCount)
+	if(m_cache.m_vertBindingsCount)
 	{
-		const GlState& state =
-			getManager().getImplementation().getRenderingThread().getState();
-
 		glBindVertexBuffers(
-			0, m_vertBindingsCount, &m_vertBuffNames[0], &m_vertBuffOffsets[0],
-			&state.m_vertexBindingStrides[0]);
+			0, m_cache.m_vertBindingsCount, &m_cache.m_vertBuffNames[0],
+			&m_cache.m_vertBuffOffsets[0], &state.m_vertexBindingStrides[0]);
 	}
 
 	// Index buffer
-	if(m_indexBuffer.m_buffer.isCreated())
+	if(m_in.m_indexBuffer.m_buffer.isCreated())
 	{
-		BufferImpl& buff = m_indexBuffer.m_buffer.get();
-		if(buff.getTarget() != GL_ELEMENT_ARRAY_BUFFER)
-		{
-			buff.setTarget(GL_ELEMENT_ARRAY_BUFFER);
-		}
-		buff.bind();
+		const BufferImpl& buff =
+			m_in.m_indexBuffer.m_buffer->getImplementation();
+		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buff.getGlName());
+
+		ANKI_ASSERT(m_in.m_indexSize == 2 || m_in.m_indexSize == 4);
+		state.m_indexSize = m_in.m_indexSize;
 	}
 }
 

+ 60 - 0
src/gr/gl/Sampler.cpp

@@ -0,0 +1,60 @@
+// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include "anki/gr/Sampler.h"
+#include "anki/gr/gl/SamplerImpl.h"
+#include "anki/gr/gl/CommandBufferImpl.h"
+
+namespace anki {
+
+//==============================================================================
+Sampler::Sampler(GrManager* manager)
+	: GrObject(manager)
+{}
+
+//==============================================================================
+Sampler::~Sampler()
+{}
+
+//==============================================================================
+class CreateSamplerCommand: public GlCommand
+{
+public:
+	SamplerPtr m_sampler;
+	SamplerInitializer m_init;
+
+	CreateSamplerCommand(Sampler* sampler, const SamplerInitializer& init)
+        : m_sampler(sampler)
+		, m_init(init)
+	{}
+
+	Error operator()(GlState&)
+	{
+        SamplerImpl& impl = m_sampler->getImplementation();
+
+		impl.create(m_init);
+
+        GlObject::State oldState =
+			impl.setStateAtomically(GlObject::State::CREATED);
+
+		(void)oldState;
+		ANKI_ASSERT(oldState == GlObject::State::TO_BE_CREATED);
+
+		return ErrorCode::NONE;
+	}
+};
+
+void Sampler::create(const SamplerInitializer& init)
+{
+	m_impl.reset(getAllocator().newInstance<SamplerImpl>(&getManager()));
+
+	CommandBufferPtr cmdb = getManager().newInstance<CommandBuffer>();
+
+	cmdb->getImplementation().pushBackNewCommand<CreateSamplerCommand>(
+		this, init);
+	cmdb->flush();
+}
+
+} // end namespace anki

+ 5 - 7
src/gr/gl/SamplerImpl.cpp

@@ -4,16 +4,16 @@
 // http://www.anki3d.org/LICENSE
 
 #include "anki/gr/gl/SamplerImpl.h"
-#include "anki/gr/TextureSamplerCommon.h"
+#include "anki/gr/Texture.h"
 
 namespace anki {
 
 //==============================================================================
-Error SamplerImpl::create(const SamplerInitializer& sinit)
+void SamplerImpl::create(const SamplerInitializer& sinit)
 {
 	glGenSamplers(1, &m_glName);
 	ANKI_ASSERT(m_glName);
-	
+
 	if(sinit.m_repeat)
 	{
 		glSamplerParameteri(m_glName, GL_TEXTURE_WRAP_S, GL_REPEAT);
@@ -28,7 +28,7 @@ Error SamplerImpl::create(const SamplerInitializer& sinit)
 	// Set filtering type
 	GLenum minFilter = GL_NONE;
 		GLenum magFilter = GL_NONE;
-	convertFilter(sinit.m_minMagFilter, sinit.m_mipmapFilter, minFilter, 
+	convertFilter(sinit.m_minMagFilter, sinit.m_mipmapFilter, minFilter,
 		magFilter);
 	glSamplerParameteri(m_glName, GL_TEXTURE_MIN_FILTER, minFilter);
 	glSamplerParameteri(m_glName, GL_TEXTURE_MAG_FILTER, magFilter);
@@ -36,12 +36,10 @@ Error SamplerImpl::create(const SamplerInitializer& sinit)
 #if ANKI_GL == ANKI_GL_DESKTOP
 	if(sinit.m_anisotropyLevel > 1)
 	{
-		glSamplerParameteri(m_glName, GL_TEXTURE_MAX_ANISOTROPY_EXT, 
+		glSamplerParameteri(m_glName, GL_TEXTURE_MAX_ANISOTROPY_EXT,
 			GLint(sinit.m_anisotropyLevel));
 	}
 #endif
-	
-	return ErrorCode::NONE;
 }
 
 } // end namespace anki

+ 0 - 116
src/gr/gl/SamplerPtr.cpp

@@ -1,116 +0,0 @@
-// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#include "anki/gr/SamplerPtr.h"
-#include "anki/gr/gl/SamplerImpl.h"
-#include "anki/gr/GrManager.h"
-#include "anki/gr/gl/CommandBufferImpl.h"
-#include "anki/gr/CommandBufferPtr.h"
-
-namespace anki {
-
-//==============================================================================
-// SamplerCommands                                                             =
-//==============================================================================
-
-//==============================================================================
-class CreateSamplerCommand: public GlCommand
-{
-public:
-	SamplerPtr m_sampler;
-	SamplerInitializer m_init;
-
-	CreateSamplerCommand(const SamplerPtr& sampler,
-		const SamplerInitializer& init)
-	:	m_sampler(sampler),
-		m_init(init)
-	{}
-
-	Error operator()(CommandBufferImpl* commands)
-	{
-		ANKI_ASSERT(commands);
-
-		Error err = m_sampler.get().create(m_init);
-
-		GlObject::State oldState = m_sampler.get().setStateAtomically(
-			(err) ? GlObject::State::ERROR : GlObject::State::CREATED);
-		ANKI_ASSERT(oldState == GlObject::State::TO_BE_CREATED);
-		(void)oldState;
-
-		return err;
-	}
-};
-
-//==============================================================================
-class BindSamplerCommand: public GlCommand
-{
-public:
-	SamplerPtr m_sampler;
-	U8 m_unit;
-
-	BindSamplerCommand(SamplerPtr& sampler, U8 unit)
-	:	m_sampler(sampler),
-		m_unit(unit)
-	{}
-
-	Error operator()(CommandBufferImpl*)
-	{
-		m_sampler.get().bind(m_unit);
-		return ErrorCode::NONE;
-	}
-};
-
-//==============================================================================
-class BindDefaultSamplerCommand: public GlCommand
-{
-public:
-	U32 m_unit;
-
-	BindDefaultSamplerCommand(U32 unit)
-	:	m_unit(unit)
-	{}
-
-	Error operator()(CommandBufferImpl*)
-	{
-		SamplerImpl::unbind(m_unit);
-		return ErrorCode::NONE;
-	}
-};
-
-//==============================================================================
-// SamplerPtr                                                               =
-//==============================================================================
-
-//==============================================================================
-SamplerPtr::SamplerPtr()
-{}
-
-//==============================================================================
-SamplerPtr::~SamplerPtr()
-{}
-
-//==============================================================================
-void SamplerPtr::create(CommandBufferPtr& commands,
-	const SamplerInitializer& init)
-{
-	Base::create(commands.get().getManager());
-	get().setStateAtomically(GlObject::State::TO_BE_CREATED);
-	commands.get().pushBackNewCommand<CreateSamplerCommand>(*this, init);
-}
-
-//==============================================================================
-void SamplerPtr::bind(CommandBufferPtr& commands, U32 unit)
-{
-	ANKI_ASSERT(isCreated());
-	commands.get().pushBackNewCommand<BindSamplerCommand>(*this, unit);
-}
-
-//==============================================================================
-void SamplerPtr::bindDefault(CommandBufferPtr& commands, U32 unit)
-{
-	commands.get().pushBackNewCommand<BindDefaultSamplerCommand>(unit);
-}
-
-} // end namespace anki

+ 79 - 0
src/gr/gl/Shader.cpp

@@ -0,0 +1,79 @@
+// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include "anki/gr/Shader.h"
+#include "anki/gr/gl/ShaderImpl.h"
+#include "anki/gr/gl/CommandBufferImpl.h"
+
+namespace anki {
+
+//==============================================================================
+Shader::Shader(GrManager* manager)
+	: GrObject(manager)
+{}
+
+//==============================================================================
+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)
+	{}
+
+	Error operator()(GlState&)
+	{
+		ShaderImpl& impl = m_shader->getImplementation();
+
+		Error err = impl.create(m_type, m_source);
+
+		GlObject::State oldState = impl.setStateAtomically(
+			(err) ? GlObject::State::ERROR : GlObject::State::CREATED);
+		ANKI_ASSERT(oldState == GlObject::State::TO_BE_CREATED);
+		(void)oldState;
+
+		// Delete source
+		m_alloc.deallocate(m_source, 1);
+
+		return err;
+	}
+};
+
+void Shader::create(ShaderType shaderType, const void* source,
+	PtrSize sourceSize)
+{
+	ANKI_ASSERT(source);
+	ANKI_ASSERT(sourceSize
+		== CString(static_cast<const char*>(source)).getLength() + 1);
+
+	m_impl.reset(getAllocator().newInstance<ShaderImpl>(&getManager()));
+
+	CommandBufferPtr cmdb = getManager().newInstance<CommandBuffer>();
+
+	// Copy source to the command buffer
+	CommandBufferAllocator<char> alloc =
+		cmdb->getImplementation().getInternalAllocator();
+	char* src = alloc.allocate(sourceSize);
+	memcpy(src, source, sourceSize);
+
+	cmdb->getImplementation().pushBackNewCommand<ShaderCreateCommand>(
+		this, shaderType, src, alloc);
+	cmdb->flush();
+}
+
+} // end namespace anki
+

+ 7 - 10
src/gr/gl/ShaderImpl.cpp

@@ -26,6 +26,12 @@ static void deleteProgram(GLsizei n, const GLuint* names)
 	glDeleteProgram(*names);
 }
 
+//==============================================================================
+ShaderImpl::~ShaderImpl()
+{
+	destroyDeferred(deleteProgram);
+}
+
 //==============================================================================
 Error ShaderImpl::create(ShaderType type, const CString& source)
 {
@@ -97,7 +103,7 @@ Error ShaderImpl::create(ShaderType type, const CString& source)
 		}
 
 		StringAuto fname(alloc);
-		CString cacheDir = getManager().getCacheDirectory();
+		CString cacheDir = m_manager->getCacheDirectory();
 		fname.sprintf("%s/%05u.%s", &cacheDir[0],
 			static_cast<U32>(m_glName), ext);
 
@@ -160,14 +166,5 @@ void ShaderImpl::handleError(String& src)
 	compilerLog.destroy(alloc);
 }
 
-//==============================================================================
-void ShaderImpl::destroy()
-{
-	if(m_glName != 0)
-	{
-		destroyDeferred(deleteProgram);
-	}
-}
-
 } // end namespace anki
 

+ 0 - 85
src/gr/gl/ShaderPtr.cpp

@@ -1,85 +0,0 @@
-// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#include "anki/gr/ShaderPtr.h"
-#include "anki/gr/GrManager.h"
-#include "anki/gr/gl/ShaderImpl.h"
-#include "anki/gr/gl/CommandBufferImpl.h"
-#include "anki/gr/CommandBufferPtr.h"
-
-namespace anki {
-
-//==============================================================================
-// Commands                                                                    =
-//==============================================================================
-
-/// Create program command
-class ShaderCreateCommand final: public GlCommand
-{
-public:
-	ShaderPtr m_shader;
-	ShaderType m_type;
-	char* m_source;
-
-	ShaderCreateCommand(ShaderPtr shader,
-		ShaderType type, char* source)
-	:	m_shader(shader),
-		m_type(type),
-		m_source(source)
-	{}
-
-	Error operator()(CommandBufferImpl* cmdb)
-	{
-		Error err = m_shader.get().create(m_type,
-			static_cast<const char*>(m_source));
-
-		GlObject::State oldState = m_shader.get().setStateAtomically(
-			(err) ? GlObject::State::ERROR : GlObject::State::CREATED);
-		ANKI_ASSERT(oldState == GlObject::State::TO_BE_CREATED);
-		(void)oldState;
-
-		// Delete source
-		cmdb->getInternalAllocator().deallocate(m_source, 1);
-
-		return err;
-	}
-};
-
-//==============================================================================
-// ShaderPtr                                                                =
-//==============================================================================
-
-//==============================================================================
-ShaderPtr::ShaderPtr()
-{}
-
-//==============================================================================
-ShaderPtr::~ShaderPtr()
-{}
-
-//==============================================================================
-void ShaderPtr::create(GrManager* manager,
-	ShaderType type, const void* source, PtrSize sourceSize)
-{
-	ANKI_ASSERT(strlen(static_cast<const char*>(source)) == sourceSize - 1);
-
-	CommandBufferPtr cmdb;
-	cmdb.create(manager);
-
-	Base::create(cmdb.get().getManager());
-	get().setStateAtomically(GlObject::State::TO_BE_CREATED);
-
-	// Copy source to the command buffer
-	void* src = cmdb.get().getInternalAllocator().allocate(sourceSize);
-	memcpy(src, source, sourceSize);
-
-	cmdb.get().pushBackNewCommand<ShaderCreateCommand>(
-		*this, type, static_cast<char*>(src));
-
-	cmdb.flush();
-}
-
-} // end namespace anki
-

+ 59 - 0
src/gr/gl/Texture.cpp

@@ -0,0 +1,59 @@
+// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include "anki/gr/Texture.h"
+#include "anki/gr/gl/TextureImpl.h"
+#include "anki/gr/gl/CommandBufferImpl.h"
+
+namespace anki {
+
+//==============================================================================
+Texture::Texture(GrManager* manager)
+	: GrObject(manager)
+{}
+
+//==============================================================================
+Texture::~Texture()
+{}
+
+//==============================================================================
+class CreateTextureCommand final: public GlCommand
+{
+public:
+	IntrusivePtr<Texture> m_tex;
+	TextureInitializer m_init;
+
+	CreateTextureCommand(Texture* tex, const TextureInitializer& init)
+		: m_tex(tex)
+		, m_init(init)
+	{}
+
+	Error operator()(GlState&)
+	{
+		TextureImpl& impl = m_tex->getImplementation();
+
+		impl.create(m_init);
+
+		GlObject::State oldState = impl.setStateAtomically(
+			GlObject::State::CREATED);
+		ANKI_ASSERT(oldState == GlObject::State::TO_BE_CREATED);
+		(void)oldState;
+
+		return ErrorCode::NONE;
+	}
+};
+
+void Texture::create(const TextureInitializer& init)
+{
+	m_impl.reset(getAllocator().newInstance<TextureImpl>(&getManager()));
+
+	CommandBufferPtr cmdb = getManager().newInstance<CommandBuffer>();
+
+	cmdb->getImplementation().pushBackNewCommand<CreateTextureCommand>(
+		this, init);
+	cmdb->flush();
+}
+
+} // end namespace anki

+ 119 - 159
src/gr/gl/TextureImpl.cpp

@@ -4,11 +4,9 @@
 // http://www.anki3d.org/LICENSE
 
 #include "anki/gr/gl/TextureImpl.h"
-#include "anki/gr/TextureSamplerCommon.h"
+#include "anki/gr/Texture.h"
 #include "anki/gr/gl/Error.h"
 #include "anki/util/Functions.h"
-#include "anki/util/DArray.h"
-#include <cstring>
 
 namespace anki {
 
@@ -193,7 +191,14 @@ static void convertTextureInformation(
 //==============================================================================
 
 //==============================================================================
-void TextureImpl::create(const Initializer& init)
+void TextureImpl::bind()
+{
+	glActiveTexture(GL_TEXTURE0);
+	glBindTexture(m_target, m_glName);
+}
+
+//==============================================================================
+void TextureImpl::create(const TextureInitializer& init)
 {
 	GrAllocator<U8> alloc = getAllocator();
 	const SamplerInitializer& sinit = init.m_sampling;
@@ -222,7 +227,7 @@ void TextureImpl::create(const Initializer& init)
 		min<U>(init.m_mipmapsCount, computeMaxMipmapCount(m_width, m_height));
 
 	// Bind
-	bind(0);
+	bind();
 
 	// Create storage
 	switch(m_target)
@@ -259,148 +264,6 @@ void TextureImpl::create(const Initializer& init)
 		ANKI_ASSERT(0);
 	}
 
-	// Load data
-	if(init.m_data[0][0].m_ptr != nullptr)
-	{
-		U w = m_width;
-		U h = m_height;
-		for(U level = 0; level < m_mipsCount; level++)
-		{
-			ANKI_ASSERT(init.m_data[level][0].m_ptr != nullptr);
-
-			switch(m_target)
-			{
-			case GL_TEXTURE_2D:
-				if(!m_compressed)
-				{
-					glTexSubImage2D(
-						m_target,
-						level,
-						0,
-						0,
-						w,
-						h,
-						m_format,
-						m_type,
-						init.m_data[level][0].m_ptr);
-				}
-				else
-				{
-					ANKI_ASSERT(init.m_data[level][0].m_ptr
-						&& init.m_data[level][0].m_size > 0);
-
-					glCompressedTexSubImage2D(
-						m_target,
-						level,
-						0,
-						0,
-						w,
-						h,
-						m_format,
-						init.m_data[level][0].m_size,
-						init.m_data[level][0].m_ptr);
-				}
-				break;
-			case GL_TEXTURE_CUBE_MAP:
-				for(U face = 0; face < 6; ++face)
-				{
-					if(!m_compressed)
-					{
-						glTexSubImage2D(
-							GL_TEXTURE_CUBE_MAP_POSITIVE_X + face,
-							level,
-							0,
-							0,
-							w,
-							h,
-							m_format,
-							m_type,
-							init.m_data[level][face].m_ptr);
-					}
-					else
-					{
-
-						glCompressedTexSubImage2D(
-							GL_TEXTURE_CUBE_MAP_POSITIVE_X + face,
-							level,
-							0,
-							0,
-							w,
-							h,
-							m_format,
-							init.m_data[level][face].m_size,
-							init.m_data[level][face].m_ptr);
-					}
-				}
-				break;
-			case GL_TEXTURE_2D_ARRAY:
-			case GL_TEXTURE_3D:
-				{
-					ANKI_ASSERT(m_depth > 0);
-
-					// Gather the data
-					DArrayAuto<U8> data(alloc);
-
-					// Check if there are data
-					if(init.m_data[level][0].m_ptr != nullptr)
-					{
-						PtrSize layerSize = init.m_data[level][0].m_size;
-						ANKI_ASSERT(layerSize > 0);
-						data.create(layerSize * m_depth);
-
-						for(U d = 0; d < m_depth; d++)
-						{
-							ANKI_ASSERT(
-								init.m_data[level][d].m_size == layerSize
-								&& init.m_data[level][d].m_ptr != nullptr);
-
-							memcpy(&data[0] + d * layerSize,
-								init.m_data[level][d].m_ptr,
-								layerSize);
-						}
-					}
-
-					if(!m_compressed)
-					{
-						glTexSubImage3D(
-							m_target,
-							level,
-							0,
-							0,
-							0,
-							w,
-							h,
-							m_depth,
-							m_format,
-							m_type,
-							&data[0]);
-					}
-					else
-					{
-						glCompressedTexSubImage3D(
-							m_target,
-							level,
-							0,
-							0,
-							0,
-							w,
-							h,
-							m_depth,
-							m_format,
-							data.getSize(),
-							&data[0]);
-					}
-				}
-				break;
-			default:
-				ANKI_ASSERT(0);
-			}
-
-			w /= 2;
-			h /= 2;
-		}
-	} // end if data
-
 	// Set parameters
 	if(init.m_samples == 1)
 	{
@@ -448,27 +311,124 @@ void TextureImpl::create(const Initializer& init)
 }
 
 //==============================================================================
-void TextureImpl::destroy()
+void TextureImpl::write(U32 mipmap, U32 slice, void* data, PtrSize dataSize)
 {
-	if(m_glName)
+	ANKI_ASSERT(data);
+	ANKI_ASSERT(dataSize > 0);
+	ANKI_ASSERT(mipmap < m_mipsCount);
+
+	U w = m_width >> mipmap;
+	U h = m_height >> mipmap;
+
+	ANKI_ASSERT(w > 0);
+	ANKI_ASSERT(h > 0);
+
+	bind();
+
+	switch(m_target)
 	{
-		destroyDeferred(glDeleteTextures);
-	}
-}
+	case GL_TEXTURE_2D:
+		if(!m_compressed)
+		{
+			glTexSubImage2D(
+				m_target,
+				mipmap,
+				0,
+				0,
+				w,
+				h,
+				m_format,
+				m_type,
+				data);
+		}
+		else
+		{
+			glCompressedTexSubImage2D(
+				m_target,
+				mipmap,
+				0,
+				0,
+				w,
+				h,
+				m_format,
+				dataSize,
+				data);
+		}
+		break;
+	case GL_TEXTURE_CUBE_MAP:
+		if(!m_compressed)
+		{
+			glTexSubImage2D(
+				GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice,
+				mipmap,
+				0,
+				0,
+				w,
+				h,
+				m_format,
+				m_type,
+				data);
+		}
+		else
+		{
+			glCompressedTexSubImage2D(
+				GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice,
+				mipmap,
+				0,
+				0,
+				w,
+				h,
+				m_format,
+				dataSize,
+				data);
+		}
+		break;
+	case GL_TEXTURE_2D_ARRAY:
+	case GL_TEXTURE_3D:
+		ANKI_ASSERT(m_depth > 0);
+		ANKI_ASSERT(slice < m_depth);
 
-//==============================================================================
-void TextureImpl::bind(U32 unit) const
-{
-	ANKI_ASSERT(isCreated());
-	glActiveTexture(GL_TEXTURE0 + unit);
-	glBindTexture(m_target, m_glName);
+		if(!m_compressed)
+		{
+			glTexSubImage3D(
+				m_target,
+				mipmap,
+				0,
+				0,
+				slice,
+				w,
+				h,
+				slice + 1,
+				m_format,
+				m_type,
+				data);
+		}
+		else
+		{
+			glCompressedTexSubImage3D(
+				m_target,
+				mipmap,
+				0,
+				0,
+				slice,
+				w,
+				h,
+				slice + 1,
+				m_format,
+				dataSize,
+				data);
+		}
+		break;
+	default:
+		ANKI_ASSERT(0);
+	}
 }
 
 //==============================================================================
 void TextureImpl::generateMipmaps()
 {
 	ANKI_ASSERT(!m_compressed);
-	bind(0);
+	bind();
 	glGenerateMipmap(m_target);
 }
 

+ 0 - 164
src/gr/gl/TexturePtr.cpp

@@ -1,164 +0,0 @@
-// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#include "anki/gr/TexturePtr.h"
-#include "anki/gr/gl/TextureImpl.h"
-#include "anki/gr/GrManager.h"
-#include "anki/gr/gl/CommandBufferImpl.h"
-#include "anki/gr/CommandBufferPtr.h"
-
-namespace anki {
-
-//==============================================================================
-// Texture commands                                                            =
-//==============================================================================
-
-//==============================================================================
-class CreateTextureCommand: public GlCommand
-{
-public:
-	TexturePtr m_tex;
-	TexturePtr::Initializer m_init;
-	Bool8 m_cleanup = false;
-
-	CreateTextureCommand(
-		TexturePtr tex,
-		const TexturePtr::Initializer& init,
-		Bool cleanup)
-	:	m_tex(tex),
-		m_init(init),
-		m_cleanup(cleanup)
-	{}
-
-	Error operator()(CommandBufferImpl* cmdb)
-	{
-		ANKI_ASSERT(cmdb);
-
-		m_tex.get().create(m_init);
-
-		GlObject::State oldState = m_tex.get().setStateAtomically(
-			GlObject::State::CREATED);
-		ANKI_ASSERT(oldState == GlObject::State::TO_BE_CREATED);
-		(void)oldState;
-
-		if(m_cleanup)
-		{
-			for(U layer = 0; layer < MAX_TEXTURE_LAYERS; ++layer)
-			{
-				for(U level = 0; level < MAX_MIPMAPS; ++level)
-				{
-					SurfaceData& surf = m_init.m_data[level][layer];
-					if(surf.m_ptr)
-					{
-						cmdb->getInternalAllocator().deallocate(
-							const_cast<void*>(surf.m_ptr), 1);
-					}
-				}
-			}
-		}
-
-		return ErrorCode::NONE;
-	}
-};
-
-//==============================================================================
-class BindTextureCommand: public GlCommand
-{
-public:
-	TexturePtr m_tex;
-	U32 m_unit;
-
-	BindTextureCommand(TexturePtr& tex, U32 unit)
-	:	m_tex(tex),
-		m_unit(unit)
-	{}
-
-	Error operator()(CommandBufferImpl*)
-	{
-		m_tex.get().bind(m_unit);
-		return ErrorCode::NONE;
-	}
-};
-
-//==============================================================================
-class GenMipmapsCommand: public GlCommand
-{
-public:
-	TexturePtr m_tex;
-
-	GenMipmapsCommand(TexturePtr& tex)
-	:	m_tex(tex)
-	{}
-
-	Error operator()(CommandBufferImpl*)
-	{
-		m_tex.get().generateMipmaps();
-		return ErrorCode::NONE;
-	}
-};
-
-//==============================================================================
-// TexturePtr                                                               =
-//==============================================================================
-
-//==============================================================================
-TexturePtr::TexturePtr()
-{}
-
-//==============================================================================
-TexturePtr::~TexturePtr()
-{}
-
-//==============================================================================
-void TexturePtr::create(
-	CommandBufferPtr& commands, const Initializer& initS)
-{
-	ANKI_ASSERT(!isCreated());
-	Initializer init(initS);
-
-	// Copy data to temp buffers
-	if(init.m_copyDataBeforeReturn)
-	{
-		for(U layer = 0; layer < MAX_TEXTURE_LAYERS; ++layer)
-		{
-			for(U level = 0; level < MAX_MIPMAPS; ++level)
-			{
-				SurfaceData& surf = init.m_data[level][layer];
-				if(surf.m_ptr)
-				{
-					void* newData = commands.get().getInternalAllocator().
-						allocate(surf.m_size);
-
-					memcpy(newData, surf.m_ptr, surf.m_size);
-					surf.m_ptr = newData;
-				}
-			}
-		}
-	}
-
-	Base::create(commands.get().getManager());
-	get().setStateAtomically(GlObject::State::TO_BE_CREATED);
-
-	// Fire the command
-	commands.get().pushBackNewCommand<CreateTextureCommand>(
-		*this, init, init.m_copyDataBeforeReturn);
-}
-
-//==============================================================================
-void TexturePtr::bind(CommandBufferPtr& commands, U32 unit)
-{
-	ANKI_ASSERT(isCreated());
-	commands.get().pushBackNewCommand<BindTextureCommand>(*this, unit);
-}
-
-//==============================================================================
-void TexturePtr::generateMipmaps(CommandBufferPtr& commands)
-{
-	ANKI_ASSERT(isCreated());
-	commands.get().pushBackNewCommand<GenMipmapsCommand>(*this);
-}
-
-} // end namespace anki
-

+ 1 - 1
thirdparty

@@ -1 +1 @@
-Subproject commit e127f60dd2e58fd88b4bc66b8e2fd6577ba72bb1
+Subproject commit ae3f414a0bfbd4877733f7488e85270989d74631