Browse Source

Fixing allocation related bugs

Panagiotis Christopoulos Charitos 11 years ago
parent
commit
ec18e6ec00

+ 4 - 0
include/anki/resource/Animation.h

@@ -65,6 +65,10 @@ public:
 class Animation
 class Animation
 {
 {
 public:
 public:
+	Animation(ResourceAllocator<U8>& alloc);
+
+	~Animation();
+
 	void load(const CString& filename, ResourceInitializer& init);
 	void load(const CString& filename, ResourceInitializer& init);
 
 
 	/// Get a vector of all animation channels
 	/// Get a vector of all animation channels

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

@@ -17,7 +17,8 @@ namespace anki {
 class DummyRsrc
 class DummyRsrc
 {
 {
 public:
 public:
-	DummyRsrc()
+	DummyRsrc(ResourceAllocator<U8>& alloc)
+	:	m_alloc(alloc)
 	{}
 	{}
 
 
 	~DummyRsrc()
 	~DummyRsrc()
@@ -32,10 +33,11 @@ public:
 	{
 	{
 		if(filename != "exception")
 		if(filename != "exception")
 		{
 		{
-			m_alloc = init.m_alloc;
 			m_memory = m_alloc.allocate(128);
 			m_memory = m_alloc.allocate(128);
 			void* tempMem = init.m_tempAlloc.allocate(128);
 			void* tempMem = init.m_tempAlloc.allocate(128);
 			(void)tempMem;
 			(void)tempMem;
+
+			init.m_tempAlloc.deallocate(tempMem, 128);
 		}
 		}
 		else
 		else
 		{
 		{

+ 2 - 1
include/anki/resource/Material.h

@@ -309,7 +309,8 @@ class Material: public MaterialProperties, public NonCopyable
 	friend class MaterialVariable;
 	friend class MaterialVariable;
 
 
 public:
 public:
-	Material();
+	Material(ResourceAllocator<U8>& alloc);
+
 	~Material();
 	~Material();
 
 
 	/// Access the base class just for copying in other classes
 	/// Access the base class just for copying in other classes

+ 4 - 5
include/anki/resource/Mesh.h

@@ -35,11 +35,9 @@ class Mesh
 {
 {
 public:
 public:
 	/// Default constructor
 	/// Default constructor
-	Mesh()
-	{}
+	Mesh(ResourceAllocator<U8>& alloc);
 
 
-	~Mesh()
-	{}
+	~Mesh();
 
 
 	U32 getTextureChannelsCount() const
 	U32 getTextureChannelsCount() const
 	{
 	{
@@ -130,7 +128,8 @@ class BucketMesh: public Mesh
 {
 {
 public:
 public:
 	/// Default constructor.
 	/// Default constructor.
-	BucketMesh()
+	BucketMesh(ResourceAllocator<U8>& alloc)
+	:	Mesh(alloc)
 	{}
 	{}
 
 
 	~BucketMesh()
 	~BucketMesh()

+ 2 - 1
include/anki/resource/Model.h

@@ -161,7 +161,8 @@ private:
 class Model
 class Model
 {
 {
 public:
 public:
-	Model();
+	Model(ResourceAllocator<U8>& alloc);
+
 	~Model();
 	~Model();
 
 
 	/// @name Accessors
 	/// @name Accessors

+ 2 - 1
include/anki/resource/ParticleEmitterResource.h

@@ -92,7 +92,8 @@ public:
 class ParticleEmitterResource: private ParticleEmitterProperties
 class ParticleEmitterResource: private ParticleEmitterProperties
 {
 {
 public:
 public:
-	ParticleEmitterResource();
+	ParticleEmitterResource(ResourceAllocator<U8>& alloc);
+
 	~ParticleEmitterResource();
 	~ParticleEmitterResource();
 
 
 	const ParticleEmitterProperties& getProperties() const
 	const ParticleEmitterProperties& getProperties() const

+ 1 - 1
include/anki/resource/ProgramResource.h

@@ -18,7 +18,7 @@ namespace anki {
 class ProgramResource
 class ProgramResource
 {
 {
 public:
 public:
-	ProgramResource()
+	ProgramResource(ResourceAllocator<U8>&)
 	{}
 	{}
 
 
 	~ProgramResource()
 	~ProgramResource()

+ 5 - 0
include/anki/resource/ResourcePointer.h

@@ -6,6 +6,7 @@
 #ifndef ANKI_RESOURCE_RESOURCE_POINTER_H
 #ifndef ANKI_RESOURCE_RESOURCE_POINTER_H
 #define ANKI_RESOURCE_RESOURCE_POINTER_H
 #define ANKI_RESOURCE_RESOURCE_POINTER_H
 
 
+#include "anki/resource/Common.h"
 #include "anki/util/Assert.h"
 #include "anki/util/Assert.h"
 #include "anki/util/Atomic.h"
 #include "anki/util/Atomic.h"
 #include <cstring>
 #include <cstring>
@@ -131,6 +132,10 @@ private:
 	class ControlBlock
 	class ControlBlock
 	{
 	{
 	public:
 	public:
+		ControlBlock(ResourceAllocator<U8>& alloc)
+		:	m_resource(alloc)
+		{}
+
 		Type m_resource;
 		Type m_resource;
 		AtomicU32 m_refcount = {1};
 		AtomicU32 m_refcount = {1};
 		TResourceManager* m_resources = nullptr;
 		TResourceManager* m_resources = nullptr;

+ 32 - 18
include/anki/resource/ResourcePointer.inl.h

@@ -32,7 +32,7 @@ void ResourcePointer<T, TResourceManager>::load(
 		// Construct
 		// Construct
 		try
 		try
 		{
 		{
-			alloc.construct(m_cb);
+			alloc.construct(m_cb, alloc);
 		}
 		}
 		catch(const std::exception& e)
 		catch(const std::exception& e)
 		{
 		{
@@ -41,30 +41,44 @@ void ResourcePointer<T, TResourceManager>::load(
 			throw ANKI_EXCEPTION("Control block construction failed") << e;
 			throw ANKI_EXCEPTION("Control block construction failed") << e;
 		}
 		}
 
 
-		// Populate the m_cb
-		TempResourceString newFname(resources->fixResourceFilename(filename));
+		// Populate the m_cb. Use a block ton cleanup temp_pool allocations
+		auto& pool = resources->_getTempAllocator().getMemoryPool();
 
 
-		try
-		{
-			ResourceInitializer init(
-				alloc,
-				resources->_getTempAllocator(),
-				*resources);
-
-			m_cb->m_resource.load(newFname.toCString(), init);
-
-			resources->_getTempAllocator().getMemoryPool().reset();
-		}
-		catch(const std::exception& e)
 		{
 		{
-			alloc.deleteInstance(m_cb);
-			m_cb = nullptr;
-			throw ANKI_EXCEPTION("Loading failed: %s", &newFname[0]) << e;
+			TempResourceString newFname(
+				resources->fixResourceFilename(filename));
+
+			try
+			{
+				ResourceInitializer init(
+					alloc,
+					resources->_getTempAllocator(),
+					*resources);
+
+				U allocsCountBefore = pool.getAllocationsCount();
+
+				m_cb->m_resource.load(newFname.toCString(), init);
+
+				ANKI_ASSERT(pool.getAllocationsCount() == allocsCountBefore
+					&& "Forgot to deallocate");
+			}
+			catch(const std::exception& e)
+			{
+				alloc.deleteInstance(m_cb);
+				m_cb = nullptr;
+				throw ANKI_EXCEPTION("Loading failed: %s", &newFname[0]) << e;
+			}
 		}
 		}
 
 
 		m_cb->m_resources = resources;
 		m_cb->m_resources = resources;
 		std::memcpy(&m_cb->m_uuid[0], &filename[0], len + 1);
 		std::memcpy(&m_cb->m_uuid[0], &filename[0], len + 1);
 
 
+		// Reset the memory pool if no-one is using it
+		if(pool.getAllocationsCount() > 0)
+		{
+			pool.reset();
+		}
+
 		// Register resource
 		// Register resource
 		resources->_registerResource(*this);
 		resources->_registerResource(*this);
 	}
 	}

+ 4 - 0
include/anki/resource/Skeleton.h

@@ -57,6 +57,10 @@ private:
 class Skeleton
 class Skeleton
 {
 {
 public:
 public:
+	Skeleton(ResourceAllocator<U8>& alloc);
+
+	~Skeleton();
+
 	/// Load file
 	/// Load file
 	void load(const CString& filename, ResourceInitializer& init);
 	void load(const CString& filename, ResourceInitializer& init);
 
 

+ 4 - 0
include/anki/resource/TextureResource.h

@@ -24,6 +24,10 @@ class Image;
 class TextureResource
 class TextureResource
 {
 {
 public:
 public:
+	TextureResource(ResourceAllocator<U8>& alloc);
+
+	~TextureResource();
+
 	/// Load a texture
 	/// Load a texture
 	void load(const CString& filename, ResourceInitializer& init);
 	void load(const CString& filename, ResourceInitializer& init);
 
 

+ 30 - 33
include/anki/util/Allocator.h

@@ -29,19 +29,20 @@ namespace anki {
 /// This is a template that accepts memory pools with a specific interface
 /// This is a template that accepts memory pools with a specific interface
 ///
 ///
 /// @tparam T The type
 /// @tparam T The type
-/// @tparam deallocationFlag If true then the allocator will try to deallocate
-///                          the memory. It is extremely important to
-///                          understand when it should be true. See notes
+/// @tparam checkFree If false then the allocator will throw an exception
+///                   if the free() method of the memory pool returns false.
+///                   It is extremely important to understand when it should be 
+///                   true. See the notes.
 ///
 ///
-/// @note The deallocationFlag can brake the allocator when used with stack 
-///       pools and the deallocations are not in the correct order.
+/// @note The checkFree can brake the allocator when used with stack pools 
+///       and the deallocations are not in the correct order.
 ///
 ///
 /// @note Don't ever EVER remove the double copy constructor and the double
 /// @note Don't ever EVER remove the double copy constructor and the double
 ///       operator=. The compiler will create defaults
 ///       operator=. The compiler will create defaults
-template<typename T, typename TPool, Bool deallocationFlag = false>
+template<typename T, typename TPool, Bool checkFree = false>
 class GenericPoolAllocator
 class GenericPoolAllocator
 {
 {
-	template<typename Y, typename TPool_, Bool deallocationFlag_>
+	template<typename Y, typename TPool_, Bool checkFree_>
 	friend class GenericPoolAllocator;
 	friend class GenericPoolAllocator;
 
 
 public:
 public:
@@ -63,7 +64,7 @@ public:
 	template<typename Y>
 	template<typename Y>
 	struct rebind
 	struct rebind
 	{
 	{
-		typedef GenericPoolAllocator<Y, TPool, deallocationFlag> other;
+		typedef GenericPoolAllocator<Y, TPool, checkFree> other;
 	};
 	};
 
 
 	/// Default constructor
 	/// Default constructor
@@ -79,7 +80,7 @@ public:
 	/// Copy constructor
 	/// Copy constructor
 	template<typename Y>
 	template<typename Y>
 	GenericPoolAllocator(const GenericPoolAllocator<
 	GenericPoolAllocator(const GenericPoolAllocator<
-		Y, TPool, deallocationFlag>& b) noexcept
+		Y, TPool, checkFree>& b) noexcept
 	{
 	{
 		*this = b;
 		*this = b;
 	}
 	}
@@ -103,7 +104,7 @@ public:
 	/// Copy
 	/// Copy
 	template<typename U>
 	template<typename U>
 	GenericPoolAllocator& operator=(const GenericPoolAllocator<
 	GenericPoolAllocator& operator=(const GenericPoolAllocator<
-		U, TPool, deallocationFlag>& b)
+		U, TPool, checkFree>& b)
 	{
 	{
 		m_pool = b.m_pool;
 		m_pool = b.m_pool;
 		return *this;
 		return *this;
@@ -150,18 +151,14 @@ public:
 	/// Deallocate memory
 	/// Deallocate memory
 	void deallocate(void* p, size_type n)
 	void deallocate(void* p, size_type n)
 	{
 	{
-		(void)p;
 		(void)n;
 		(void)n;
 
 
-		if(deallocationFlag)
-		{
-			Bool ok = m_pool.free(p);
+		Bool ok = m_pool.free(p);
 
 
-			if(!ok)
-			{
-				throw ANKI_EXCEPTION("Freeing wrong pointer. "
-					"Pool's free returned false");
-			}
+		if(checkFree && !ok)
+		{
+			throw ANKI_EXCEPTION("Freeing wrong pointer. "
+				"Pool's free returned false");
 		}
 		}
 	}
 	}
 
 
@@ -275,38 +272,38 @@ private:
 /// @{
 /// @{
 
 
 /// Another allocator of the same type can deallocate from this one
 /// Another allocator of the same type can deallocate from this one
-template<typename T1, typename T2, typename TPool, Bool deallocationFlag>
+template<typename T1, typename T2, typename TPool, Bool checkFree>
 inline bool operator==(
 inline bool operator==(
-	const GenericPoolAllocator<T1, TPool, deallocationFlag>&,
-	const GenericPoolAllocator<T2, TPool, deallocationFlag>&)
+	const GenericPoolAllocator<T1, TPool, checkFree>&,
+	const GenericPoolAllocator<T2, TPool, checkFree>&)
 {
 {
 	return true;
 	return true;
 }
 }
 
 
 /// Another allocator of the another type cannot deallocate from this one
 /// Another allocator of the another type cannot deallocate from this one
 template<typename T1, typename AnotherAllocator, typename TPool, 
 template<typename T1, typename AnotherAllocator, typename TPool, 
-	Bool deallocationFlag>
+	Bool checkFree>
 inline bool operator==(
 inline bool operator==(
-	const GenericPoolAllocator<T1, TPool, deallocationFlag>&,
+	const GenericPoolAllocator<T1, TPool, checkFree>&,
 	const AnotherAllocator&)
 	const AnotherAllocator&)
 {
 {
 	return false;
 	return false;
 }
 }
 
 
 /// Another allocator of the same type can deallocate from this one
 /// Another allocator of the same type can deallocate from this one
-template<typename T1, typename T2, typename TPool, Bool deallocationFlag>
+template<typename T1, typename T2, typename TPool, Bool checkFree>
 inline bool operator!=(
 inline bool operator!=(
-	const GenericPoolAllocator<T1, TPool, deallocationFlag>&,
-	const GenericPoolAllocator<T2, TPool, deallocationFlag>&)
+	const GenericPoolAllocator<T1, TPool, checkFree>&,
+	const GenericPoolAllocator<T2, TPool, checkFree>&)
 {
 {
 	return false;
 	return false;
 }
 }
 
 
 /// Another allocator of the another type cannot deallocate from this one
 /// Another allocator of the another type cannot deallocate from this one
 template<typename T1, typename AnotherAllocator, typename TPool, 
 template<typename T1, typename AnotherAllocator, typename TPool, 
-	Bool deallocationFlag>
+	Bool checkFree>
 inline bool operator!=(
 inline bool operator!=(
-	const GenericPoolAllocator<T1, TPool, deallocationFlag>&,
+	const GenericPoolAllocator<T1, TPool, checkFree>&,
 	const AnotherAllocator&)
 	const AnotherAllocator&)
 {
 {
 	return true;
 	return true;
@@ -321,14 +318,14 @@ using HeapAllocator =
 	GenericPoolAllocator<T, HeapMemoryPool, true>;
 	GenericPoolAllocator<T, HeapMemoryPool, true>;
 
 
 /// Allocator that uses a StackMemoryPool
 /// Allocator that uses a StackMemoryPool
-template<typename T, Bool deallocationFlag = false>
+template<typename T, Bool checkFree = false>
 using StackAllocator = 
 using StackAllocator = 
-	GenericPoolAllocator<T, StackMemoryPool, deallocationFlag>;
+	GenericPoolAllocator<T, StackMemoryPool, checkFree>;
 
 
 /// Allocator that uses a ChainMemoryPool
 /// Allocator that uses a ChainMemoryPool
-template<typename T, Bool deallocationFlag = true>
+template<typename T, Bool checkFree = true>
 using ChainAllocator = 
 using ChainAllocator = 
-	GenericPoolAllocator<T, ChainMemoryPool, deallocationFlag>;
+	GenericPoolAllocator<T, ChainMemoryPool, checkFree>;
 
 
 /// @}
 /// @}
 
 

+ 19 - 1
include/anki/util/File.h

@@ -8,6 +8,7 @@
 
 
 #include "anki/util/String.h"
 #include "anki/util/String.h"
 #include "anki/util/Enum.h"
 #include "anki/util/Enum.h"
+#include "anki/util/NonCopyable.h"
 
 
 namespace anki {
 namespace anki {
 
 
@@ -32,7 +33,7 @@ namespace anki {
 /// - If the filename starts with '$' it will try to load a system specific 
 /// - If the filename starts with '$' it will try to load a system specific 
 ///   file. For Android this is a file in the .apk
 ///   file. For Android this is a file in the .apk
 /// - If the above are false then try to load a regular C file
 /// - If the above are false then try to load a regular C file
-class File
+class File: public NonCopyable
 {
 {
 public:
 public:
 	/// Open mode
 	/// Open mode
@@ -66,9 +67,18 @@ public:
 		open(filename, openMask);
 		open(filename, openMask);
 	}
 	}
 
 
+	/// Move
+	File(File&& b)
+	{
+		*this = std::move(b);
+	}
+
 	/// Closes the file if it's open
 	/// Closes the file if it's open
 	~File();
 	~File();
 
 
+	/// Move 
+	File& operator=(File&& b);
+
 	/// Open a file
 	/// Open a file
 	/// @param[in] filename The file to open
 	/// @param[in] filename The file to open
 	/// @param[in] openMask The open flags. It's a combination of OpenFlag enum
 	/// @param[in] openMask The open flags. It's a combination of OpenFlag enum
@@ -157,6 +167,14 @@ private:
 
 
 	/// The file should be open
 	/// The file should be open
 	PtrSize getSize();
 	PtrSize getSize();
+
+	void zero()
+	{
+		m_file = nullptr;
+		m_type = Type::NONE;
+		m_flags = OpenFlag::NONE;
+		m_size = 0;
+	}
 };
 };
 
 
 /// @}
 /// @}

+ 3 - 0
include/anki/util/Memory.h

@@ -185,6 +185,9 @@ public:
 	/// @param s The snapshot to be used
 	/// @param s The snapshot to be used
 	void resetUsingSnapshot(Snapshot s);
 	void resetUsingSnapshot(Snapshot s);
 
 
+	/// Return number of allocations
+	U32 getAllocationsCount() const;
+
 private:
 private:
 	// Forward. Hide the implementation because Memory.h is the base of other
 	// Forward. Hide the implementation because Memory.h is the base of other
 	// files and should not include them
 	// files and should not include them

+ 10 - 5
include/anki/util/String.h

@@ -126,7 +126,7 @@ public:
 	/// Return true if the string is not initialized.
 	/// Return true if the string is not initialized.
 	Bool isEmpty() const noexcept
 	Bool isEmpty() const noexcept
 	{
 	{
-		return m_ptr == nullptr;
+		return m_ptr == nullptr || getLength() == 0;
 	}
 	}
 
 
 	Bool operator==(const CString& b) const noexcept
 	Bool operator==(const CString& b) const noexcept
@@ -386,16 +386,21 @@ public:
 	template<typename TTAlloc>
 	template<typename TTAlloc>
 	Self& operator+=(const StringBase<TTAlloc>& b)
 	Self& operator+=(const StringBase<TTAlloc>& b)
 	{
 	{
-		b.checkInit();
-		append(&b.m_data[0], b.m_data.size());
+		if(!b.isEmpty())
+		{
+			append(&b.m_data[0], b.m_data.size());
+		}
 		return *this;
 		return *this;
 	}
 	}
 
 
 	/// Append a const string to this one.
 	/// Append a const string to this one.
 	Self& operator+=(const CStringType& cstr)
 	Self& operator+=(const CStringType& cstr)
 	{
 	{
-		U size = cstr.getLength() + 1;
-		append(cstr.get(), size);
+		if(!cstr.isEmpty())
+		{
+			U size = cstr.getLength() + 1;
+			append(cstr.get(), size);
+		}
 		return *this;
 		return *this;
 	}
 	}
 
 

+ 5 - 0
include/anki/util/StringList.inl.h

@@ -13,6 +13,11 @@ template<typename TAlloc>
 typename StringListBase<TAlloc>::String 
 typename StringListBase<TAlloc>::String 
 	StringListBase<TAlloc>::join(const CString& separator) const
 	StringListBase<TAlloc>::join(const CString& separator) const
 {
 {
+	if(Base::size() == 0)
+	{
+		return String(Base::get_allocator());
+	}
+
 	// Count the characters
 	// Count the characters
 	I sepLen = separator.getLength();
 	I sepLen = separator.getLength();
 	I charCount = 0;
 	I charCount = 0;

+ 9 - 0
src/resource/Animation.cpp

@@ -9,6 +9,15 @@
 
 
 namespace anki {
 namespace anki {
 
 
+//==============================================================================
+Animation::Animation(ResourceAllocator<U8>& alloc)
+:	m_channels(alloc)
+{}
+
+//==============================================================================
+Animation::~Animation()
+{}
+
 //==============================================================================
 //==============================================================================
 void Animation::load(const CString& filename, ResourceInitializer& init)
 void Animation::load(const CString& filename, ResourceInitializer& init)
 {
 {

+ 15 - 20
src/resource/Material.cpp

@@ -126,7 +126,12 @@ U32 MaterialVariable::getArraySize() const
 //==============================================================================
 //==============================================================================
 
 
 //==============================================================================
 //==============================================================================
-Material::Material()
+Material::Material(ResourceAllocator<U8>& alloc)
+:	m_vars(alloc),
+	m_varDict(10, Dictionary<MaterialVariable*>::hasher(),
+		Dictionary<MaterialVariable*>::key_equal(), alloc),
+	m_progs(alloc),
+	m_pplines(alloc)
 {}
 {}
 
 
 //==============================================================================
 //==============================================================================
@@ -264,18 +269,7 @@ void Material::load(const CString& filename, ResourceInitializer& init)
 {
 {
 	try
 	try
 	{
 	{
-		m_vars = std::move(ResourceVector<MaterialVariable*>(init.m_alloc));
-
-		Dictionary<MaterialVariable*> dict(10, 
-			Dictionary<MaterialVariable*>::hasher(),
-			Dictionary<MaterialVariable*>::key_equal(),
-			init.m_alloc);
-		m_varDict = std::move(dict);
-
-		m_progs = 
-			std::move(ResourceVector<ProgramResourcePointer>(init.m_alloc));
-		m_pplines = 
-			std::move(ResourceVector<GlProgramPipelineHandle>(init.m_alloc));
+		m_resources = &init.m_resources;
 
 
 		XmlDocument doc;
 		XmlDocument doc;
 		doc.loadFile(filename, init.m_tempAlloc);
 		doc.loadFile(filename, init.m_tempAlloc);
@@ -355,11 +349,11 @@ void Material::parseMaterialTag(const XmlElement& materialEl,
 
 
 	// shaderProgram
 	// shaderProgram
 	//
 	//
-	MaterialProgramCreator mspc(
+	MaterialProgramCreator loader(
 		materialEl.getChildElement("programs"),
 		materialEl.getChildElement("programs"),
 		rinit.m_tempAlloc);
 		rinit.m_tempAlloc);
 
 
-	m_tessellation = mspc.hasTessellation();
+	m_tessellation = loader.hasTessellation();
 	U tessCount = m_tessellation ? 2 : 1;
 	U tessCount = m_tessellation ? 2 : 1;
 
 
 	// Alloc program vector
 	// Alloc program vector
@@ -398,8 +392,9 @@ void Material::parseMaterialTag(const XmlElement& materialEl,
 
 
 					src.sprintf("#define LOD %u\n"
 					src.sprintf("#define LOD %u\n"
 						"#define PASS %u\n"
 						"#define PASS %u\n"
-						"#define TESSELLATION %u\n", 
-						level, pid, tess);
+						"#define TESSELLATION %u\n"
+						"%s\n", 
+						level, pid, tess, &loader.getProgramSource(shader)[0]);
 
 
 					TempResourceString filename =
 					TempResourceString filename =
 						createProgramSourceToChache(src);
 						createProgramSourceToChache(src);
@@ -415,7 +410,7 @@ void Material::parseMaterialTag(const XmlElement& materialEl,
 		}
 		}
 	}
 	}
 
 
-	populateVariables(mspc);
+	populateVariables(loader);
 
 
 	// Get uniform block size
 	// Get uniform block size
 	ANKI_ASSERT(m_progs.size() > 0);
 	ANKI_ASSERT(m_progs.size() > 0);
@@ -450,9 +445,9 @@ TempResourceString Material::createProgramSourceToChache(
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-void Material::populateVariables(const MaterialProgramCreator& mspc)
+void Material::populateVariables(const MaterialProgramCreator& loader)
 {
 {
-	for(auto in : mspc.getInputVariables())
+	for(auto in : loader.getInputVariables())
 	{
 	{
 		if(in.m_constant)
 		if(in.m_constant)
 		{
 		{

+ 10 - 2
src/resource/Mesh.cpp

@@ -15,6 +15,15 @@ namespace anki {
 // Mesh                                                                        =
 // Mesh                                                                        =
 //==============================================================================
 //==============================================================================
 
 
+//==============================================================================
+Mesh::Mesh(ResourceAllocator<U8>& alloc)
+:	m_subMeshes(alloc)
+{}
+
+//==============================================================================
+Mesh::~Mesh()
+{}
+
 //==============================================================================
 //==============================================================================
 Bool Mesh::isCompatible(const Mesh& other) const
 Bool Mesh::isCompatible(const Mesh& other) const
 {
 {
@@ -79,7 +88,7 @@ void Mesh::createBuffers(const MeshLoader& loader,
 	U32 vbosize = vertexsize * m_vertsCount;
 	U32 vbosize = vertexsize * m_vertsCount;
 
 
 	// Create a temp buffer and populate it
 	// Create a temp buffer and populate it
-	Vector<U8> buff(vbosize, 0);
+	TempResourceVector<U8> buff(vbosize, 0, init.m_tempAlloc);
 
 
 	U8* ptra = &buff[0];
 	U8* ptra = &buff[0];
 	for(U i = 0; i < m_vertsCount; i++)
 	for(U i = 0; i < m_vertsCount; i++)
@@ -237,7 +246,6 @@ void BucketMesh::load(const CString& filename, ResourceInitializer& init)
 		XmlElement meshEl = meshesEl.getChildElement("mesh");
 		XmlElement meshEl = meshesEl.getChildElement("mesh");
 
 
 		m_vertsCount = 0;
 		m_vertsCount = 0;
-		m_subMeshes = std::move(ResourceVector<SubMesh>(init.m_alloc));
 		m_subMeshes.reserve(4);
 		m_subMeshes.reserve(4);
 		m_indicesCount = 0;
 		m_indicesCount = 0;
 
 

+ 3 - 1
src/resource/Model.cpp

@@ -268,7 +268,9 @@ ModelPatch<MeshResourcePointerType>::ModelPatch(
 //==============================================================================
 //==============================================================================
 
 
 //==============================================================================
 //==============================================================================
-Model::Model()
+Model::Model(ResourceAllocator<U8>& alloc)
+:	m_modelPatches(alloc),
+	m_animations(alloc)
 {}
 {}
 
 
 //==============================================================================
 //==============================================================================

+ 1 - 1
src/resource/ParticleEmitterResource.cpp

@@ -85,7 +85,7 @@ void ParticleEmitterProperties::updateFlags()
 //==============================================================================
 //==============================================================================
 
 
 //==============================================================================
 //==============================================================================
-ParticleEmitterResource::ParticleEmitterResource()
+ParticleEmitterResource::ParticleEmitterResource(ResourceAllocator<U8>&)
 {}
 {}
 
 
 //==============================================================================
 //==============================================================================

+ 4 - 1
src/resource/ResourceManager.cpp

@@ -71,7 +71,10 @@ ResourceManager::ResourceManager(Initializer& init)
 
 
 //==============================================================================
 //==============================================================================
 ResourceManager::~ResourceManager()
 ResourceManager::~ResourceManager()
-{}
+{
+	ANKI_ASSERT(m_tmpAlloc.getMemoryPool().getAllocationsCount() == 0
+		&& "Forgot to deallocate");
+}
 
 
 //==============================================================================
 //==============================================================================
 TempResourceString ResourceManager::fixResourceFilename(
 TempResourceString ResourceManager::fixResourceFilename(

+ 9 - 1
src/resource/Skeleton.cpp

@@ -9,6 +9,15 @@
 
 
 namespace anki {
 namespace anki {
 
 
+//==============================================================================
+Skeleton::Skeleton(ResourceAllocator<U8>& alloc)
+:	m_bones(alloc)
+{}
+
+//==============================================================================
+Skeleton::~Skeleton()
+{}
+
 //==============================================================================
 //==============================================================================
 void Skeleton::load(const CString& filename, ResourceInitializer& init)
 void Skeleton::load(const CString& filename, ResourceInitializer& init)
 {
 {
@@ -30,7 +39,6 @@ void Skeleton::load(const CString& filename, ResourceInitializer& init)
 	} while(boneEl);
 	} while(boneEl);
 
 
 	// Alloc the vector
 	// Alloc the vector
-	m_bones = std::move(ResourceVector<Bone>(init.m_alloc));
 	m_bones.resize(bonesCount, Bone(init.m_alloc));
 	m_bones.resize(bonesCount, Bone(init.m_alloc));
 
 
 	// Load every bone
 	// Load every bone

+ 8 - 0
src/resource/TextureResource.cpp

@@ -24,6 +24,14 @@ static void deleteImageCallback(void* data)
 	alloc.deleteInstance(image);
 	alloc.deleteInstance(image);
 }
 }
 
 
+//==============================================================================
+TextureResource::TextureResource(ResourceAllocator<U8>&)
+{}
+
+//==============================================================================
+TextureResource::~TextureResource()
+{}
+
 //==============================================================================
 //==============================================================================
 void TextureResource::load(const CString& filename, ResourceInitializer& init)
 void TextureResource::load(const CString& filename, ResourceInitializer& init)
 {
 {

+ 40 - 16
src/util/File.cpp

@@ -13,10 +13,36 @@
 
 
 namespace anki {
 namespace anki {
 
 
+//==============================================================================
+// Misc
+
 #if ANKI_OS == ANKI_OS_ANDROID
 #if ANKI_OS == ANKI_OS_ANDROID
 extern android_app* gAndroidApp;
 extern android_app* gAndroidApp;
+
+#define ANKI_AFILE reinterpret_cast<AAsset*>(m_file)
 #endif
 #endif
 
 
+#define ANKI_CFILE reinterpret_cast<FILE*>(m_file)
+#define ANKI_ZFILE reinterpret_cast<void*>(m_file)
+
+//==============================================================================
+File& File::operator=(File&& b)
+{
+	close();
+
+	if(b.m_file != nullptr)
+	{
+		m_file = b.m_file;
+		m_type = b.m_type;
+		m_flags = b.m_flags;
+		m_size = b.m_size;
+	}
+
+	b.zero();
+
+	return *this;
+}
+
 //==============================================================================
 //==============================================================================
 File::~File()
 File::~File()
 {
 {
@@ -207,16 +233,16 @@ void File::close()
 	{
 	{
 		if(m_type == Type::C)
 		if(m_type == Type::C)
 		{
 		{
-			fclose(reinterpret_cast<FILE*>(m_file));
+			fclose(ANKI_CFILE);
 		}
 		}
 		else if(m_type == Type::ZIP)
 		else if(m_type == Type::ZIP)
 		{
 		{
-			unzClose(m_file);
+			unzClose(ANKI_ZFILE);
 		}
 		}
 #if ANKI_OS == ANKI_OS_ANDROID
 #if ANKI_OS == ANKI_OS_ANDROID
 		else if(m_type == Type::SPECIAL)
 		else if(m_type == Type::SPECIAL)
 		{
 		{
-			AAsset_close(reinterpret_cast<AAsset*>(m_file));
+			AAsset_close(ANKI_AFILE);
 		}
 		}
 #endif
 #endif
 		else
 		else
@@ -225,9 +251,7 @@ void File::close()
 		}
 		}
 	}
 	}
 
 
-	m_file = nullptr;
-	m_flags = OpenFlag::NONE;
-	m_type = Type::NONE;
+	zero();
 }
 }
 
 
 //==============================================================================
 //==============================================================================
@@ -239,7 +263,7 @@ void File::flush()
 	{
 	{
 		if(m_type == Type::C)
 		if(m_type == Type::C)
 		{
 		{
-			I err = fflush(reinterpret_cast<FILE*>(m_file));
+			I err = fflush(ANKI_CFILE);
 			if(err)
 			if(err)
 			{
 			{
 				throw ANKI_EXCEPTION("fflush() failed");
 				throw ANKI_EXCEPTION("fflush() failed");
@@ -272,7 +296,7 @@ void File::read(void* buff, PtrSize size)
 
 
 	if(m_type == Type::C)
 	if(m_type == Type::C)
 	{
 	{
-		readSize = fread(buff, 1, size, reinterpret_cast<FILE*>(m_file));
+		readSize = fread(buff, 1, size, ANKI_CFILE);
 	}
 	}
 	else if(m_type == Type::ZIP)
 	else if(m_type == Type::ZIP)
 	{
 	{
@@ -281,7 +305,7 @@ void File::read(void* buff, PtrSize size)
 #if ANKI_OS == ANKI_OS_ANDROID
 #if ANKI_OS == ANKI_OS_ANDROID
 	else if(m_type == Type::SPECIAL)
 	else if(m_type == Type::SPECIAL)
 	{
 	{
-		readSize = AAsset_read(reinterpret_cast<AAsset*>(m_file), buff, size);
+		readSize = AAsset_read(ANKI_AFILE, buff, size);
 	}
 	}
 #endif
 #endif
 	else
 	else
@@ -305,13 +329,13 @@ PtrSize File::getSize()
 	if(m_type == Type::C)
 	if(m_type == Type::C)
 	{
 	{
 		// Get file size
 		// Get file size
-		fseek(reinterpret_cast<FILE*>(m_file), 0, SEEK_END);
-		I64 size = ftell(reinterpret_cast<FILE*>(m_file));
+		fseek(ANKI_CFILE, 0, SEEK_END);
+		I64 size = ftell(ANKI_CFILE);
 		if(size < 1)
 		if(size < 1)
 		{
 		{
 			throw ANKI_EXCEPTION("ftell() failed");
 			throw ANKI_EXCEPTION("ftell() failed");
 		}
 		}
-		rewind(reinterpret_cast<FILE*>(m_file));
+		rewind(ANKI_CFILE);
 
 
 		out = size;
 		out = size;
 	}
 	}
@@ -323,7 +347,7 @@ PtrSize File::getSize()
 #if ANKI_OS == ANKI_OS_ANDROID
 #if ANKI_OS == ANKI_OS_ANDROID
 	else if(m_type == Type::SPECIAL)
 	else if(m_type == Type::SPECIAL)
 	{
 	{
-		out = AAsset_getLength(reinterpret_cast<AAsset*>(m_file));
+		out = AAsset_getLength(ANKI_AFILE);
 	}
 	}
 #endif
 #endif
 	else
 	else
@@ -398,7 +422,7 @@ void File::write(void* buff, PtrSize size)
 	if(m_type == Type::C)
 	if(m_type == Type::C)
 	{
 	{
 		PtrSize writeSize = 0;
 		PtrSize writeSize = 0;
-		writeSize = std::fwrite(buff, 1, size, reinterpret_cast<FILE*>(m_file));
+		writeSize = std::fwrite(buff, 1, size, ANKI_CFILE);
 
 
 		if(writeSize != size)
 		if(writeSize != size)
 		{
 		{
@@ -459,7 +483,7 @@ void File::seek(PtrSize offset, SeekOrigin origin)
 
 
 	if(m_type == Type::C)
 	if(m_type == Type::C)
 	{
 	{
-		if(fseek(reinterpret_cast<FILE*>(m_file), offset, (I)origin) != 0)
+		if(fseek(ANKI_CFILE, offset, (I)origin) != 0)
 		{
 		{
 			throw ANKI_EXCEPTION("fseek() failed");
 			throw ANKI_EXCEPTION("fseek() failed");
 		}
 		}
@@ -488,7 +512,7 @@ void File::seek(PtrSize offset, SeekOrigin origin)
 #if ANKI_OS == ANKI_OS_ANDROID
 #if ANKI_OS == ANKI_OS_ANDROID
 	else if(m_type == Type::SPECIAL)
 	else if(m_type == Type::SPECIAL)
 	{
 	{
-		if(AAsset_seek(reinterpret_cast<AAsset*>(file), offset, origin) 
+		if(AAsset_seek(ANKI_AFILE, offset, origin) 
 			== (off_t)-1)
 			== (off_t)-1)
 		{
 		{
 			throw ANKI_EXCEPTION("AAsset_seek() failed");
 			throw ANKI_EXCEPTION("AAsset_seek() failed");

+ 21 - 5
src/util/Memory.cpp

@@ -10,6 +10,7 @@
 #include "anki/util/NonCopyable.h"
 #include "anki/util/NonCopyable.h"
 #include "anki/util/Thread.h"
 #include "anki/util/Thread.h"
 #include "anki/util/Vector.h"
 #include "anki/util/Vector.h"
+#include "anki/util/Atomic.h"
 #include <cstdlib>
 #include <cstdlib>
 #include <cstring>
 #include <cstring>
 
 
@@ -117,8 +118,8 @@ void* allocAligned(
 class HeapMemoryPool::Implementation: public NonCopyable
 class HeapMemoryPool::Implementation: public NonCopyable
 {
 {
 public:
 public:
-	std::atomic<U32> m_refcount;
-	std::atomic<U32> m_allocationsCount;
+	AtomicU32 m_refcount;
+	AtomicU32 m_allocationsCount;
 	AllocAlignedCallback m_allocCb;
 	AllocAlignedCallback m_allocCb;
 	void* m_allocCbUserData;
 	void* m_allocCbUserData;
 
 
@@ -227,7 +228,7 @@ public:
 	static_assert(sizeof(MemoryBlockHeader) == sizeof(U32), "Size error");
 	static_assert(sizeof(MemoryBlockHeader) == sizeof(U32), "Size error");
 
 
 	/// Refcount
 	/// Refcount
-	std::atomic<U32> m_refcount = {1};
+	AtomicU32 m_refcount = {1};
 
 
 	/// User allocation function
 	/// User allocation function
 	AllocAlignedCallback m_allocCb;
 	AllocAlignedCallback m_allocCb;
@@ -248,7 +249,9 @@ public:
 	PtrSize m_memsize = 0;
 	PtrSize m_memsize = 0;
 
 
 	/// Points to the memory and more specifically to the top of the stack
 	/// Points to the memory and more specifically to the top of the stack
-	std::atomic<U8*> m_top = {nullptr};
+	Atomic<U8*> m_top = {nullptr};
+
+	AtomicU32 m_allocationsCount = {0};
 
 
 	// Construct
 	// Construct
 	Implementation(AllocAlignedCallback allocCb, void* allocCbUserData,
 	Implementation(AllocAlignedCallback allocCb, void* allocCbUserData,
@@ -340,6 +343,9 @@ public:
 
 
 			// Check alignment
 			// Check alignment
 			ANKI_ASSERT(isAligned(m_alignmentBytes, out));
 			ANKI_ASSERT(isAligned(m_alignmentBytes, out));
+
+			// Increase count
+			++m_allocationsCount;
 		}
 		}
 		else
 		else
 		{
 		{
@@ -387,6 +393,9 @@ public:
 		// }
 		// }
 		Bool exchange = m_top.compare_exchange_strong(expected, desired);
 		Bool exchange = m_top.compare_exchange_strong(expected, desired);
 
 
+		// Decrease count
+		--m_allocationsCount;
+
 		return exchange;
 		return exchange;
 	}
 	}
 
 
@@ -511,6 +520,13 @@ void StackMemoryPool::resetUsingSnapshot(Snapshot s)
 	m_impl->m_top.store(static_cast<U8*>(s));
 	m_impl->m_top.store(static_cast<U8*>(s));
 }
 }
 
 
+//==============================================================================
+U32 StackMemoryPool::getAllocationsCount() const
+{
+	ANKI_ASSERT(m_impl != nullptr);
+	return m_impl->m_allocationsCount.load();
+}
+
 //==============================================================================
 //==============================================================================
 // ChainMemoryPool                                                             =
 // ChainMemoryPool                                                             =
 //==============================================================================
 //==============================================================================
@@ -539,7 +555,7 @@ public:
 	};
 	};
 
 
 	/// Refcount
 	/// Refcount
-	std::atomic<U32> m_refcount = {1};
+	AtomicU32 m_refcount = {1};
 
 
 	/// User allocation function
 	/// User allocation function
 	AllocAlignedCallback m_allocCb;
 	AllocAlignedCallback m_allocCb;

+ 31 - 3
tests/util/String.cpp

@@ -85,7 +85,10 @@ ANKI_TEST(Util, String)
 
 
 		a += "456";
 		a += "456";
 		a += String("789", alloc);
 		a += String("789", alloc);
-		ANKI_TEST_EXPECT_EQ(a, "123456789");
+		a += String(alloc);
+		a += "";
+		a += "0";
+		ANKI_TEST_EXPECT_EQ(a, "1234567890");
 	}
 	}
 
 
 	// Compare
 	// Compare
@@ -112,16 +115,41 @@ ANKI_TEST(Util, String)
 
 
 		// Extreme
 		// Extreme
 		const char* s = "1234567890ABCDEF!@#$%^&*()_+asfghjkl:,.;ljk\"><{}[]/";
 		const char* s = "1234567890ABCDEF!@#$%^&*()_+asfghjkl:,.;ljk\"><{}[]/";
-		a.sprintf("%s%s%s%s%s%s%s%s%s%s %d", s, s, s, s, s, s, s, s, s, s, 88);
+		a.sprintf("%s%s%s%s%s%s%s%s%s%s%s %d", 
+			s, s, s, s, s, s, s, s, s, s, s, 88);
 
 
 		String b(alloc);
 		String b(alloc);
-		for(U i = 0; i < 10; i++)
+		for(U i = 0; i < 11; i++)
 		{
 		{
 			b += s;
 			b += s;
 		}
 		}
 		b += " 88";
 		b += " 88";
 
 
 		ANKI_TEST_EXPECT_EQ(a, b);
 		ANKI_TEST_EXPECT_EQ(a, b);
+		ANKI_TEST_EXPECT_EQ(a.getLength(), b.getLength());
+	}
+
+	// sprintf #2: Smaller result (will trigger another path)
+	{
+		String a(alloc);
+
+		// Simple
+		a.sprintf("12%c  %d", '3', 123);
+		ANKI_TEST_EXPECT_EQ(a, "123  123");
+
+		// Extreme
+		const char* s = "12345";
+		a.sprintf("%s%s %d", s, s, 88);
+
+		String b(alloc);
+		for(U i = 0; i < 2; i++)
+		{
+			b += s;
+		}
+		b += " 88";
+
+		ANKI_TEST_EXPECT_EQ(a, b);
+		ANKI_TEST_EXPECT_EQ(a.getLength(), b.getLength());
 	}
 	}
 
 
 	// Resize
 	// Resize