Panagiotis Christopoulos Charitos 10 лет назад
Родитель
Сommit
6eb2ecf333
38 измененных файлов с 941 добавлено и 1203 удалено
  1. 0 45
      include/anki/gr/ClientBufferHandle.h
  2. 0 99
      include/anki/gr/ClientBufferImpl.h
  3. 13 39
      include/anki/gr/CommandBufferHandle.h
  4. 30 9
      include/anki/gr/Common.h
  5. 0 55
      include/anki/gr/GlContainerHandle.h
  6. 0 86
      include/anki/gr/GlDevice.h
  7. 0 397
      include/anki/gr/GlHandle.h
  8. 0 36
      include/anki/gr/GlSync.h
  9. 0 45
      include/anki/gr/GlSyncHandles.h
  10. 235 0
      include/anki/gr/GrHandle.h
  11. 96 0
      include/anki/gr/GrManager.h
  12. 55 0
      include/anki/gr/GrObject.h
  13. 2 1
      include/anki/gr/gl/BufferImpl.h
  14. 33 59
      include/anki/gr/gl/CommandBufferImpl.h
  15. 4 4
      include/anki/gr/gl/DeferredDeleter.h
  16. 3 5
      include/anki/gr/gl/Error.h
  17. 38 4
      include/anki/gr/gl/GlObject.h
  18. 51 0
      include/anki/gr/gl/GrManagerImpl.h
  19. 8 7
      include/anki/gr/gl/RenderingThread.h
  20. 4 4
      include/anki/gr/gl/State.h
  21. 211 0
      include/anki/util/HashMap.h
  22. 0 64
      src/gr/ClientBufferHandle.cpp
  23. 0 0
      src/gr/Common.cpp
  24. 0 102
      src/gr/GlDevice.cpp
  25. 0 71
      src/gr/GlSyncHandles.cpp
  26. 4 4
      src/gr/GrObject.cpp
  27. 4 4
      src/gr/gl/BufferHandle.cpp
  28. 2 2
      src/gr/gl/BufferImpl.cpp
  29. 6 7
      src/gr/gl/CommandBufferHandle.cpp
  30. 9 19
      src/gr/gl/CommandBufferImpl.cpp
  31. 0 0
      src/gr/gl/Error.cpp
  32. 1 1
      src/gr/gl/FramebufferHandle.cpp
  33. 40 0
      src/gr/gl/GlObject.cpp
  34. 46 0
      src/gr/gl/GrManagerImpl.cpp
  35. 2 2
      src/gr/gl/PipelineHandle.cpp
  36. 37 25
      src/gr/gl/RenderingThread.cpp
  37. 3 3
      src/gr/gl/ShaderHandle.cpp
  38. 4 4
      src/gr/gl/TextureHandle.cpp

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

@@ -1,45 +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_GL_GL_CLIENT_BUFFER_HANDLE_H
-#define ANKI_GL_GL_CLIENT_BUFFER_HANDLE_H
-
-#include "anki/gr/GlHandle.h"
-
-namespace anki {
-
-/// @addtogroup opengl_other
-/// @{
-
-/// Client buffer handle
-class ClientBufferHandle: public GlHandle<ClientBufferImpl>
-{
-public:
-	using Base = GlHandle<ClientBufferImpl>;
-
-	ClientBufferHandle();
-
-	~ClientBufferHandle();
-
-	/// Create the buffer using preallocated memory or memory from the chain
-	/// @param chain The command buffer this client memory belongs to
-	/// @param size The size of the buffer
-	/// @param preallocatedMem Preallocated memory. Can be nullptr
-	/// @return The address of the new memory
-	ANKI_USE_RESULT Error create(
-		CommandBufferHandle& chain, PtrSize size, void* preallocatedMem);
-
-	/// Get the base address
-	void* getBaseAddress();
-
-	/// Get size
-	PtrSize getSize() const;
-};
-
-/// @}
-
-} // end namespace anki
-
-#endif

+ 0 - 99
include/anki/gr/ClientBufferImpl.h

@@ -1,99 +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_CLIENT_BUFFER_IMPL_H
-#define ANKI_GR_CLIENT_BUFFER_IMPL_H
-
-#include "anki/gr/GlCommon.h"
-#include <memory>
-
-namespace anki {
-
-/// @addtogroup opengl_private
-/// @{
-
-/// A client buffer used to pass data to and from the server
-class ClientBufferImpl: public NonCopyable
-{
-public:
-	/// Default constructor
-	ClientBufferImpl()
-	{}
-
-	~ClientBufferImpl()
-	{
-		destroy();
-	}
-
-	/// Create the buffer and allocate memory for the chain's allocator
-	ANKI_USE_RESULT Error create(
-		const GlCommandBufferAllocator<U8>& chainAlloc, PtrSize size)
-	{
-		ANKI_ASSERT(size > 0);
-
-		m_alloc = chainAlloc;
-		m_ptr = m_alloc.allocate(size);
-		m_size = size;
-		m_preallocated = false;
-
-		return ErrorCode::NONE;
-	}
-
-	/// Create the buffer using preallocated memory
-	ANKI_USE_RESULT Error create(void* preallocatedMem, PtrSize size)
-	{
-		ANKI_ASSERT(size > 0);
-		m_ptr = preallocatedMem;
-		m_size = size;
-		m_preallocated = true;
-
-		return ErrorCode::NONE;
-	}
-
-	/// Return the base address
-	void* getBaseAddress()
-	{
-		ANKI_ASSERT(m_size > 0 && m_ptr != 0);
-		return m_ptr;
-	}
-
-	/// Get size of buffer
-	PtrSize getSize() const 
-	{
-		ANKI_ASSERT(m_size > 0);
-		return m_size;
-	}
-
-	/// Return the allocator
-	GlCommandBufferAllocator<U8> getAllocator() const
-	{
-		ANKI_ASSERT(!m_preallocated);
-		return m_alloc;
-	}
-
-private:
-	void* m_ptr = nullptr;
-	U32 m_size = 0;
-	GlCommandBufferAllocator<U8> m_alloc;
-	Bool8 m_preallocated;
-
-	void destroy()
-	{
-		if(!m_preallocated && m_ptr)
-		{
-			ANKI_ASSERT(m_size > 0);
-			m_alloc.deallocate(m_ptr, m_size);
-
-			m_size = 0;
-			m_ptr = nullptr;
-		}
-	}
-};
-/// @}
-
-} // end namespace anki
-
-#endif
-

+ 13 - 39
include/anki/gr/CommandBufferHandle.h

@@ -6,22 +6,18 @@
 #ifndef ANKI_GR_COMMAND_BUFFER_HANDLE_H
 #define ANKI_GR_COMMAND_BUFFER_HANDLE_H
 
-#include "anki/gr/GlHandle.h"
-#include "anki/gr/gl/CommandBufferImpl.h"
+#include "anki/gr/GrHandle.h"
 
 namespace anki {
 
-// Forward
-class GlDevice;
-
-/// @addtogroup opengl_other
+/// @addtogroup graphics
 /// @{
 
 /// Command buffer handle
-class CommandBufferHandle: public GlHandle<CommandBufferImpl>
+class CommandBufferHandle: public GrHandle<CommandBufferImpl>
 {
 public:
-	using Base = GlHandle<CommandBufferImpl>;
+	using Base = GrHandle<CommandBufferImpl>;
 	using UserCallback = Error(*)(void*);
 
 	CommandBufferHandle();
@@ -29,8 +25,8 @@ public:
 	~CommandBufferHandle();
 
 	/// Create command buffer
-	ANKI_USE_RESULT Error create(GlDevice* gl, 
-		CommandBufferImplInitHints hints = CommandBufferImplInitHints());
+	ANKI_USE_RESULT Error create(GrManager* manager, 
+		CommandBufferInitHints hints = CommandBufferInitHints());
 
 	/// Add a user command at the end of the command buffer
 	void pushBackUserCommand(UserCallback callback, void* data);
@@ -45,9 +41,9 @@ public:
 	void finish();
 
 	/// Compute initialization hints
-	CommandBufferImplInitHints computeInitHints() const
+	CommandBufferInitHints computeInitHints() const
 	{
-		return _get().computeInitHints();
+		return get().computeInitHints();
 	}
 
 	/// @name State manipulation
@@ -165,39 +161,17 @@ public:
 
 	/// @privatesection
 	/// @{
-	GlCommandBufferAllocator<U8> _getAllocator() const
-	{
-		return _get().getAllocator();
-	}
-
-	GlAllocator<U8> _getGlobalAllocator() const
-	{
-		return _get().getGlobalAllocator();
-	}
-
-	Queue& _getQueue()
-	{
-		return _get().getQueue();
-	}
-
-	const Queue& _getQueue() const
-	{
-		return _get().getQueue();
-	}
 
+	// XXX
+#if 0
 	/// Add a new command to the list
 	template<typename TCommand, typename... TArgs>
-	void _pushBackNewCommand(TArgs&&... args)
+	void pushBackNewCommand(TArgs&&... args)
 	{
-		_get().template pushBackNewCommand<TCommand>(
+		get().template pushBackNewCommand<TCommand>(
 			std::forward<TArgs>(args)...);
 	}
-
-	/// Execute all commands
-	ANKI_USE_RESULT Error _executeAllCommands()
-	{
-		return _get().executeAllCommands();
-	}
+#endif
 	/// @}
 };
 /// @}

+ 30 - 9
include/anki/gr/GlCommon.h → include/anki/gr/Common.h

@@ -51,18 +51,43 @@ class ClientBufferImpl;
 class ClientBufferHandle;
 class CommandBufferImpl;
 class CommandBufferHandle;
-class Queue;
+class RenderingThread;
+class GrManager;
+class GrManagerImpl;
 
-/// @addtogroup opengl_private
+/// @addtogroup graphics_private
 /// @{
 
-/// The type of the allocator of GlCommandBuffer
+/// The type of the allocator of CommandBuffer
 template<typename T>
-using GlCommandBufferAllocator = ChainAllocator<T>;
+using CommandBufferAllocator = ChainAllocator<T>;
 
 /// The type of the allocator for heap allocations
 template<typename T>
-using GlAllocator = HeapAllocator<T>;
+using GrAllocator = HeapAllocator<T>;
+/// @}
+
+/// @addtogroup graphics
+/// @{
+
+/// 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_containers
@@ -250,10 +275,6 @@ ShaderType computeShaderTypeIndex(const GLenum glType);
 /// A function that returns a GLenum from an index
 GLenum computeGlShaderType(const ShaderType idx, GLbitfield* bit = nullptr);
 
-/// GL generic callback
-using GlCallback = void(*)(void*);
-using GlMakeCurrentCallback = void(*)(void*, void*);
-
 /// Occlusion query result bit.
 enum class GlOcclusionQueryResultBit: U8
 {

+ 0 - 55
include/anki/gr/GlContainerHandle.h

@@ -1,55 +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_GL_GL_CONTAINER_HANDLE_H
-#define ANKI_GL_GL_CONTAINER_HANDLE_H
-
-#include "anki/gr/GlHandle.h"
-#include "anki/gr/GlDevice.h"
-
-namespace anki {
-
-/// @addtogroup opengl_private
-/// @{
-
-/// Handle template for container objects
-template<typename T>
-class GlContainerHandle: public GlHandle<T>
-{
-public:
-	using Base = GlHandle<T>;
-
-protected:
-	/// Check if the object has been created and if not serialize the server
-	ANKI_USE_RESULT Error serializeOnGetter() const
-	{
-		Error err = ErrorCode::NONE;
-		GlHandleState state = Base::_getState();
-		ANKI_ASSERT(state != GlHandleState::NEW);
-		
-		if(state == GlHandleState::TO_BE_CREATED)
-		{
-			Base::_getDevice()._getQueue().syncClientServer();
-
-			state = Base::_getState();
-
-			if(state == GlHandleState::ERROR)
-			{
-				err = ErrorCode::UNKNOWN;
-			}
-		}
-
-		ANKI_ASSERT(state > GlHandleState::TO_BE_CREATED);
-
-		return err;
-	}
-};
-/// @}
-
-
-} // end namespace anki
-
-#endif
-

+ 0 - 86
include/anki/gr/GlDevice.h

@@ -1,86 +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_GL_GL_DEVICE_H
-#define ANKI_GL_GL_DEVICE_H
-
-#include "anki/gr/GlCommon.h"
-#include "anki/gr/gl/Queue.h"
-
-namespace anki {
-
-/// @addtogroup opengl_other
-/// @{
-
-/// Common stuff for all GL contexts
-class GlDevice
-{
-public:
-	/// Default constructor
-	GlDevice() = default;
-
-	~GlDevice()
-	{
-		destroy();
-	}
-
-	/// Create
-	ANKI_USE_RESULT Error create(
-		AllocAlignedCallback alloc, 
-		void* allocUserData, 
-		const CString& cacheDir);
-
-	/// Start the queue thread. @see Queue::start
-	ANKI_USE_RESULT Error startServer(
-		GlMakeCurrentCallback makeCurrentCb, void* makeCurrentCbData, void* ctx,
-		GlCallback swapBuffersCallback, void* swapBuffersCbData,
-		Bool registerDebugMessages);
-
-	/// Synchronize client and server
-	void syncClientServer();
-
-	/// Swap buffers
-	void swapBuffers();
-
-	/// Return the alignment of a buffer target
-	PtrSize getBufferOffsetAlignment(GLenum target) const;
-
-	/// @privatesection
-	/// @{
-	HeapAllocator<U8>& _getAllocator()
-	{
-		return m_alloc;
-	}
-
-	Queue& _getQueue() 
-	{
-		return *m_queue;
-	}
-
-	const Queue& _getQueue() const
-	{
-		return *m_queue;
-	}
-
-	CString _getCacheDirectory() const
-	{
-		ANKI_ASSERT(m_cacheDir != nullptr);
-		return m_cacheDir;
-	}
-	/// @}
-
-private:
-	Queue* m_queue = nullptr;
-	HeapAllocator<U8> m_alloc; ///< Keep it last to be deleted last
-	char* m_cacheDir = nullptr;
-	Bool8 m_queueStarted = false;
-
-	void destroy();
-};
-/// @}
-
-} // end namespace anki
-
-#endif

+ 0 - 397
include/anki/gr/GlHandle.h

@@ -1,397 +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_GL_GL_HANDLE_H
-#define ANKI_GL_GL_HANDLE_H
-
-#include "anki/gr/GlCommon.h"
-#include "anki/util/Atomic.h"
-
-namespace anki {
-
-// Forward
-class GlDevice;
-
-/// @addtogroup opengl_private
-/// @{
-
-/// State of the handle
-enum class GlHandleState: U8
-{
-	NEW,
-	TO_BE_CREATED,
-	CREATED,
-	TO_BE_DELETED,
-	DELETED,
-	ERROR
-};
-
-/// Default deleter for the GlHandle
-template<typename T, typename TAlloc>
-class GlHandleDefaultDeleter
-{
-public:
-	void operator()(T* ptr, TAlloc alloc, GlDevice*)
-	{
-		alloc.deleteInstance(ptr);
-	}
-};
-
-/// It's essentialy a custom shared pointer. Created to have full control over 
-/// allocations, it takes less space than a regular shared pointer (1 pointer 
-/// instead of 2) and it can have custom control blocks
-///
-/// @tparam T The type of the pointer
-template<typename T>
-class GlHandle
-{
-public:
-	using Type = T;
-
-	GlHandle()
-	:	m_cb(nullptr)
-	{}
-
-	GlHandle(const GlHandle& b)
-	:	GlHandle()
-	{
-		*this = b;
-	}
-
-	~GlHandle()
-	{
-		reset();
-	}
-
-	/// Copy
-	GlHandle& operator=(const GlHandle& b)
-	{
-		reset();
-	
-		if(b.m_cb)
-		{
-			auto count = b.m_cb->m_refcount.fetchAdd(1);
-			ANKI_ASSERT(count > 0);
-			(void)count;
-
-			m_cb = b.m_cb;
-		}
-
-		return *this;
-	}
-
-	/// Compare
-	Bool operator==(const GlHandle& b) const
-	{
-		return m_cb == b.m_cb;
-	}
-
-	/// Compare
-	Bool operator!=(const GlHandle& b) const
-	{
-		return m_cb != b.m_cb;
-	}
-
-	/// Compare
-	Bool operator<(const GlHandle& b) const
-	{
-		return m_cb < b.m_cb;
-	}
-
-	/// Compare
-	Bool operator<=(const GlHandle& b) const
-	{
-		return m_cb <= b.m_cb;
-	}
-
-	/// Compare
-	Bool operator>(const GlHandle& b) const
-	{
-		return m_cb > b.m_cb;
-	}
-
-	/// Compare
-	Bool operator>=(const GlHandle& b) const
-	{
-		return m_cb >= b.m_cb;
-	}
-
-	/// Allocate a GL object and initialize the handle with that
-	/// @param[in] alloc The allocator that will be used for all internal 
-	///                  allocations of the handle
-	/// @param[in] del The deleter that will be used to cleanup the allocated
-	///                object. The containers for example require deferred 
-	///                deleters
-	template<typename TAlloc, typename TDeleter>
-	ANKI_USE_RESULT Error _createSimple(TAlloc alloc, TDeleter del)
-	{
-		using Cb = CtrlBlockSimple<T, TAlloc, TDeleter>;
-
-		Error err = ErrorCode::NONE;
-
-		// Create the object
-		T* ptr = alloc.template newInstance<T>();
-
-		if(ptr != nullptr)
-		{
-			Cb* cb = alloc.template newInstance<Cb>();
-
-			if(cb != nullptr)
-			{
-				cb->m_alloc = alloc;
-				cb->m_del = del;
-				cb->m_refcount.store(1);
-				cb->m_ptr = ptr;
-
-				m_cb = cb;
-			}
-			else
-			{
-				alloc. template deleteInstance(ptr);
-				err = ErrorCode::OUT_OF_MEMORY;
-			}
-		}
-		else
-		{
-			err = ErrorCode::OUT_OF_MEMORY;
-		}
-
-		return err;
-	}
-
-	/// Create an object and initialize the handle with that
-	/// @param[in,out] dev The device.
-	/// @param[in] alloc The allocator that will be used for all internal 
-	///                  allocations of the handle
-	/// @param[in] del The deleter that will be used to cleanup the allocated
-	///                object. The containers for example require deferred 
-	///                deleters
-	/// @param args The arguments to pass to the object's constructor
-	template<typename TAlloc, typename TDeleter>
-	ANKI_USE_RESULT Error _createAdvanced(
-		GlDevice* dev, TAlloc alloc, TDeleter del)
-	{
-		ANKI_ASSERT(dev);
-
-		using Cb = CtrlBlockContainer<T, TAlloc, TDeleter>;
-
-		Error err = ErrorCode::NONE;
-
-		// Create the object
-		T* ptr = alloc.template newInstance<T>();
-
-		if(ptr != nullptr)
-		{
-			Cb* cb = alloc.template newInstance<Cb>();
-
-			if(cb != nullptr)
-			{
-				cb->m_state.store(static_cast<I32>(GlHandleState::NEW));
-				cb->m_gl = dev;
-				cb->m_alloc = alloc;
-				cb->m_del = del;
-				cb->m_refcount.store(1);
-				cb->m_ptr = ptr;
-
-				m_cb = cb;
-			}
-			else
-			{
-				alloc. template deleteInstance(ptr);
-				err = ErrorCode::OUT_OF_MEMORY;
-			}
-		}
-		else
-		{
-			err = ErrorCode::OUT_OF_MEMORY;
-		}
-
-		return err;
-	}
-
-	/// Return true if it's pointing to actual data
-	Bool isCreated() const
-	{
-		return m_cb != nullptr;
-	}
-
-	/// Return the number of users
-	U getReferenceCount() const
-	{
-		ANKI_ASSERT(m_cb != nullptr && m_cb->m_ptr != nullptr);
-		return m_cb->m_refcount.load();
-	}
-
-	/// Get the mutable pointer 
-	T& _get()
-	{
-		ANKI_ASSERT(m_cb != nullptr && m_cb->m_ptr != nullptr);
-		return *m_cb->m_ptr;
-	}
-
-	/// Get the immutable pointer
-	const T& _get() const
-	{
-		ANKI_ASSERT(m_cb != nullptr && m_cb->m_ptr != nullptr);
-		return *m_cb->m_ptr;
-	}
-
-	/// Get the current state
-	GlHandleState _getState() const
-	{
-		ANKI_ASSERT(m_cb != nullptr);
-		return m_cb->getStateAtomically(nullptr);
-	}
-
-	/// Set the handle state
-	GlHandleState _setState(GlHandleState newVal)
-	{
-		ANKI_ASSERT(m_cb != nullptr);
-		return m_cb->getStateAtomically(&newVal);
-	}
-
-	GlDevice& _getDevice() const
-	{
-		ANKI_ASSERT(m_cb != nullptr && m_cb->getDevice() != nullptr);
-		return *m_cb->getDevice(); 
-	}
-
-private:
-	/// Control block base
-	/// @note The non-pure virtuals indicate an optional feature
-	template<typename Y>
-	class CtrlBlockBase
-	{
-	public:
-		Y* m_ptr;
-		Atomic<I32> m_refcount;
-
-		virtual ~CtrlBlockBase()
-		{}
-		
-		/// Delete the m_ptr
-		virtual void deletePtr() = 0;
-
-		/// Delete the block itself
-		virtual void deleteSelf() = 0;
-
-		/// The container handles want the manager
-		virtual GlDevice* getDevice() const
-		{
-			return nullptr;
-		}
-
-		/// Manipulate the state. It will return the value of the state and if
-		/// newVal is not nullptr it will set a new value
-		virtual GlHandleState getStateAtomically(GlHandleState* newVal)
-		{
-			(void)newVal;
-			return GlHandleState::NEW;
-		}
-	};
-
-	/// Control block for simple objects
-	template<typename Y, typename YAlloc, typename YDeleter>
-	class CtrlBlockSimple: public CtrlBlockBase<Y>
-	{
-	public:	
-		using Base = CtrlBlockBase<Y>;
-
-		/// Copy of the allocator
-		YAlloc m_alloc; 
-
-		/// The deleter functor
-		YDeleter m_del;
-		
-		void deletePtr()
-		{
-			// Delete object
-			m_del(Base::m_ptr, m_alloc, nullptr);
-		}
-
-		void deleteSelf()
-		{
-			// Delete control block
-			m_alloc.deleteInstance(this);
-		}
-	};
-
-	/// Control block for container objects
-	template<typename Y, typename YAlloc, typename YDeleter>
-	class CtrlBlockContainer: public CtrlBlockBase<Y>
-	{
-	public:	
-		using Base = CtrlBlockBase<Y>;
-
-		/// Copy of the allocator
-		YAlloc m_alloc; 
-
-		/// The deleter functor
-		YDeleter m_del;
-
-		/// @note Its mutable because we want read/write access to it
-		mutable GlDevice* m_gl; 
-
-		Atomic<I32> m_state;
-		
-		void deletePtr()
-		{
-			// Delete object
-			m_del(Base::m_ptr, m_alloc, getDevice());
-		}
-
-		void deleteSelf()
-		{
-			// Delete control block
-			m_alloc.deleteInstance(this);
-		}
-
-		GlDevice* getDevice() const override
-		{
-			return m_gl;
-		}
-
-		GlHandleState getStateAtomically(GlHandleState* newVal) override
-		{
-			GlHandleState crntVal;
-			if(newVal)
-			{
-				I32 newValI32 = static_cast<I32>(*newVal);
-				crntVal = 
-					static_cast<GlHandleState>(m_state.exchange(newValI32));
-			}
-			else
-			{
-				crntVal = static_cast<GlHandleState>(m_state.load());
-			}
-			return crntVal;
-		}
-	};
-
-	CtrlBlockBase<T>* m_cb;
-
-	/// Reset the pointer to it's original state and remove the references to
-	/// any object
-	void reset()
-	{
-		if(m_cb)
-		{
-			auto count = m_cb->m_refcount.fetchSub(1);
-			if(count == 1)
-			{
-				m_cb->deletePtr();
-				m_cb->deleteSelf();
-			}
-
-			m_cb = nullptr;
-		}
-	}
-};
-/// @}
-
-} // end namespace anki
-
-#endif
-

+ 0 - 36
include/anki/gr/GlSync.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_GL_GL_SYNC_H
-#define ANKI_GL_GL_SYNC_H
-
-#include "anki/gr/GlCommon.h"
-#include "anki/util/Thread.h"
-
-namespace anki {
-
-/// @addtogroup opengl_private
-/// @{
-
-/// Sync with the client
-class GlClientSync
-{
-public:
-	GlClientSync()
-	:	m_barrier(2)
-	{}
-
-	/// Wait 
-	void wait();
-
-private:
-	Barrier m_barrier;
-};
-/// @}
-
-} // end namespace anki
-
-#endif
-

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

@@ -1,45 +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_GL_GL_SYNC_HANDLES_H
-#define ANKI_GL_GL_SYNC_HANDLES_H
-
-#include "anki/gr/GlHandle.h"
-
-namespace anki {
-
-// Forward
-class GlClientSync;
-
-/// @addtogroup opengl_other
-/// @{
-
-/// Client sync handle
-class GlClientSyncHandle: public GlHandle<GlClientSync>
-{
-public:
-	using Base = GlHandle<GlClientSync>;
-
-	GlClientSyncHandle();
-
-	~GlClientSyncHandle();
-
-	ANKI_USE_RESULT Error create(CommandBufferHandle& commands);
-
-	/// Fire a command that adds a waits for the client. The client should call 
-	/// wait some time after this call or the server will keep waiting forever
-	void sync(CommandBufferHandle& commands);
-
-	/// Wait for the server. You need to call sync first or the client will
-	/// keep waiting forever
-	void wait();
-};
-
-/// @}
-
-} // end namespace anki
-
-#endif
-

+ 235 - 0
include/anki/gr/GrHandle.h

@@ -0,0 +1,235 @@
+// 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"
+
+namespace anki {
+
+/// @addtogroup graphics_private
+/// @{
+
+/// Default deleter for the GrHandle
+template<typename T>
+class GrHandleDefaultDeleter
+{
+public:
+	void operator()(T* ptr)
+	{
+		ptr->getAllocator().deleteInstance(ptr);
+	}
+};
+
+/// It's essentialy a custom shared pointer. Created to have full control over 
+/// allocations, it takes less space than a regular shared pointer (1 pointer 
+/// instead of 2) and it can have custom control blocks
+///
+/// @tparam T The type of the pointer
+template<typename T>
+class GrHandle
+{
+public:
+	using Type = T;
+
+	GrHandle()
+	:	m_cb(nullptr)
+	{}
+
+	GrHandle(const GrHandle& b)
+	:	GrHandle()
+	{
+		*this = b;
+	}
+
+	~GrHandle()
+	{
+		reset();
+	}
+
+	/// Copy
+	GrHandle& operator=(const GrHandle& b)
+	{
+		reset();
+	
+		if(b.m_cb)
+		{
+			auto count = b.m_cb->getRefcount().fetchAdd(1);
+			ANKI_ASSERT(count > 0);
+			(void)count;
+
+			m_cb = b.m_cb;
+		}
+
+		return *this;
+	}
+
+	/// Compare
+	Bool operator==(const GrHandle& b) const
+	{
+		return m_cb == b.m_cb;
+	}
+
+	/// Compare
+	Bool operator!=(const GrHandle& b) const
+	{
+		return m_cb != b.m_cb;
+	}
+
+	/// Compare
+	Bool operator<(const GrHandle& b) const
+	{
+		return m_cb < b.m_cb;
+	}
+
+	/// Compare
+	Bool operator<=(const GrHandle& b) const
+	{
+		return m_cb <= b.m_cb;
+	}
+
+	/// Compare
+	Bool operator>(const GrHandle& b) const
+	{
+		return m_cb > b.m_cb;
+	}
+
+	/// Compare
+	Bool operator>=(const GrHandle& b) const
+	{
+		return m_cb >= b.m_cb;
+	}
+
+	/// Create an object and initialize the handle with that.
+	/// @param[in,out] manager The manager.
+	/// @param[in] del The deleter that will be used to cleanup the allocated
+	///                object. Some objects example may require deferred 
+	///                deleters.
+	template<typename TDeleter>
+	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);
+
+		if(ptr != nullptr)
+		{
+			Cb* cb = alloc.template newInstance<Cb>();
+
+			if(cb != nullptr)
+			{
+				cb->m_del = del;
+				cb->getRefcount().store(1);
+				cb->m_ptr = ptr;
+
+				m_cb = cb;
+			}
+			else
+			{
+				alloc.template deleteInstance(ptr);
+				err = ErrorCode::OUT_OF_MEMORY;
+			}
+		}
+		else
+		{
+			err = ErrorCode::OUT_OF_MEMORY;
+		}
+
+		return err;
+	}
+
+	/// Return true if it's pointing to actual data
+	Bool isCreated() const
+	{
+		return m_cb != nullptr;
+	}
+
+	/// Get the mutable pointer 
+	T& get()
+	{
+		ANKI_ASSERT(m_cb != nullptr && m_cb->m_ptr != nullptr);
+		return *m_cb->m_ptr;
+	}
+
+	/// Get the immutable pointer
+	const T& get() const
+	{
+		ANKI_ASSERT(m_cb != nullptr && m_cb->m_ptr != nullptr);
+		return *m_cb->m_ptr;
+	}
+
+private:
+	/// Control block base
+	class CtrlBlockBase
+	{
+	public:
+		GrObject* m_ptr;
+
+		virtual ~CtrlBlockBase()
+		{}
+
+		Atomic<I32>& getRefcount()
+		{
+			ANKI_ASSERT(m_ptr);
+			return m_ptr->getRefcount();
+		}
+		
+		/// Delete the m_ptr
+		virtual void deletePtr() = 0;
+	};
+
+	/// Control block with deleter.
+	template<typename YDeleter>
+	class CtrlBlock: public CtrlBlockBase
+	{
+	public:	
+		using Base = CtrlBlockBase;
+
+		/// The deleter functor
+		YDeleter m_del;
+		
+		void deletePtr()
+		{
+			// Delete object
+			m_del(Base::m_ptr);
+		}
+	};
+
+	CtrlBlockBase* m_cb;
+
+	/// Reset the pointer to it's original state and remove the references to
+	/// any object
+	void reset()
+	{
+		if(m_cb && m_cb->m_ptr)
+		{
+			auto count = m_cb->getRefcount().fetchSub(1);
+			if(count == 1)
+			{
+				auto alloc = m_cb->m_ptr->getAllocator();
+				// Delete pointer
+				m_cb->deletePtr();
+				m_cb->m_ptr = nullptr;
+				// Delete control block
+				alloc.deleteInstance(m_cb);
+			}
+
+			m_cb = nullptr;
+		}
+	}
+};
+/// @}
+
+} // end namespace anki
+
+#endif
+

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

@@ -0,0 +1,96 @@
+// 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_MANAGER_H
+#define ANKI_GR_GR_MANAGER_H
+
+#include "anki/gr/Common.h"
+#include "anki/util/String.h"
+
+namespace anki {
+
+/// @addtogroup graphics_other
+/// @{
+
+/// Manager initializer.
+struct GrManagerInitializer
+{
+	AllocAlignedCallback m_allocCallback; 
+	void* m_allocCallbackUserData;
+
+	MakeCurrentCallback m_makeCurrentCallback;
+	void* m_makeCurrentCallbackData;
+	void* m_ctx;
+
+	SwapBuffersCallback m_swapBuffersCallback;
+	void* m_swapBuffersCallbackData;
+
+	CString m_cacheDirectory;
+	Bool m_registerDebugMessages = false;
+};
+
+/// The graphics manager, owner of all graphics objects.
+class GrManager
+{
+	friend class GrManagerImpl;
+
+public:
+	using Initializer = GrManagerInitializer;
+
+	/// Default constructor
+	GrManager() = default;
+
+	~GrManager()
+	{
+		destroy();
+	}
+
+	/// 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;
+
+	/// @privatesection
+	/// @{
+	GrAllocator<U8>& getAllocator()
+	{
+		return m_alloc;
+	}
+
+	GrManagerImpl& getImplementation() 
+	{
+		return *m_impl;
+	}
+
+	const GrManagerImpl& getImplementation() const
+	{
+		return *m_impl;
+	}
+
+	CString getCacheDirectory() const
+	{
+		return m_cacheDir.toCString();
+	}
+	/// @}
+
+private:
+	GrManagerImpl* m_impl = nullptr;
+	StringBase<GrAllocator<char>> m_cacheDir;
+	GrAllocator<U8> m_alloc; ///< Keep it last to deleted last
+
+	void destroy();
+};
+/// @}
+
+} // end namespace anki
+
+#endif

+ 55 - 0
include/anki/gr/GrObject.h

@@ -0,0 +1,55 @@
+// 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_OBJECT_H
+#define ANKI_GR_GR_OBJECT_H
+
+#include "anki/gr/Common.h"
+#include "anki/util/Atomic.h"
+
+namespace anki {
+
+/// @addtogroup graphics_private
+/// @{
+
+/// Base of all graphics objects.
+class GrObject
+{
+public:
+	GrObject(GrManager* manager)
+	:	m_refcount(0),
+		m_manager(manager)
+	{}
+
+	virtual ~GrObject()
+	{}
+
+	GrManager& getManager()
+	{
+		return *m_manager;
+	}
+
+	const GrManager& getManager() const
+	{
+		return *m_manager;
+	}
+
+	GrAllocator<U8> getAllocator() const;
+
+	Atomic<I32>& getRefcount()
+	{
+		return m_refcount;
+	}
+
+private:
+	Atomic<I32> m_refcount;
+	GrManager* m_manager;
+};
+/// @}
+
+} // end namespace anki
+
+#endif
+

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

@@ -21,7 +21,8 @@ public:
 	using Base = GlObject;
 
 	/// Default
-	BufferImpl()
+	BufferImpl(GrManager* manager)
+	:	GlObject(manager)
 	{}
 
 	/// It deletes the BO

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

@@ -6,13 +6,14 @@
 #ifndef ANKI_GR_GL_COMMAND_BUFFER_IMPL_H
 #define ANKI_GR_GL_COMMAND_BUFFER_IMPL_H
 
-#include "anki/gr/GlCommon.h"
+#include "anki/gr/GrObject.h"
+#include "anki/gr/GrManager.h"
 #include "anki/util/Assert.h"
 #include "anki/util/Allocator.h"
 
 namespace anki {
 
-/// @addtogroup opengl_private
+/// @addtogroup opengl
 /// @{
 
 /// The base of all GL commands
@@ -28,49 +29,16 @@ public:
 	virtual ANKI_USE_RESULT Error operator()(CommandBufferImpl*) = 0;
 };
 
-/// A common command that deletes an object
-template<typename T, typename TAlloc>
-class GlDeleteObjectCommand: public GlCommand
-{
-public:
-	T* m_ptr;
-	TAlloc m_alloc;
-
-	GlDeleteObjectCommand(T* ptr, TAlloc alloc)
-	:	m_ptr(ptr), 
-		m_alloc(alloc)
-	{
-		ANKI_ASSERT(m_ptr);
-	}
-
-	Error operator()(CommandBufferImpl*) override
-	{
-		m_alloc.deleteInstance(m_ptr);
-		return ErrorCode::NONE;
-	}
-};
-
-/// Command buffer initialization hints. They are used to optimize the 
-/// allocators of a command buffer
-class CommandBufferImplInitHints
-{
-	friend class CommandBufferImpl;
-
-private:
-	enum
-	{
-		MAX_CHUNK_SIZE = 4 * 1024 * 1024 // 4MB
-	};
-
-	PtrSize m_chunkSize = 1024;
-};
-
 /// A number of GL commands organized in a chain
-class CommandBufferImpl: public NonCopyable
+class CommandBufferImpl: public GrObject, public NonCopyable
 {
 public:
+	using InitHints = CommandBufferImplInitHints;
+
 	/// Default constructor
-	CommandBufferImpl() = default;
+	CommandBufferImpl(GrManager* manager)
+	:	GrObject(manager)
+	{}
 
 	~CommandBufferImpl()
 	{
@@ -80,29 +48,16 @@ public:
 	/// Default constructor
 	/// @param server The command buffers server
 	/// @param hints Hints to optimize the command's allocator
-	ANKI_USE_RESULT Error create(Queue* server, 
-		const CommandBufferImplInitHints& hints);
+	ANKI_USE_RESULT Error create(const InitHints& hints);
 
 	/// Get he allocator
-	GlCommandBufferAllocator<U8> getAllocator() const
+	CommandBufferAllocator<U8> getAllocator() const
 	{
 		return m_alloc;
 	}
 
-	GlAllocator<U8> getGlobalAllocator() const;
-
-	Queue& getQueue()
-	{
-		return *m_server;
-	}
-
-	const Queue& getQueue() const
-	{
-		return *m_server;
-	}
-
 	/// Compute initialization hints
-	CommandBufferImplInitHints computeInitHints() const;
+	InitHints computeInitHints() const;
 
 	/// Create a new command and add it to the chain
 	template<typename TCommand, typename... TArgs>
@@ -126,10 +81,9 @@ public:
 	}
 
 private:
-	Queue* m_server = nullptr;
 	GlCommand* m_firstCommand = nullptr;
 	GlCommand* m_lastCommand = nullptr;
-	GlCommandBufferAllocator<U8> m_alloc;
+	CommandBufferAllocator<U8> m_alloc;
 	Bool8 m_immutable = false;
 
 #if ANKI_DEBUG
@@ -161,6 +115,26 @@ 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

+ 4 - 4
include/anki/gr/GlHandleDeferredDeleter.h → include/anki/gr/gl/DeferredDeleter.h

@@ -3,8 +3,8 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_GL_GL_HANDLE_DEFERRED_DELETER_H
-#define ANKI_GL_GL_HANDLE_DEFERRED_DELETER_H
+#ifndef ANKI_GL_DEFERRED_DELETER_H
+#define ANKI_GL_DEFERRED_DELETER_H
 
 #include "anki/gr/GlDevice.h"
 #include "anki/gr/CommandBufferHandle.h"
@@ -20,7 +20,7 @@ namespace anki {
 /// 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>
-class GlHandleDeferredDeleter
+class DeferredDeleter
 {
 public:
 	void operator()(T* obj, TAlloc alloc, GlDevice* manager)
@@ -29,7 +29,7 @@ public:
 		ANKI_ASSERT(manager);
 		
 		/// If not the server thread then create a command for the server thread
-		if(!manager->_getQueue().isServerThread())
+		if(!manager->_getRenderingThread().isServerThread())
 		{
 			CommandBufferHandle commands;
 			

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

@@ -3,11 +3,10 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_GL_GL_ERROR_H
-#define ANKI_GL_GL_ERROR_H
+#ifndef ANKI_GL_ERROR_H
+#define ANKI_GL_ERROR_H
 
-#include "anki/Config.h"
-#include "anki/gr/GlCommon.h"
+#include "anki/gr/Common.h"
 
 namespace anki {
 
@@ -27,7 +26,6 @@ void glConditionalCheckError(const char* file, int line, const char* func);
 #else
 #	define ANKI_CHECK_GL_ERROR() ((void)0)
 #endif
-
 /// @}
 
 } // end namespace anki

+ 38 - 4
include/anki/gr/gl/GlObject.h

@@ -6,20 +6,35 @@
 #ifndef ANKI_GR_GL_OBJECT_H
 #define ANKI_GR_GL_OBJECT_H
 
-#include "anki/gr/GlCommon.h"
+#include "anki/gr/GrObject.h"
 
 namespace anki {
 
 /// @addtogroup opengl_private
 /// @{
 
+/// State of the handle
+enum class GlObjectState: U32
+{
+	NEW,
+	TO_BE_CREATED,
+	CREATED,
+	TO_BE_DELETED,
+	DELETED,
+	ERROR
+};
+
 /// A GL object
-class GlObject: public NonCopyable
+class GlObject: public GrObject, public NonCopyable
 {
 public:
+	using State = GlObjectState;
+
 	/// Default
-	GlObject()
-	:	m_glName(0)
+	GlObject(GrManager* manager)
+	:	GrObject(manager),
+		m_glName(0),
+		m_state(I32(State::NEW))
 	{}
 
 	~GlObject()
@@ -41,8 +56,27 @@ public:
 		return m_glName != 0;
 	}
 
+	State getStateAtomically(State* newVal)
+	{
+		State crntVal;
+		if(newVal)
+		{
+			I32 newValI32 = I32(*newVal);
+			crntVal = State(m_state.exchange(newValI32));
+		}
+		else
+		{
+			crntVal = State(m_state.load());
+		}
+		return crntVal;
+	}
+
+	/// Check if the object has been created and if not serialize the thread.
+	ANKI_USE_RESULT Error serializeOnGetter() const;
+
 protected:
 	GLuint m_glName; ///< OpenGL name
+	mutable Atomic<I32> m_state;
 };
 /// @}
 

+ 51 - 0
include/anki/gr/gl/GrManagerImpl.h

@@ -0,0 +1,51 @@
+// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// 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
+
+#include "anki/gr/Common.h"
+#include "anki/util/List.h"
+
+namespace anki {
+
+/// @addtogroup opengl
+/// @{
+
+/// Graphics manager backend specific.
+class GrManagerImpl
+{
+public:
+	GrManagerImpl(GrManager* manager)
+	:	m_manager(manager)
+	{
+		ANKI_ASSERT(manager);
+	}
+
+	ANKI_USE_RESULT Error create(GrManagerInitializer& init);
+
+	GrAllocator<U8> getAllocator() const;
+
+	const RenderingThread& getRenderingThread() const
+	{
+		return *m_thread;
+	}
+
+	RenderingThread& getRenderingThread()
+	{
+		return *m_thread;
+	}
+
+private:
+	GrManager* m_manager;
+	RenderingThread* m_thread = nullptr;
+	List<GrObject*> m_objectsForDeletion;
+};
+/// @}
+
+} // end namespace anki
+
+#endif
+

+ 8 - 7
include/anki/gr/gl/Queue.h → include/anki/gr/gl/RenderingThread.h

@@ -3,11 +3,10 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_GR_GL_QUEUE_H
-#define ANKI_GR_GL_QUEUE_H
+#ifndef ANKI_GR_GL_RENDERING_THREAD_H
+#define ANKI_GR_GL_RENDERING_THREAD_H
 
 #include "anki/gr/CommandBufferHandle.h"
-#include "anki/gr/GlSyncHandles.h"
 #include "anki/gr/gl/State.h"
 #include "anki/util/Thread.h"
 
@@ -21,13 +20,15 @@ class GlDevice;
 
 /// Command queue. It's essentialy a queue of command buffers waiting for 
 /// execution and a server
-class Queue
+class RenderingThread
 {
+	friend class SyncCommand;
+
 public:
-	Queue(GlDevice* device, 
+	RenderingThread(GlDevice* device, 
 		AllocAlignedCallback alloc, void* allocUserData);
 
-	~Queue();
+	~RenderingThread();
 
 	GlDevice& getDevice()
 	{
@@ -126,7 +127,7 @@ private:
 	/// A special command buffer that is called every time we want to wait for 
 	/// the server
 	CommandBufferHandle m_syncCommands;
-	GlClientSyncHandle m_sync;
+	Barrier m_syncBarrier{2};
 
 	GLuint m_copyFbo = MAX_U32; ///< FBO for copying from tex to buffer.
 

+ 4 - 4
include/anki/gr/gl/State.h

@@ -3,14 +3,14 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_GL_GL_STATE_H
-#define ANKI_GL_GL_STATE_H
+#ifndef ANKI_GR_GL_STATE_H
+#define ANKI_GR_GL_STATE_H
 
-#include "anki/gr/GlCommon.h"
+#include "anki/gr/Common.h"
 
 namespace anki {
 
-/// @addtogroup opengl_private
+/// @addtogroup opengl
 /// @{
 
 /// Knowing the ventor allows some optimizations

+ 211 - 0
include/anki/util/HashMap.h

@@ -0,0 +1,211 @@
+// Copyright (C) 2014, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#ifndef ANKI_UTIL_HASH_MAP_H
+#define ANKI_UTIL_HASH_MAP_H
+
+#include "anki/util/Allocator.h"
+#include "anki/util/NonCopyable.h"
+
+/// @addtogroup util_private
+/// @{
+
+/// HashMap node.
+template<typename T>
+class HashMapNode
+{
+public:
+	using Value = T;
+
+	Value m_value;
+	U64 m_hash;
+	HashMapNode* m_prev = nullptr;
+	HashMapNode* m_next = nullptr;
+
+	template<typename... TArgs>
+	HashMapNode(TArgs&&... args)
+	:	m_value(std::forward<TArgs>(args)...)
+	{}
+};
+
+/// HashMap bidirectional iterator.
+template<typename TNodePointer, typename TValuePointer, 
+	typename TValueReference, typename THashMapPointer>
+class HashMapIterator
+{
+public:
+	TNodePointer m_node = nullptr;
+	THashMapPointer m_map = nullptr; ///< Used to go back from the end
+
+	HashMapIterator() = default;
+
+	HashMapIterator(const HashMapIterator& b)
+	:	m_node(b.m_node),
+		m_map(b.m_map)
+	{}
+
+	/// Allow conversion from iterator to const iterator.
+	template<typename YNodePointer, typename YValuePointer, 
+		typename YValueReference, typename YHashMap>
+	HashMapIterator(const HashMapIterator<YNodePointer, 
+		YValuePointer, YValueReference, YHashMap>& b)
+	:	m_node(b.m_node),
+		m_map(b.m_map)
+	{}
+
+	HashMapIterator(TNodePointer node, THashMapPointer list)
+	:	m_node(node),
+		m_map(list)
+	{
+		ANKI_ASSERT(list);
+	}
+
+	TValueReference operator*() const
+	{
+		ANKI_ASSERT(m_node);
+		return m_node->m_value;
+	}
+
+	TValuePointer operator->() const
+	{
+		ANKI_ASSERT(m_node);
+		return &m_node->m_value;
+	}
+
+	HashMapIterator& operator++()
+	{
+		ANKI_ASSERT(m_node);
+		m_node = m_node->m_next;
+		return *this;
+	}
+
+	HashMapIterator operator++(int)
+	{
+		ANKI_ASSERT(m_node);
+		HashMapIterator out = *this;
+		++(*this);
+		return out;
+	}
+
+	HashMapIterator& operator--();
+
+	HashMapIterator operator--(int)
+	{
+		ANKI_ASSERT(m_node);
+		HashMapIterator out = *this;
+		--(*this);
+		return out;
+	}
+
+	HashMapIterator operator+(U n) const
+	{
+		HashMapIterator it = *this;
+		while(n-- != 0)
+		{
+			++it;
+		}
+		return it;
+	}
+
+	HashMapIterator operator-(U n) const
+	{
+		HashMapIterator it = *this;
+		while(n-- != 0)
+		{
+			--it;
+		}
+		return it;
+	}
+
+	HashMapIterator& operator+=(U n)
+	{
+		while(n-- != 0)
+		{
+			++(*this);
+		}
+		return *this;
+	}
+
+	HashMapIterator& operator-=(U n)
+	{
+		while(n-- != 0)
+		{
+			--(*this);
+		}
+		return *this;
+	}
+
+	Bool operator==(const HashMapIterator& b) const
+	{
+		ANKI_ASSERT(m_list == b.m_list 
+			&& "Comparing iterators from different lists");
+		return m_node == b.m_node;
+	}
+
+	Bool operator!=(const HashMapIterator& b) const
+	{
+		return !(*this == b);
+	}
+};
+/// @}
+
+/// @addtogroup util_containers
+/// @{
+
+/// Hash map template.
+template<typename T>
+class HashMap
+{
+public:
+	using Value = T;
+	using Node = HashMapNode<Value>;
+	using Reference = Value&;
+	using ConstReference = const Value&;
+	using Pointer = Value*;
+	using ConstPointer = const Value*;
+
+	HashMap() = default;
+
+	/// Move.
+	HashMap(HashMap&& b)
+	:	HashMap()
+	{
+		move(b);
+	}
+
+	/// You need to manually destroy the map.
+	/// @see HashMap::destroy
+	~HashMap()
+	{
+		ANKI_ASSERT(m_root == nullptr && "Requires manual destruction");
+	}
+
+	/// Move.
+	HashMap& operator=(HashMap&& b)
+	{
+		move(b);
+		return *this;
+	}
+
+	/// Return true if map is empty.
+	Bool isEmpty() const
+	{
+		return m_root == nullptr;
+	}
+
+private:
+	Node* m_root = nullptr;
+
+	void move(HashMap& b)
+	{
+		ANKI_ASSERT(isEmpty() && "Cannot move before destroying");
+		m_root = b.m_root;
+		b.m_root = nullptr;
+	}
+};
+/// @}
+
+#endif
+

+ 0 - 64
src/gr/ClientBufferHandle.cpp

@@ -1,64 +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/ClientBufferHandle.h"
-#include "anki/gr/ClientBufferImpl.h"
-#include "anki/gr/CommandBufferHandle.h"
-#include "anki/gr/GlDevice.h"
-#include "anki/core/Counters.h"
-
-namespace anki {
-
-//==============================================================================
-ClientBufferHandle::ClientBufferHandle()
-{}
-
-//==============================================================================
-ClientBufferHandle::~ClientBufferHandle()
-{}
-
-//==============================================================================
-Error ClientBufferHandle::create(
-	CommandBufferHandle& commands, PtrSize size, void* preallocatedMem)
-{
-	ANKI_ASSERT(!isCreated());
-
-	using Deleter = GlHandleDefaultDeleter<
-		ClientBufferImpl, GlCommandBufferAllocator<ClientBufferImpl>>;
-
-	auto alloc = commands._getAllocator();
-	Error err = _createSimple(alloc, Deleter());
-
-	if(!err)
-	{
-		if(preallocatedMem != nullptr)
-		{
-			err = _get().create(preallocatedMem, size);
-		}
-		else
-		{
-			err = _get().create(alloc, size);
-
-			ANKI_COUNTER_INC(GL_CLIENT_BUFFERS_SIZE, U64(size));
-		}
-	}
-
-	return err;
-}
-
-//==============================================================================
-void* ClientBufferHandle::getBaseAddress()
-{
-	return _get().getBaseAddress();
-}
-
-//==============================================================================
-PtrSize ClientBufferHandle::getSize() const
-{
-	return _get().getSize();
-}
-
-} // end namespace anki
-

+ 0 - 0
src/gr/GlCommon.cpp → src/gr/Common.cpp


+ 0 - 102
src/gr/GlDevice.cpp

@@ -1,102 +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/GlDevice.h"
-#include "anki/core/Timestamp.h"
-#include <cstring>
-
-namespace anki {
-
-//==============================================================================
-Error GlDevice::create(
-	AllocAlignedCallback alloc, void* allocUserData,
-	const CString& cacheDir)
-{
-	m_alloc = HeapAllocator<U8>(alloc, allocUserData);
-
-	// Allocate cache dir
-	auto len = cacheDir.getLength();
-	m_cacheDir = reinterpret_cast<char*>(m_alloc.allocate(len + 1));
-	std::memcpy(m_cacheDir, &cacheDir[0], len + 1);
-
-	// Create queue
-	m_queue = m_alloc.newInstance<Queue>(
-		this, alloc, allocUserData);
-
-#if ANKI_QUEUE_DISABLE_ASYNC
-	ANKI_LOGW("GL queue works in synchronous mode");
-#endif
-
-	return ErrorCode::NONE;
-}
-
-//==============================================================================
-void GlDevice::destroy()
-{
-	if(m_queue)
-	{
-		if(m_queueStarted)
-		{
-			m_queue->stop();
-		}
-
-		m_alloc.deleteInstance(m_queue);
-	}
-
-	if(m_cacheDir)
-	{
-		m_alloc.deallocate(m_cacheDir, std::strlen(m_cacheDir) + 1);
-	}
-}
-
-//==============================================================================
-Error GlDevice::startServer(
-	GlMakeCurrentCallback makeCurrentCb, void* makeCurrentCbData, void* ctx,
-	GlCallback swapBuffersCallback, void* swapBuffersCbData,
-	Bool registerDebugMessages)
-{
-	Error err = m_queue->start(makeCurrentCb, makeCurrentCbData, ctx, 
-		swapBuffersCallback, swapBuffersCbData, 
-		registerDebugMessages);
-
-	if(!err)
-	{
-		syncClientServer();
-
-		m_queueStarted = true;
-	}
-
-	return err;
-}
-
-//==============================================================================
-void GlDevice::syncClientServer()
-{
-	m_queue->syncClientServer();
-}
-
-//==============================================================================
-void GlDevice::swapBuffers()
-{
-	m_queue->swapBuffers();
-}
-
-//==============================================================================
-PtrSize GlDevice::getBufferOffsetAlignment(GLenum target) const
-{
-	const State& state = m_queue->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

+ 0 - 71
src/gr/GlSyncHandles.cpp

@@ -1,71 +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/GlSyncHandles.h"
-#include "anki/gr/GlSync.h"
-#include "anki/gr/CommandBufferHandle.h"
-#include "anki/gr/GlDevice.h"
-#include "anki/core/Counters.h"
-
-
-namespace anki {
-
-//==============================================================================
-/// Wait command
-class GlClientSyncWaitCommand: public GlCommand
-{
-public:
-	GlClientSyncHandle m_sync;	
-
-	GlClientSyncWaitCommand(const GlClientSyncHandle& s)
-	:	m_sync(s)
-	{}
-
-	Error operator()(CommandBufferImpl*)
-	{
-		ANKI_COUNTER_START_TIMER(GL_SERVER_WAIT_TIME);
-		m_sync._get().wait();
-		ANKI_COUNTER_STOP_TIMER_INC(GL_SERVER_WAIT_TIME);
-
-		return ErrorCode::NONE;
-	}
-};
-
-//==============================================================================
-GlClientSyncHandle::GlClientSyncHandle()
-{}
-
-//==============================================================================
-GlClientSyncHandle::~GlClientSyncHandle()
-{}
-
-//==============================================================================
-Error GlClientSyncHandle::create(CommandBufferHandle& commands)
-{
-	auto alloc = commands._getGlobalAllocator();
-
-	using Deleter = 
-		GlHandleDefaultDeleter<GlClientSync, GlAllocator<U8>>;
-
-	return _createAdvanced(
-		&commands._getQueue().getDevice(), alloc, Deleter());
-}
-
-//==============================================================================
-void GlClientSyncHandle::sync(CommandBufferHandle& commands)
-{
-	commands._pushBackNewCommand<GlClientSyncWaitCommand>(*this);
-}
-
-//==============================================================================
-void GlClientSyncHandle::wait()
-{
-	ANKI_COUNTER_START_TIMER(GL_CLIENT_WAIT_TIME);
-	_get().wait();
-	ANKI_COUNTER_STOP_TIMER_INC(GL_CLIENT_WAIT_TIME);
-}
-
-} // end namespace anki
-

+ 4 - 4
src/gr/GlSync.cpp → src/gr/GrObject.cpp

@@ -3,15 +3,15 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#include "anki/gr/GlSync.h"
-#include "anki/util/Logger.h"
+#include "anki/gr/GrObject.h"
+#include "anki/gr/GrManager.h"
 
 namespace anki {
 
 //==============================================================================
-void GlClientSync::wait()
+GrAllocator<U8> GrObject::getAllocator() const
 {
-	m_barrier.wait();
+	m_manager->getAllocator();
 }
 
 } // end namespace anki

+ 4 - 4
src/gr/gl/BufferHandle.cpp

@@ -88,8 +88,8 @@ Error BufferHandle::create(CommandBufferHandle& commands,
 	using Deleter = GlHandleDeferredDeleter<BufferImpl, Alloc, DeleteCommand>;
 
 	Error err = _createAdvanced(
-		&commands._getQueue().getDevice(),
-		commands._getQueue().getDevice()._getAllocator(), 
+		&commands._getRenderingThread().getDevice(),
+		commands._getRenderingThread().getDevice()._getAllocator(), 
 		Deleter());
 
 	if(!err)
@@ -118,8 +118,8 @@ Error BufferHandle::create(CommandBufferHandle& commands,
 	using Deleter = GlHandleDeferredDeleter<BufferImpl, Alloc, DeleteCommand>;
 
 	Error err = _createAdvanced(
-		&commands._getQueue().getDevice(),
-		commands._getQueue().getDevice()._getAllocator(), 
+		&commands._getRenderingThread().getDevice(),
+		commands._getRenderingThread().getDevice()._getAllocator(), 
 		Deleter());
 
 	if(!err)

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

@@ -3,10 +3,10 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#include <cstring>
 #include "anki/gr/gl/BufferImpl.h"
-#include "anki/gr/GlError.h"
+#include "anki/gr/gl/Error.h"
 #include "anki/util/Logger.h"
+#include <cstring>
 #include <cmath>
 
 namespace anki {

+ 6 - 7
src/gr/gl/CommandBufferHandle.cpp

@@ -5,7 +5,6 @@
 
 #include "anki/gr/CommandBufferHandle.h"
 #include "anki/gr/GlDevice.h"
-#include "anki/gr/GlSyncHandles.h"
 #include "anki/gr/gl/FramebufferImpl.h"
 #include "anki/gr/TextureHandle.h"
 #include "anki/gr/gl/TextureImpl.h"
@@ -148,7 +147,7 @@ Error CommandBufferHandle::create(GlDevice* gl,
 
 	if(!err)
 	{
-		err = _get().create(&gl->_getQueue(), hints);
+		err = _get().create(&gl->_getRenderingThread(), hints);
 	}
 
 	return err;
@@ -206,13 +205,13 @@ void CommandBufferHandle::pushBackOtherCommandBuffer(
 //==============================================================================
 void CommandBufferHandle::flush()
 {
-	_get().getQueue().flushCommandBuffer(*this);
+	_get().getRenderingThread().flushCommandBuffer(*this);
 }
 
 //==============================================================================
 void CommandBufferHandle::finish()
 {
-	_get().getQueue().finishCommandBuffer(*this);
+	_get().getRenderingThread().finishCommandBuffer(*this);
 }
 
 //==============================================================================
@@ -254,7 +253,7 @@ void CommandBufferHandle::setViewport(U16 minx, U16 miny, U16 maxx, U16 maxy)
 
 		Error operator()(CommandBufferImpl* commands)
 		{
-			GlState& state = commands->getQueue().getState();
+			State& state = commands->getRenderingThread().getState();
 
 			if(state.m_viewport[0] != m_value[0] 
 				|| state.m_viewport[1] != m_value[1]
@@ -351,7 +350,7 @@ void CommandBufferHandle::setBlendFunctions(GLenum sfactor, GLenum dfactor)
 
 		Error operator()(CommandBufferImpl* commands)
 		{
-			GlState& state = commands->getQueue().getState();
+			State& state = commands->getRenderingThread().getState();
 
 			if(state.m_blendSfunc != m_sfactor 
 				|| state.m_blendDfunc != m_dfactor)
@@ -623,7 +622,7 @@ public:
 		BufferImpl& buff = m_buff._get();
 
 		// Bind
-		GLuint copyFbo = cmd->getQueue().getCopyFbo();
+		GLuint copyFbo = cmd->getRenderingThread().getCopyFbo();
 		glBindFramebuffer(GL_FRAMEBUFFER, copyFbo);
 
 		// Attach texture

+ 9 - 19
src/gr/gl/CommandBufferImpl.cpp

@@ -4,9 +4,8 @@
 // http://www.anki3d.org/LICENSE
 
 #include "anki/gr/gl/CommandBufferImpl.h"
-#include "anki/gr/gl/Queue.h"
-#include "anki/gr/GlDevice.h"
-#include "anki/gr/GlError.h"
+#include "anki/gr/GrManager.h"
+#include "anki/gr/gl/Error.h"
 #include "anki/util/Logger.h"
 #include "anki/core/Counters.h"
 #include <cstring>
@@ -14,18 +13,15 @@
 namespace anki {
 
 //==============================================================================
-Error CommandBufferImpl::create(Queue* server, 
-	const CommandBufferImplInitHints& hints)
+Error CommandBufferImpl::create(const CommandBufferImplInitHints& hints)
 {
-	ANKI_ASSERT(server);
+	auto& pool = getManager().getAllocator().getMemoryPool();
 
-	m_server = server;
-
-	m_alloc = GlCommandBufferAllocator<GlCommand*>(
-		m_server->getAllocationCallback(),
-		m_server->getAllocationCallbackUserData(),
+	m_alloc = CommandBufferAllocator<GlCommand*>(
+		pool.getAllocationCallback(),
+		pool.getAllocationCallbackUserData(),
 		hints.m_chunkSize, 
-		CommandBufferImplInitHints::MAX_CHUNK_SIZE, 
+		InitHints::MAX_CHUNK_SIZE, 
 		ChainMemoryPool::ChunkGrowMethod::ADD,
 		hints.m_chunkSize);
 
@@ -54,13 +50,7 @@ void CommandBufferImpl::destroy()
 	ANKI_ASSERT(m_alloc.getMemoryPool().getUsersCount() == 1 
 		&& "Someone is holding a reference to the command buffer's allocator");
 
-	m_alloc = GlCommandBufferAllocator<U8>();
-}
-
-//==============================================================================
-GlAllocator<U8> CommandBufferImpl::getGlobalAllocator() const
-{
-	return m_server->getDevice()._getAllocator();
+	m_alloc = CommandBufferAllocator<U8>();
 }
 
 //==============================================================================

+ 0 - 0
src/gr/GlError.cpp → src/gr/gl/Error.cpp


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

@@ -70,7 +70,7 @@ Error FramebufferHandle::create(
 		GlHandleDeferredDeleter<FramebufferImpl, Alloc, DeleteCommand>;
 
 	Error err = _createAdvanced(
-		&commands._get().getQueue().getDevice(),
+		&commands._get().getRenderingThread().getDevice(),
 		commands._get().getGlobalAllocator(), 
 		Deleter());
 

+ 40 - 0
src/gr/gl/GlObject.cpp

@@ -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
+
+#include "anki/gr/gl/GlObject.h"
+#include "anki/gr/GrManager.h"
+#include "anki/gr/gl/GrManagerImpl.h"
+#include "anki/gr/gl/RenderingThread.h"
+
+namespace anki {
+
+//==============================================================================
+Error GlObject::serializeOnGetter() const
+{
+	Error err = ErrorCode::NONE;
+	State state = State(m_state.load());
+	ANKI_ASSERT(state != State::NEW);
+	
+	if(state == State::TO_BE_CREATED)
+	{
+		auto& thread = getManager().getImplementation().getRenderingThread();
+		thread.syncClientServer();
+
+		state = State(m_state.load());
+
+		if(state == State::ERROR)
+		{
+			err = ErrorCode::UNKNOWN;
+		}
+	}
+
+	ANKI_ASSERT(state > State::TO_BE_CREATED);
+
+	return err;
+}
+
+} // end namespace anki
+
+

+ 46 - 0
src/gr/gl/GrManagerImpl.cpp

@@ -0,0 +1,46 @@
+// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include "anki/gr/gl/GrManagerImpl.h"
+#include "anki/gr/gl/RenderingThread.h"
+
+namespace anki {
+
+//==============================================================================
+Error GlManagerImpl::create(GrManagerInitializer& init)
+{
+	Error err = ErrorCode::NONE;
+
+	// Create thread
+	m_thread = getAllocator().newInstance<RenderingThread>(m_manager);
+	if(!thread)
+	{
+		err = ErrorCode::OUT_OF_MEMORY;
+	}
+
+	// Start it
+	if(!err)
+	{
+		err = m_thread->start(init.m_makeCurrentCallback, 
+			init.m_makeCurrentCallbackData, init.m_ctx, 
+			init.m_swapBuffersCallback, init.m_swapBuffersCallbackData);
+	}
+
+	if(!err)
+	{
+		m_thread->syncClientServer();
+	}
+
+	return err;
+}
+
+//==============================================================================
+GrAllocator<U8> GlManagerImpl::getAllocator() const
+{
+	return m_manager->getAllocator();
+}
+
+} // end namespace anki
+

+ 2 - 2
src/gr/gl/PipelineHandle.cpp

@@ -78,7 +78,7 @@ Error PipelineHandle::commonConstructor(
 		GlHandleDeferredDeleter<PipelineImpl, Alloc, DeleteCommand>;
 
 	Error err = _createAdvanced(
-		&commands._get().getQueue().getDevice(),
+		&commands._get().getRenderingThread().getDevice(),
 		commands._get().getGlobalAllocator(), 
 		Deleter());
 
@@ -108,7 +108,7 @@ void PipelineHandle::bind(CommandBufferHandle& commands)
 
 		Error operator()(CommandBufferImpl* commands)
 		{
-			GlState& state = commands->getQueue().getState();
+			State& state = commands->getRenderingThread().getState();
 
 			if(state.m_crntPpline != m_ppline._get().getGlName())
 			{

+ 37 - 25
src/gr/gl/Queue.cpp → src/gr/gl/RenderingThread.cpp

@@ -3,9 +3,8 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#include "anki/gr/gl/Queue.h"
+#include "anki/gr/gl/RenderingThread.h"
 #include "anki/gr/gl/CommandBufferImpl.h"
-#include "anki/gr/GlSyncHandles.h"
 #include "anki/gr/GlDevice.h"
 #include "anki/util/Logger.h"
 #include "anki/core/Counters.h"
@@ -13,7 +12,25 @@
 namespace anki {
 
 //==============================================================================
-Queue::Queue(GlDevice* device, 
+// Misc                                                                        =
+//==============================================================================
+
+//==============================================================================
+class SyncCommand: public GlCommand
+{
+	ANKI_USE_RESULT Error operator()(CommandBufferImpl* cmd)
+	{
+		cmd->getRenderingThread().m_syncBarrier.wait();
+		return ErrorCode::NONE;
+	}
+};
+
+//==============================================================================
+// RenderingThread                                                             =
+//==============================================================================
+
+//==============================================================================
+RenderingThread::RenderingThread(GlDevice* device, 
 	AllocAlignedCallback allocCb, void* allocCbUserData)
 :	m_device(device), 
 	m_allocCb(allocCb),
@@ -27,11 +44,11 @@ Queue::Queue(GlDevice* device,
 }
 
 //==============================================================================
-Queue::~Queue()
+RenderingThread::~RenderingThread()
 {}
 
 //==============================================================================
-void Queue::flushCommandBuffer(CommandBufferHandle& commands)
+void RenderingThread::flushCommandBuffer(CommandBufferHandle& commands)
 {
 	commands._get().makeImmutable();
 
@@ -66,20 +83,20 @@ void Queue::flushCommandBuffer(CommandBufferHandle& commands)
 }
 
 //==============================================================================
-void Queue::finishCommandBuffer(CommandBufferHandle& commands)
+void RenderingThread::finishCommandBuffer(CommandBufferHandle& commands)
 {
 #if !ANKI_QUEUE_DISABLE_ASYNC
 	flushCommandBuffer(commands);
 
 	flushCommandBuffer(m_syncCommands);
-	m_sync.wait();
+	m_syncBarrier.wait();
 #else
 	flushCommandBuffer(commands);
 #endif
 }
 
 //==============================================================================
-Error Queue::start(
+Error RenderingThread::start(
 	GlMakeCurrentCallback makeCurrentCb, void* makeCurrentCbData, void* ctx,
 	GlCallback swapBuffersCallback, void* swapBuffersCbData,
 	Bool registerMessages)
@@ -119,12 +136,7 @@ Error Queue::start(
 
 	if(!err)
 	{
-		err = m_sync.create(m_syncCommands);
-	}
-
-	if(!err)
-	{
-		m_sync.sync(m_syncCommands);
+		m_syncCommands._pushBackNewCommand<SyncCommand>();
 	}
 
 	if(err && threadStarted)
@@ -139,7 +151,7 @@ Error Queue::start(
 }
 
 //==============================================================================
-void Queue::stop()
+void RenderingThread::stop()
 {
 #if !ANKI_QUEUE_DISABLE_ASYNC
 	{
@@ -158,7 +170,7 @@ void Queue::stop()
 }
 
 //==============================================================================
-void Queue::prepare()
+void RenderingThread::prepare()
 {
 	ANKI_ASSERT(m_makeCurrentCb && m_ctx);
 	(*m_makeCurrentCb)(m_makeCurrentCbData, m_ctx);
@@ -186,7 +198,7 @@ void Queue::prepare()
 }
 
 //==============================================================================
-void Queue::finish()
+void RenderingThread::finish()
 {
 	// Iterate the queue and release the refcounts
 	for(U i = 0; i < m_queue.size(); i++)
@@ -210,15 +222,15 @@ void Queue::finish()
 }
 
 //==============================================================================
-Error Queue::threadCallback(Thread::Info& info)
+Error RenderingThread::threadCallback(Thread::Info& info)
 {
-	Queue* queue = reinterpret_cast<Queue*>(info.m_userData);
+	RenderingThread* queue = reinterpret_cast<RenderingThread*>(info.m_userData);
 	queue->threadLoop();
 	return ErrorCode::NONE;
 }
 
 //==============================================================================
-void Queue::threadLoop()
+void RenderingThread::threadLoop()
 {
 	prepare();
 
@@ -262,19 +274,19 @@ void Queue::threadLoop()
 }
 
 //==============================================================================
-void Queue::syncClientServer()
+void RenderingThread::syncClientServer()
 {
 #if !ANKI_QUEUE_DISABLE_ASYNC
 	flushCommandBuffer(m_syncCommands);
-	m_sync.wait();
+	m_syncBarrier.wait();
 #endif
 }
 
 //==============================================================================
-Error Queue::swapBuffersInternal(void* ptr)
+Error RenderingThread::swapBuffersInternal(void* ptr)
 {
 	ANKI_ASSERT(ptr);
-	Queue& self = *reinterpret_cast<Queue*>(ptr);
+	RenderingThread& self = *reinterpret_cast<RenderingThread*>(ptr);
 
 	// Do the swap buffers
 	self.m_swapBuffersCallback(self.m_swapBuffersCbData);
@@ -291,7 +303,7 @@ Error Queue::swapBuffersInternal(void* ptr)
 }
 
 //==============================================================================
-void Queue::swapBuffers()
+void RenderingThread::swapBuffers()
 {
 	// Wait for the rendering thread to finish swap buffers...
 	{

+ 3 - 3
src/gr/gl/ShaderHandle.cpp

@@ -31,8 +31,8 @@ public:
 	{
 		Error err = m_shader._get().create(m_type, 
 			reinterpret_cast<const char*>(m_source.getBaseAddress()),
-			commands->getQueue().getDevice()._getAllocator(),
-			commands->getQueue().getDevice()._getCacheDirectory());
+			commands->getRenderingThread().getDevice()._getAllocator(),
+			commands->getRenderingThread().getDevice()._getCacheDirectory());
 
 		GlHandleState oldState = m_shader._setState(
 			(err) ? GlHandleState::ERROR : GlHandleState::CREATED);
@@ -60,7 +60,7 @@ Error ShaderHandle::create(CommandBufferHandle& commands,
 	using Deleter = GlHandleDeferredDeleter<ShaderImpl, Alloc, DeleteCommand>;
 
 	Error err = _createAdvanced(
-		&commands._get().getQueue().getDevice(),
+		&commands._get().getRenderingThread().getDevice(),
 		commands._get().getGlobalAllocator(), 
 		Deleter());
 

+ 4 - 4
src/gr/gl/TextureHandle.cpp

@@ -107,8 +107,8 @@ Error TextureHandle::create(
 	using Deleter = GlHandleDeferredDeleter<TextureImpl, Alloc, DeleteCommand>;
 
 	Error err = _createAdvanced(
-		&commands._getQueue().getDevice(),
-		commands._getQueue().getDevice()._getAllocator(), 
+		&commands._getRenderingThread().getDevice(),
+		commands._getRenderingThread().getDevice()._getAllocator(), 
 		Deleter());
 
 	if(!err)
@@ -271,8 +271,8 @@ Error SamplerHandle::create(CommandBufferHandle& commands)
 	using Deleter = GlHandleDeferredDeleter<SamplerImpl, Alloc, DeleteCommand>;
 
 	Error err = _createAdvanced(
-		&commands._getQueue().getDevice(),
-		commands._getQueue().getDevice()._getAllocator(), 
+		&commands._getRenderingThread().getDevice(),
+		commands._getRenderingThread().getDevice()._getAllocator(), 
 		Deleter());
 
 	if(!err)