Panagiotis Christopoulos Charitos 10 лет назад
Родитель
Сommit
e72e7068c2

+ 1 - 1
include/anki/gr/BufferHandle.h

@@ -39,7 +39,7 @@ public:
 	/// Write data to the buffer
 	void write(
 		CommandBufferHandle& commands, 
-		ClientBufferHandle& data, PtrSize readOffset,
+		const void* data, PtrSize dataSize, PtrSize readOffset,
 		PtrSize writeOffset, PtrSize size);
 
 	/// Bind to the state as uniform/shader storage buffer

+ 4 - 6
include/anki/gr/GrHandle.h

@@ -110,17 +110,15 @@ public:
 	///                object. Some objects example may require deferred 
 	///                deleters.
 	template<typename TDeleter>
-	ANKI_USE_RESULT Error create(GrManager* manager, TDeleter del)
+	ANKI_USE_RESULT Error create(GrManager& manager, TDeleter del)
 	{
-		ANKI_ASSERT(manager);
-
 		using Cb = CtrlBlock<TDeleter>;
 
 		Error err = ErrorCode::NONE;
 
 		// Create the object
-		auto alloc = manager->getAllocator();
-		T* ptr = alloc.template newInstance<T>(manager);
+		auto alloc = manager.getAllocator();
+		T* ptr = alloc.template newInstance<T>(&manager);
 
 		if(ptr != nullptr)
 		{
@@ -201,7 +199,7 @@ private:
 		void deletePtr()
 		{
 			// Delete object
-			m_del(Base::m_ptr);
+			m_del(static_cast<T*>(Base::m_ptr));
 		}
 	};
 

+ 1 - 1
include/anki/gr/TextureHandle.h

@@ -10,7 +10,7 @@
 
 namespace anki {
 
-/// @addtogroup opengl_containers
+/// @addtogroup graphics
 /// @{
 
 /// Texture handle

+ 2 - 2
include/anki/gr/gl/BufferImpl.h

@@ -90,7 +90,7 @@ public:
 
 	/// Write data to buffer. 
 	/// @param[in] buff The buffer to copy to BO
-	void write(void* buff)
+	void write(const void* buff)
 	{
 		write(buff, 0, m_size);
 	}
@@ -99,7 +99,7 @@ public:
 	/// @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(void* buff, U32 offset, U32 size);
+	void write(const void* buff, U32 offset, U32 size);
 
 	/// Set the binding for this buffer
 	void setBinding(GLuint binding) const;

+ 13 - 8
include/anki/gr/gl/DeferredDeleter.h

@@ -6,8 +6,11 @@
 #ifndef ANKI_GR_GL_DEFERRED_DELETER_H
 #define ANKI_GR_GL_DEFERRED_DELETER_H
 
-#include "anki/gr/GlDevice.h"
+#include "anki/gr/GrManager.h"
 #include "anki/gr/CommandBufferHandle.h"
+#include "anki/gr/gl/CommandBufferImpl.h"
+#include "anki/gr/gl/RenderingThread.h"
+#include "anki/gr/gl/GrManagerImpl.h"
 
 namespace anki {
 
@@ -19,25 +22,26 @@ namespace anki {
 /// get deleted in the server thread (where the context is). This deleter will
 /// fire a server command with the deletion if the handle gets realeased thread 
 /// other than the server thread.
-template<typename T, typename TAlloc, typename TDeleteCommand>
+template<typename T, typename TDeleteCommand>
 class DeferredDeleter
 {
 public:
-	void operator()(T* obj, TAlloc alloc, GlDevice* manager)
+	void operator()(T* obj)
 	{
 		ANKI_ASSERT(obj);
-		ANKI_ASSERT(manager);
+		GrManager& manager = obj->getManager();
+		const RenderingThread& thread = 
+			manager.getImplementation().getRenderingThread();
 		
 		/// If not the server thread then create a command for the server thread
-		if(!manager->_getRenderingThread().isServerThread())
+		if(!thread.isServerThread())
 		{
 			CommandBufferHandle commands;
 			
-			Error err = commands.create(manager);
+			Error err = commands.create(&manager);
 			if(!err)
 			{
-				commands.template _pushBackNewCommand<TDeleteCommand>(
-					obj, alloc);
+				commands.get().template pushBackNewCommand<TDeleteCommand>(obj);
 				commands.flush();
 			}
 			else
@@ -47,6 +51,7 @@ public:
 		}
 		else
 		{
+			auto alloc = obj->getAllocator();
 			alloc.deleteInstance(obj);
 		}
 	}

+ 2 - 12
include/anki/gr/gl/GlObject.h

@@ -56,19 +56,9 @@ public:
 		return m_glName != 0;
 	}
 
-	State getStateAtomically(State* newVal)
+	State setStateAtomically(State newVal)
 	{
-		State crntVal;
-		if(newVal)
-		{
-			I32 newValI32 = I32(*newVal);
-			crntVal = State(m_state.exchange(newValI32));
-		}
-		else
-		{
-			crntVal = State(m_state.load());
-		}
-		return crntVal;
+		return State(m_state.exchange(I32(newVal)));
 	}
 
 	/// Check if the object has been created and if not serialize the thread.

+ 154 - 168
src/gr/gl/BufferHandle.cpp

@@ -4,12 +4,16 @@
 // http://www.anki3d.org/LICENSE
 
 #include "anki/gr/BufferHandle.h"
-#include "anki/gr/gl/HandleDeferredDeleter.h"
+#include "anki/gr/gl/DeferredDeleter.h"
 #include "anki/gr/gl/BufferImpl.h"
 #include "anki/gr/GrManager.h"
 
 namespace anki {
 
+//==============================================================================
+// Commands                                                                    =
+//==============================================================================
+
 //==============================================================================
 /// Create buffer command
 class BufferCreateCommand: public GlCommand
@@ -22,7 +26,7 @@ public:
 	GLbitfield m_flags;
 
 	BufferCreateCommand(
-		BufferHandle buff, GLenum target, const void* data, PtrSize size
+		BufferHandle buff, GLenum target, const void* data, PtrSize size,
 		GLenum flags)
 	:	m_buff(buff), 
 		m_target(target), 
@@ -31,14 +35,14 @@ public:
 		m_flags(flags)
 	{}
 
-	Error operator()(CommandBufferImpl*)
+	Error operator()(CommandBufferImpl*) final
 	{
 		Error err = ErrorCode::NONE;
 
 		err = m_buff.get().create(m_target, m_data, m_size, m_flags);
 
-		GlObject::State oldState = m_buff.get().getStateAtomically(
-			(err) ? GlHandleState::ERROR : GlHandleState::CREATED);
+		GlObject::State oldState = m_buff.get().setStateAtomically(
+			(err) ? GlObject::State::ERROR : GlObject::State::CREATED);
 
 		(void)oldState;
 		ANKI_ASSERT(oldState == GlObject::State::TO_BE_CREATED);
@@ -48,68 +52,164 @@ public:
 };
 
 //==============================================================================
-BufferHandle::BufferHandle()
-{}
+class BufferWriteCommand: public GlCommand
+{
+public:
+	BufferHandle m_buff;
+	const void* m_data;
+	PtrSize m_dataSize;
+	PtrSize m_readOffset;
+	PtrSize m_writeOffset;
+	PtrSize m_size;
+
+	BufferWriteCommand(BufferHandle& 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*) 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);
+
+		return ErrorCode::NONE;
+	}
+};
 
 //==============================================================================
-BufferHandle::~BufferHandle()
-{}
+class BufferBindVertexCommand: public GlCommand
+{
+public:
+	BufferHandle m_buff;
+	U32 m_elementSize;
+	GLenum m_type;
+	Bool8 m_normalized;
+	U32 m_stride;
+	U32 m_offset;
+	U32 m_attribLocation;
+
+	BufferBindVertexCommand(BufferHandle& 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;
+	}
+};
 
 //==============================================================================
-Error BufferHandle::create(CommandBufferHandle& commands,
-	GLenum target, ClientBufferHandle& data, GLenum flags)
+class BindShaderBufferCommand: public GlCommand
 {
-	ANKI_ASSERT(!isCreated());
+public:
+	BufferHandle m_buff;
+	I32 m_offset;
+	I32 m_size;
+	U8 m_binding;
+
+	BindShaderBufferCommand(BufferHandle& 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();
 
-	using Alloc = GlAllocator<BufferImpl>;
+		m_buff.get().setBindingRange(m_binding, offset, size);
 
-	using DeleteCommand = 
-		GlDeleteObjectCommand<BufferImpl, GlAllocator<U8>>;
+		return ErrorCode::NONE;
+	}
+};
 
-	using Deleter = GlHandleDeferredDeleter<BufferImpl, Alloc, DeleteCommand>;
+//==============================================================================
+class BindIndexBufferCommand: public GlCommand
+{
+public:
+	BufferHandle m_buff;
 
-	Error err = _createAdvanced(
-		&commands._getRenderingThread().getDevice(),
-		commands._getRenderingThread().getDevice()._getAllocator(), 
-		Deleter());
+	BindIndexBufferCommand(BufferHandle& buff)
+	:	m_buff(buff)
+	{}
 
-	if(!err)
+	Error operator()(CommandBufferImpl*)
 	{
-		_setState(GlHandleState::TO_BE_CREATED);
+		BufferImpl& buff = m_buff.get();
+		buff.setTarget(GL_ELEMENT_ARRAY_BUFFER);
+		buff.bind();
 
-		// Fire the command
-		commands._pushBackNewCommand<BufferCreateCommand>(
-			*this, target, data, flags);
+		return ErrorCode::NONE;
 	}
+};
 
-	return err;
-}
+//==============================================================================
+// BufferHandle                                                                =
+//==============================================================================
+
+//==============================================================================
+BufferHandle::BufferHandle()
+{}
+
+//==============================================================================
+BufferHandle::~BufferHandle()
+{}
 
 //==============================================================================
 Error BufferHandle::create(CommandBufferHandle& commands,
-	GLenum target, PtrSize size, GLenum flags)
+	GLenum target, const void* data, PtrSize size, GLenum flags)
 {
 	ANKI_ASSERT(!isCreated());
 
-	using Alloc = GlAllocator<BufferImpl>;
-
-	using DeleteCommand = 
-		GlDeleteObjectCommand<BufferImpl, GlAllocator<U8>>;
+	using DeleteCommand = DeleteObjectCommand<BufferImpl>;
 
-	using Deleter = GlHandleDeferredDeleter<BufferImpl, Alloc, DeleteCommand>;
-
-	Error err = _createAdvanced(
-		&commands._getRenderingThread().getDevice(),
-		commands._getRenderingThread().getDevice()._getAllocator(), 
-		Deleter());
+	using Deleter = DeferredDeleter<BufferImpl, DeleteCommand>;
 
+	Error err = Base::create(commands.get().getManager(), Deleter());
 	if(!err)
 	{
-		_setState(GlHandleState::TO_BE_CREATED);
-		
+		get().setStateAtomically(GlObject::State::TO_BE_CREATED);
+
 		// Fire the command
-		commands._pushBackNewCommand<BufferCreateCommand>(
-			*this, target, size, flags);
+		commands.get().pushBackNewCommand<BufferCreateCommand>(
+			*this, target, data, size, flags);
 	}
 
 	return err;
@@ -117,71 +217,21 @@ Error BufferHandle::create(CommandBufferHandle& commands,
 
 //==============================================================================
 void BufferHandle::write(CommandBufferHandle& commands, 
-	ClientBufferHandle& data, PtrSize readOffset, PtrSize writeOffset, 
+	const void* data, PtrSize dataSize, PtrSize readOffset, PtrSize writeOffset, 
 	PtrSize size)
 {
-	class Command: public GlCommand
-	{
-	public:
-		BufferHandle m_buff;
-		ClientBufferHandle m_data;
-		PtrSize m_readOffset;
-		PtrSize m_writeOffset;
-		PtrSize m_size;
-
-		Command(BufferHandle& buff, ClientBufferHandle& data, 
-			PtrSize readOffset, PtrSize writeOffset, PtrSize size)
-			:	m_buff(buff), m_data(data), m_readOffset(readOffset), 
-				m_writeOffset(writeOffset), m_size(size)
-		{}
-
-		Error operator()(CommandBufferImpl*)
-		{
-			ANKI_ASSERT(m_readOffset + m_size <= m_data.getSize());
-
-			m_buff._get().write(
-				(U8*)m_data.getBaseAddress() + m_readOffset, 
-				m_writeOffset, 
-				m_size);
-
-			return ErrorCode::NONE;
-		}
-	};
-
 	ANKI_ASSERT(isCreated());
-	commands._pushBackNewCommand<Command>(
-		*this, data, readOffset, writeOffset, size);
+	commands.get().pushBackNewCommand<BufferWriteCommand>(
+		*this, data, dataSize, readOffset, writeOffset, size);
 }
 
 //==============================================================================
 void BufferHandle::bindShaderBufferInternal(CommandBufferHandle& commands,
 	I32 offset, I32 size, U32 bindingPoint)
 {
-	class Command: public GlCommand
-	{
-	public:
-		BufferHandle m_buff;
-		I32 m_offset;
-		I32 m_size;
-		U8 m_binding;
-
-		Command(BufferHandle& buff, I32 offset, I32 size, U8 binding)
-			: m_buff(buff), m_offset(offset), m_size(size), m_binding(binding)
-		{}
-
-		Error operator()(CommandBufferImpl*)
-		{
-			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;
-		}
-	};
-
 	ANKI_ASSERT(isCreated());
-	commands._pushBackNewCommand<Command>(*this, offset, size, bindingPoint);
+	commands.get().pushBackNewCommand<BindShaderBufferCommand>(
+		*this, offset, size, bindingPoint);
 }
 
 //==============================================================================
@@ -194,99 +244,35 @@ void BufferHandle::bindVertexBuffer(
 	PtrSize offset,
 	U32 attribLocation)
 {
-	class Command: public GlCommand
-	{
-	public:
-		BufferHandle m_buff;
-		U32 m_elementSize;
-		GLenum m_type;
-		Bool8 m_normalized;
-		U32 m_stride;
-		U32 m_offset;
-		U32 m_attribLocation;
-
-		Command(BufferHandle& 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;
-		}
-	};
-
 	ANKI_ASSERT(isCreated());
-	commands._pushBackNewCommand<Command>(*this, elementSize, type, 
-		normalized, stride, offset, attribLocation);
+	commands.get().pushBackNewCommand<BufferBindVertexCommand>(
+		*this, elementSize, type, normalized, stride, offset, attribLocation);
 }
 
 //==============================================================================
 void BufferHandle::bindIndexBuffer(CommandBufferHandle& commands)
 {
-	class Command: public GlCommand
-	{
-	public:
-		BufferHandle m_buff;
-
-		Command(BufferHandle& buff)
-		:	m_buff(buff)
-		{}
-
-		Error operator()(CommandBufferImpl*)
-		{
-			BufferImpl& buff = m_buff._get();
-			buff.setTarget(GL_ELEMENT_ARRAY_BUFFER);
-			buff.bind();
-
-			return ErrorCode::NONE;
-		}
-	};
-
 	ANKI_ASSERT(isCreated());
-	commands._pushBackNewCommand<Command>(*this);
+	commands.get().pushBackNewCommand<BindIndexBufferCommand>(*this);
 }
 
 //==============================================================================
 PtrSize BufferHandle::getSize() const
 {
-	return (serializeOnGetter()) ? 0 : _get().getSize();
+	return (get().serializeOnGetter()) ? 0 : get().getSize();
 }
 
 //==============================================================================
 GLenum BufferHandle::getTarget() const
 {
-	return (serializeOnGetter()) ? GL_NONE : _get().getTarget();
+	return (get().serializeOnGetter()) ? GL_NONE : get().getTarget();
 }
 
 //==============================================================================
 void* BufferHandle::getPersistentMappingAddress()
 {
-	return 
-		(serializeOnGetter()) ? nullptr : _get().getPersistentMappingAddress();
+	return (get().serializeOnGetter()) 
+		? nullptr : get().getPersistentMappingAddress();
 }
 
 } // end namespace anki

+ 1 - 1
src/gr/gl/BufferImpl.cpp

@@ -88,7 +88,7 @@ Error BufferImpl::create(GLenum target, const void* dataPtr,
 }
 
 //==============================================================================
-void BufferImpl::write(void* buff, U32 offset, U32 size)
+void BufferImpl::write(const void* buff, U32 offset, U32 size)
 {
 	ANKI_ASSERT(isCreated());
 	ANKI_ASSERT(offset + size <= size);

+ 219 - 271
src/gr/gl/TextureHandle.cpp

@@ -5,11 +5,126 @@
 
 #include "anki/gr/TextureHandle.h"
 #include "anki/gr/gl/TextureImpl.h"
-#include "anki/gr/GlDevice.h"
-#include "anki/gr/GlHandleDeferredDeleter.h"	
+#include "anki/gr/GrManager.h"
+#include "anki/gr/gl/DeferredDeleter.h"	
 
 namespace anki {
 
+//==============================================================================
+// Texture commands                                                            =
+//==============================================================================
+
+//==============================================================================
+class CreateTextureCommand: public GlCommand
+{
+public:
+	TextureHandle m_tex;
+	TextureHandle::Initializer m_init;
+
+	CreateTextureCommand(
+		TextureHandle tex, 
+		const TextureHandle::Initializer& init)
+	:	m_tex(tex), 
+		m_init(init)
+	{}
+
+	Error operator()(CommandBufferImpl* commands)
+	{
+		ANKI_ASSERT(commands);
+		TextureImpl::Initializer init;
+
+		static_cast<GlTextureInitializerBase&>(init) = m_init;
+
+		U layers = 0;
+		switch(m_init.m_target)
+		{
+		case GL_TEXTURE_CUBE_MAP:
+			layers = 6;
+			break;
+		case GL_TEXTURE_2D_ARRAY:
+		case GL_TEXTURE_3D:
+			layers = m_init.m_depth;
+			break;
+		case GL_TEXTURE_2D:
+		case GL_TEXTURE_2D_MULTISAMPLE:
+			layers = 1;
+			break;
+		default:
+			ANKI_ASSERT(0);
+		}
+
+		auto alloc = commands->getAllocator();
+
+		Error err = m_tex.get().create(init);
+
+		GlHandleState oldState = m_tex.get().setStateAtomically(
+			(err) ? GlObject::State::ERROR : GlObject::State::CREATED);
+		ANKI_ASSERT(oldState == GlObject::State::TO_BE_CREATED);
+		(void)oldState;
+
+		return err;
+	}
+};
+
+//==============================================================================
+class BindTextureCommand: public GlCommand
+{
+public:
+	TextureHandle m_tex;
+	U32 m_unit;
+
+	BindTextureCommand(TextureHandle& tex, U32 unit)
+	:	m_tex(tex), 
+		m_unit(unit)
+	{}
+
+	Error operator()(CommandBufferImpl*)
+	{
+		m_tex.get().bind(m_unit);
+		return ErrorCode::NONE;
+	}
+};
+
+//==============================================================================
+class SetFilterCommand: public GlCommand
+{
+public:
+	TextureHandle m_tex;
+	TextureImpl::Filter m_filter;
+
+	SetFilterCommand(TextureHandle tex, TextureImpl::Filter filter)
+	:	m_tex(tex), 
+		m_filter(filter)
+	{}
+
+	Error operator()(CommandBufferImpl*)
+	{
+		m_tex.get().setFilter(m_filter);
+		return ErrorCode::NONE;
+	}
+};
+
+//==============================================================================
+class SetParameterCommand: public GlCommand
+{
+public:
+	TextureHandle m_tex;
+	GLenum m_param;
+	GLint m_value;
+
+	SetParameterCommand(TextureHandle& tex, GLenum param, GLint value)
+	:	m_tex(tex), 
+		m_param(param), 
+		m_value(value)
+	{}
+
+	Error operator()(CommandBufferImpl*)
+	{
+		m_tex.get().setParameter(m_param, m_value);
+		return ErrorCode::NONE;
+	}
+};
+
 //==============================================================================
 // TextureHandle                                                               =
 //==============================================================================
@@ -26,97 +141,19 @@ TextureHandle::~TextureHandle()
 Error TextureHandle::create(
 	CommandBufferHandle& commands, const Initializer& init)
 {
-	class Command: public GlCommand
-	{
-	public:
-		TextureHandle m_tex;
-		TextureHandle::Initializer m_init;
-
-		Command(
-			TextureHandle tex, 
-			const TextureHandle::Initializer& init)
-		:	m_tex(tex), 
-			m_init(init)
-		{}
-
-		Error operator()(CommandBufferImpl* commands)
-		{
-			ANKI_ASSERT(commands);
-			TextureImpl::Initializer init;
-
-			static_cast<GlTextureInitializerBase&>(init) = m_init;
-
-			U layers = 0;
-			switch(m_init.m_target)
-			{
-			case GL_TEXTURE_CUBE_MAP:
-				layers = 6;
-				break;
-			case GL_TEXTURE_2D_ARRAY:
-			case GL_TEXTURE_3D:
-				layers = m_init.m_depth;
-				break;
-			case GL_TEXTURE_2D:
-			case GL_TEXTURE_2D_MULTISAMPLE:
-				layers = 1;
-				break;
-			default:
-				ANKI_ASSERT(0);
-			}
-
-			for(U level = 0; level < m_init.m_mipmapsCount; level++)
-			{
-				for(U layer = 0; layer < layers; ++layer)
-				{
-					auto& buff = m_init.m_data[level][layer];
-					auto& initBuff = init.m_data[level][layer];
-
-					if(buff.isCreated())
-					{
-						initBuff.m_ptr = buff.getBaseAddress();
-						initBuff.m_size = buff.getSize();
-					}
-					else
-					{
-						initBuff.m_ptr = nullptr;
-						initBuff.m_size = 0;
-					}
-				}
-			}
-
-			auto alloc = commands->getGlobalAllocator();
-
-			Error err = m_tex._get().create(init, alloc);
-
-			GlHandleState oldState = m_tex._setState(
-				(err) ? GlHandleState::ERROR : GlHandleState::CREATED);
-			ANKI_ASSERT(oldState == GlHandleState::TO_BE_CREATED);
-			(void)oldState;
-
-			return err;
-		}
-	};
-
 	ANKI_ASSERT(!isCreated());
 
-	using Alloc = GlAllocator<TextureImpl>;
-
-	using DeleteCommand = 
-		GlDeleteObjectCommand<TextureImpl, Alloc>;
-
-	using Deleter = GlHandleDeferredDeleter<TextureImpl, Alloc, DeleteCommand>;
+	using DeleteCommand = DeleteObjectCommand<TextureImpl>;
 
-	Error err = _createAdvanced(
-		&commands._getRenderingThread().getDevice(),
-		commands._getRenderingThread().getDevice()._getAllocator(), 
-		Deleter());
+	using Deleter = DeferredDeleter<TextureImpl, DeleteCommand>;
 
+	Error err = Base::(&commands.get().getManager(), Deleter());
 	if(!err)
 	{
-		_setState(GlHandleState::TO_BE_CREATED);
+		get().setStateAtomically(GlObject::State::TO_BE_CREATED);
 
 		// Fire the command
-		commands._pushBackNewCommand<Command>(*this, init);
+		commands.get().pushBackNewCommand<CreateTextureCommand>(*this, init);
 	}
 
 	return err;
@@ -125,49 +162,13 @@ Error TextureHandle::create(
 //==============================================================================
 void TextureHandle::bind(CommandBufferHandle& commands, U32 unit)
 {
-	class Command: public GlCommand
-	{
-	public:
-		TextureHandle m_tex;
-		U32 m_unit;
-
-		Command(TextureHandle& tex, U32 unit)
-		:	m_tex(tex), 
-			m_unit(unit)
-		{}
-
-		Error operator()(CommandBufferImpl*)
-		{
-			m_tex._get().bind(m_unit);
-			return ErrorCode::NONE;
-		}
-	};
-
 	ANKI_ASSERT(isCreated());
-	commands._pushBackNewCommand<Command>(*this, unit);
+	commands.get().pushBackNewCommand<BindTextureCommand>(*this, unit);
 }
 
 //==============================================================================
 void TextureHandle::setFilter(CommandBufferHandle& commands, Filter filter)
 {
-	class Command: public GlCommand
-	{
-	public:
-		TextureHandle m_tex;
-		TextureImpl::Filter m_filter;
-
-		Command(TextureHandle tex, TextureImpl::Filter filter)
-		:	m_tex(tex), 
-			m_filter(filter)
-		{}
-
-		Error operator()(CommandBufferImpl*)
-		{
-			m_tex._get().setFilter(m_filter);
-			return ErrorCode::NONE;
-		}
-	};
-
 	ANKI_ASSERT(isCreated());
 	commands._pushBackNewCommand<Command>(*this, filter);
 }
@@ -175,24 +176,8 @@ void TextureHandle::setFilter(CommandBufferHandle& commands, Filter filter)
 //==============================================================================
 void TextureHandle::generateMipmaps(CommandBufferHandle& commands)
 {
-	class Command: public GlCommand
-	{
-	public:
-		TextureHandle m_tex;
-
-		Command(TextureHandle tex)
-		:	m_tex(tex)
-		{}
-
-		Error operator()(CommandBufferImpl*)
-		{
-			m_tex._get().generateMipmaps();
-			return ErrorCode::NONE;
-		}
-	};
-
 	ANKI_ASSERT(isCreated());
-	commands._pushBackNewCommand<Command>(*this);
+	commands.get().pushBackNewCommand<SetFilterCommand>(*this);
 }
 
 //==============================================================================
@@ -200,85 +185,119 @@ void TextureHandle::setParameter(CommandBufferHandle& commands,
 	GLenum param, GLint value)
 {
 	ANKI_ASSERT(isCreated());
-
-	class Command: public GlCommand
-	{
-	public:
-		TextureHandle m_tex;
-		GLenum m_param;
-		GLint m_value;
-
-		Command(TextureHandle& tex, GLenum param, GLint value)
-		:	m_tex(tex), 
-			m_param(param), 
-			m_value(value)
-		{}
-
-		Error operator()(CommandBufferImpl*)
-		{
-			m_tex._get().setParameter(m_param, m_value);
-			return ErrorCode::NONE;
-		}
-	};
-
-	ANKI_ASSERT(isCreated());
-	commands._pushBackNewCommand<Command>(*this, param, value);
+	commands.get().pushBackNewCommand<SetParameterCommand>(*this, param, value);
 }
 
 //==============================================================================
-// SamplerHandle                                                               =
+// SamplerCommands                                                             =
 //==============================================================================
 
 //==============================================================================
-SamplerHandle::SamplerHandle()
-{}
+class CreateSamplerCommand: public GlCommand
+{
+public:
+	SamplerHandle m_sampler;
 
-//==============================================================================
-SamplerHandle::~SamplerHandle()
-{}
+	CreateSamplerCommand(const SamplerHandle& sampler)
+	:	m_sampler(sampler)
+	{}
+
+	Error operator()(CommandBufferImpl* commands)
+	{
+		ANKI_ASSERT(commands);
+
+		Error err = m_sampler.get().create();
+
+		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;
+	}
+};
 
 //==============================================================================
-Error SamplerHandle::create(CommandBufferHandle& commands)
+class BindSamplerCommand: public GlCommand
 {
-	class Command: public GlCommand
-	{
-	public:
-		SamplerHandle m_sampler;
+public:
+	SamplerHandle m_sampler;
+	U32 m_unit;
 
-		Command(const SamplerHandle& sampler)
-		:	m_sampler(sampler)
-		{}
+	BindSamplerCommand(SamplerHandle& sampler, U32 unit)
+	:	m_sampler(sampler), 
+		m_unit(unit)
+	{}
 
-		Error operator()(CommandBufferImpl* commands)
-		{
-			ANKI_ASSERT(commands);
+	Error operator()(CommandBufferImpl*)
+	{
+		m_sampler.get().bind(m_unit);
+		return ErrorCode::NONE;
+	}
+};
+
+//==============================================================================
+class SetSamplerParameterCommand: public GlCommand
+{
+public:
+	SamplerHandle m_sampler;
+	GLenum m_param;
+	GLint m_value;
+
+	SetSamplerParameterCommand(SamplerHandle& sampler, 
+		GLenum param, GLint value)
+	:	m_sampler(sampler), 
+		m_param(param), 
+		m_value(value)
+	{}
+
+	Error operator()(CommandBufferImpl*)
+	{
+		m_sampler.get().setParameter(m_param, m_value);
+		return ErrorCode::NONE;
+	}
+};
 
-			Error err = m_sampler._get().create();
+//==============================================================================
+class BindDefaultSamplerCommand: public GlCommand
+{
+public:
+	U32 m_unit;
 
-			GlHandleState oldState = m_sampler._setState(
-				(err) ? GlHandleState::ERROR : GlHandleState::CREATED);
-			ANKI_ASSERT(oldState == GlHandleState::TO_BE_CREATED);
-			(void)oldState;
+	BindDefaultSamplerCommand(U32 unit)
+	:	m_unit(unit)
+	{}
 
-			return err;
-		}
-	};
+	Error operator()(CommandBufferImpl*)
+	{
+		SamplerImpl::unbind(m_unit);
+		return ErrorCode::NONE;
+	}
+};
 
-	using Alloc = GlAllocator<SamplerImpl>;
+//==============================================================================
+// SamplerHandle                                                               =
+//==============================================================================
 
-	using DeleteCommand = GlDeleteObjectCommand<SamplerImpl, Alloc>;
+//==============================================================================
+SamplerHandle::SamplerHandle()
+{}
 
-	using Deleter = GlHandleDeferredDeleter<SamplerImpl, Alloc, DeleteCommand>;
+//==============================================================================
+SamplerHandle::~SamplerHandle()
+{}
 
-	Error err = _createAdvanced(
-		&commands._getRenderingThread().getDevice(),
-		commands._getRenderingThread().getDevice()._getAllocator(), 
-		Deleter());
+//==============================================================================
+Error SamplerHandle::create(CommandBufferHandle& commands)
+{
+	using DeleteCommand = DeleteObjectCommand<SamplerImpl>;
+	using Deleter = DeferredDeleter<SamplerImpl, DeleteCommand>;
 
+	Error err = Base::create(commands.getManager(), Deleter());
 	if(!err)
 	{
-		_setState(GlHandleState::TO_BE_CREATED);
-		commands._pushBackNewCommand<Command>(*this);
+		get().setStateAtomically(GlHandleState::TO_BE_CREATED);
+		commands.get().pushBackNewCommand<CreateSamplerCommand>(*this);
 	}
 
 	return err;
@@ -287,24 +306,6 @@ Error SamplerHandle::create(CommandBufferHandle& commands)
 //==============================================================================
 void SamplerHandle::bind(CommandBufferHandle& commands, U32 unit)
 {
-	class Command: public GlCommand
-	{
-	public:
-		SamplerHandle m_sampler;
-		U32 m_unit;
-
-		Command(SamplerHandle& sampler, U32 unit)
-		:	m_sampler(sampler), 
-			m_unit(unit)
-		{}
-
-		Error operator()(CommandBufferImpl*)
-		{
-			m_sampler._get().bind(m_unit);
-			return ErrorCode::NONE;
-		}
-	};
-
 	ANKI_ASSERT(isCreated());
 	commands._pushBackNewCommand<Command>(*this, unit);
 }
@@ -312,76 +313,23 @@ void SamplerHandle::bind(CommandBufferHandle& commands, U32 unit)
 //==============================================================================
 void SamplerHandle::setFilter(CommandBufferHandle& commands, Filter filter)
 {
-	class Command: public GlCommand
-	{
-	public:
-		SamplerHandle m_sampler;
-		SamplerHandle::Filter m_filter;
-
-		Command(const SamplerHandle& sampler, SamplerHandle::Filter filter)
-		:	m_sampler(sampler), 
-			m_filter(filter)
-		{}
-
-		Error operator()(CommandBufferImpl*)
-		{
-			m_sampler._get().setFilter(m_filter);
-			return ErrorCode::NONE;
-		}
-	};
-
 	ANKI_ASSERT(isCreated());
-	commands._pushBackNewCommand<Command>(*this, filter);
+	commands.get().pushBackNewCommand<BindSamplerCommand>(*this, filter);
 }
 
 //==============================================================================
 void SamplerHandle::setParameter(
 	CommandBufferHandle& commands, GLenum param, GLint value)
 {
-	class Command: public GlCommand
-	{
-	public:
-		SamplerHandle m_sampler;
-		GLenum m_param;
-		GLint m_value;
-
-		Command(SamplerHandle& sampler, GLenum param, GLint value)
-		:	m_sampler(sampler), 
-			m_param(param), 
-			m_value(value)
-		{}
-
-		Error operator()(CommandBufferImpl*)
-		{
-			m_sampler._get().setParameter(m_param, m_value);
-			return ErrorCode::NONE;
-		}
-	};
-
 	ANKI_ASSERT(isCreated());
-	commands._pushBackNewCommand<Command>(*this, param, value);
+	commands.get().pushBackNewCommand<SetSamplerParameterCommand>(
+		*this, param, value);
 }
 
 //==============================================================================
 void SamplerHandle::bindDefault(CommandBufferHandle& commands, U32 unit)
 {
-	class Command: public GlCommand
-	{
-	public:
-		U32 m_unit;
-
-		Command(U32 unit)
-		:	m_unit(unit)
-		{}
-
-		Error operator()(CommandBufferImpl*)
-		{
-			SamplerImpl::unbind(m_unit);
-			return ErrorCode::NONE;
-		}
-	};
-
-	commands._pushBackNewCommand<Command>(unit);
+	commands.pushBackNewCommand<BindDefaultSamplerCommand>(unit);
 }
 
 } // end namespace anki