Explorar el Código

Some GR refactoring

Panagiotis Christopoulos Charitos hace 9 años
padre
commit
8ce42326b4
Se han modificado 54 ficheros con 719 adiciones y 501 borrados
  1. 6 8
      include/anki/gr/CommandBuffer.h
  2. 32 17
      include/anki/gr/Common.h
  3. 4 3
      include/anki/gr/GrManager.h
  4. 1 10
      include/anki/gr/ResourceGroup.h
  5. 3 5
      include/anki/gr/common/GpuBlockAllocator.h
  6. 1 2
      include/anki/gr/common/GpuFrameRingAllocator.h
  7. 36 11
      include/anki/gr/gl/CommandBufferImpl.h
  8. 49 9
      include/anki/gr/gl/DynamicMemoryManager.h
  9. 1 12
      include/anki/gr/gl/GlState.h
  10. 30 0
      include/anki/gr/gl/GrManagerImpl.h
  11. 5 15
      include/anki/gr/gl/RenderingThread.h
  12. 4 4
      include/anki/gr/gl/ResourceGroupImpl.h
  13. 3 3
      include/anki/renderer/Renderer.h
  14. 1 1
      include/anki/scene/RenderComponent.h
  15. 1 0
      sandbox/config.xml
  16. 0 1
      src/core/App.cpp
  17. 2 1
      src/core/Config.cpp
  18. 6 12
      src/gr/common/GpuBlockAllocator.cpp
  19. 4 9
      src/gr/common/GpuFrameRingAllocator.cpp
  20. 2 1
      src/gr/gl/Buffer.cpp
  21. 50 171
      src/gr/gl/CommandBuffer.cpp
  22. 208 5
      src/gr/gl/CommandBufferImpl.cpp
  23. 84 26
      src/gr/gl/DynamicMemoryManager.cpp
  24. 1 0
      src/gr/gl/Framebuffer.cpp
  25. 1 5
      src/gr/gl/GlState.cpp
  26. 10 8
      src/gr/gl/GrManager.cpp
  27. 16 1
      src/gr/gl/GrManagerImpl.cpp
  28. 2 1
      src/gr/gl/GrManagerImplSdl.cpp
  29. 1 0
      src/gr/gl/OcclusionQuery.cpp
  30. 1 0
      src/gr/gl/Pipeline.cpp
  31. 1 4
      src/gr/gl/PipelineImpl.cpp
  32. 19 42
      src/gr/gl/RenderingThread.cpp
  33. 1 0
      src/gr/gl/ResourceGroup.cpp
  34. 46 37
      src/gr/gl/ResourceGroupImpl.cpp
  35. 1 0
      src/gr/gl/Sampler.cpp
  36. 1 0
      src/gr/gl/Shader.cpp
  37. 1 0
      src/gr/gl/Texture.cpp
  38. 1 1
      src/gr/gl/TextureImpl.cpp
  39. 3 3
      src/renderer/Bloom.cpp
  40. 2 2
      src/renderer/Drawer.cpp
  41. 5 5
      src/renderer/Fs.cpp
  42. 3 3
      src/renderer/Ir.cpp
  43. 20 15
      src/renderer/Is.cpp
  44. 10 10
      src/renderer/Lf.cpp
  45. 1 2
      src/renderer/Renderer.cpp
  46. 7 7
      src/renderer/Ssao.cpp
  47. 3 3
      src/renderer/Tm.cpp
  48. 3 3
      src/renderer/Upsample.cpp
  49. 3 3
      src/renderer/Volumetric.cpp
  50. 1 1
      src/resource/Material.cpp
  51. 12 10
      src/resource/Mesh.cpp
  52. 6 5
      src/resource/TextureResource.cpp
  53. 1 1
      src/scene/LensFlareComponent.cpp
  54. 3 3
      src/ui/UiInterfaceImpl.cpp

+ 6 - 8
include/anki/gr/CommandBuffer.h

@@ -137,7 +137,7 @@ public:
 
 	/// Bind resources.
 	void bindResourceGroup(
-		ResourceGroupPtr rc, U slot, const DynamicBufferInfo* dynInfo);
+		ResourceGroupPtr rc, U slot, const TransientMemoryInfo* dynInfo);
 	/// @}
 
 	/// @name Jobs
@@ -182,15 +182,13 @@ public:
 	/// @{
 
 	/// Upload data to a texture.
-	void textureUpload(TexturePtr tex,
+	void uploadTextureSurface(TexturePtr tex,
 		const TextureSurfaceInfo& surf,
-		const DynamicBufferToken& token);
+		const TransientMemoryToken& token);
 
-	/// Write data to a buffer. It will copy the dynamic memory to the buffer
-	/// starting from offset to the range indicated by the allocation of the
-	/// token.
-	void writeBuffer(
-		BufferPtr buff, PtrSize offset, const DynamicBufferToken& token);
+	/// Upload data to a buffer.
+	void uploadBuffer(
+		BufferPtr buff, PtrSize offset, const TransientMemoryToken& token);
 	/// @}
 
 	/// @name Sync

+ 32 - 17
include/anki/gr/Common.h

@@ -24,9 +24,6 @@ class GrManagerInitInfo;
 class PipelineInitInfo;
 class FramebufferInitInfo;
 
-class DynamicBufferToken;
-class DynamicBufferInfo;
-
 /// @addtogroup graphics
 /// @{
 
@@ -70,20 +67,6 @@ enum GrObjectType : U16
 template<typename T>
 using GrAllocator = HeapAllocator<T>;
 
-/// Token that gets returned when requesting for memory to write to a dynamic
-/// buffer.
-class DynamicBufferToken
-{
-anki_internal:
-	U32 m_offset = 0;
-	U32 m_range = 0;
-
-	void markUnused()
-	{
-		m_offset = m_range = MAX_U32;
-	}
-};
-
 /// Clear values for textures or attachments.
 class ClearValue
 {
@@ -134,6 +117,38 @@ const U MAX_ATOMIC_BUFFER_BINDINGS = 1;
 const U MAX_FRAMES_IN_FLIGHT = 3; ///< Triple buffering.
 const U MAX_RESOURCE_GROUPS = 2; ///< Groups that can be bound at the same time.
 
+/// The life expectancy of a TransientMemoryToken.
+enum class TransientMemoryTokenLifetime : U8
+{
+	PER_FRAME,
+	PERSISTENT
+};
+
+/// Token that gets returned when requesting for memory to write to a resource.
+class TransientMemoryToken
+{
+anki_internal:
+	PtrSize m_offset = 0;
+	PtrSize m_range = 0;
+	TransientMemoryTokenLifetime m_lifetime =
+		TransientMemoryTokenLifetime::PER_FRAME;
+	BufferUsage m_usage = BufferUsage::COUNT;
+
+	void markUnused()
+	{
+		m_offset = m_range = MAX_U32;
+	}
+};
+
+/// Struct to help update the offset of the dynamic buffers.
+class TransientMemoryInfo
+{
+public:
+	Array<TransientMemoryToken, MAX_UNIFORM_BUFFER_BINDINGS> m_uniformBuffers;
+	Array<TransientMemoryToken, MAX_STORAGE_BUFFER_BINDINGS> m_storageBuffers;
+	Array<TransientMemoryToken, MAX_VERTEX_ATTRIBUTES> m_vertexBuffers;
+};
+
 /// Compute max number of mipmaps for a 2D texture.
 inline U computeMaxMipmapCount(U w, U h)
 {

+ 4 - 3
include/anki/gr/GrManager.h

@@ -40,7 +40,6 @@ public:
 	/// Major OpenGL version. Used to create core profile context
 	U32 m_majorVersion = 0;
 	Bool8 m_useGles = false; ///< Use OpenGL ES
-	Bool8 m_debugContext = false; ///< Enables KHR_debug
 	/// @}
 };
 
@@ -78,8 +77,10 @@ public:
 
 	/// Allocate memory for dynamic buffers. The memory will be reclaimed at
 	/// the begining of the N-(MAX_FRAMES_IN_FLIGHT-1) frame.
-	void* allocateFrameHostVisibleMemory(
-		PtrSize size, BufferUsage usage, DynamicBufferToken& token);
+	void* allocateFrameTransientMemory(PtrSize size,
+		BufferUsage usage,
+		TransientMemoryToken& token,
+		Error* err = nullptr);
 
 anki_internal:
 	GrAllocator<U8>& getAllocator()

+ 1 - 10
include/anki/gr/ResourceGroup.h

@@ -31,7 +31,7 @@ public:
 	BufferPtr m_buffer;
 	PtrSize m_offset = 0;
 	PtrSize m_range = 0;
-	Bool m_dynamic = false;
+	Bool m_uploadedMemory = false;
 };
 
 /// Resource group initializer.
@@ -47,15 +47,6 @@ public:
 	I8 m_indexSize = -1; ///< Index size in bytes. 2 or 4
 };
 
-/// Struct to help update the offset of the dynamic buffers.
-class DynamicBufferInfo
-{
-public:
-	Array<DynamicBufferToken, MAX_UNIFORM_BUFFER_BINDINGS> m_uniformBuffers;
-	Array<DynamicBufferToken, MAX_STORAGE_BUFFER_BINDINGS> m_storageBuffers;
-	Array<DynamicBufferToken, MAX_VERTEX_ATTRIBUTES> m_vertexBuffers;
-};
-
 /// Resource group.
 class ResourceGroup : public GrObject
 {

+ 3 - 5
include/anki/gr/common/GpuBlockAllocator.h

@@ -32,13 +32,11 @@ public:
 		PtrSize blockSize);
 
 	/// Allocate GPU memory.
-	ANKI_USE_RESULT Error allocate(PtrSize size,
-		U alignment,
-		DynamicBufferToken& handle,
-		Bool handleOomError = true);
+	ANKI_USE_RESULT Error allocate(
+		PtrSize size, U alignment, PtrSize& outOffset);
 
 	/// Free GPU memory.
-	void free(const DynamicBufferToken& handle);
+	void free(PtrSize offset);
 
 private:
 	class Block;

+ 1 - 2
include/anki/gr/common/GpuFrameRingAllocator.h

@@ -36,8 +36,7 @@ public:
 		PtrSize size, U32 alignment, PtrSize maxAllocationSize = MAX_PTR_SIZE);
 
 	/// Allocate memory for a dynamic buffer.
-	ANKI_USE_RESULT Error allocate(
-		PtrSize size, DynamicBufferToken& token, Bool handleOomErrors = true);
+	ANKI_USE_RESULT Error allocate(PtrSize size, PtrSize& outOffset);
 
 	/// Call this at the end of the frame.
 	/// @return The bytes that were not used. Used for statistics.

+ 36 - 11
include/anki/gr/gl/CommandBufferImpl.h

@@ -5,8 +5,8 @@
 
 #pragma once
 
-#include <anki/gr/GrManager.h>
 #include <anki/gr/CommandBuffer.h>
+#include <anki/gr/gl/DynamicMemoryManager.h>
 #include <anki/util/Assert.h>
 #include <anki/util/Allocator.h>
 
@@ -64,10 +64,8 @@ public:
 		destroy();
 	}
 
-	/// Default constructor
-	/// @param server The command buffers server
-	/// @param hints Hints to optimize the command's allocator
-	void init(const InitHints& hints);
+	/// Initialize.
+	void init(const CommandBufferInitInfo& init);
 
 	/// Get the internal allocator.
 	CommandBufferAllocator<U8> getInternalAllocator() const
@@ -96,12 +94,6 @@ public:
 #endif
 	}
 
-	void checkDrawcall() const
-	{
-		ANKI_ASSERT(m_dbg.m_viewport == true);
-		ANKI_ASSERT(m_dbg.m_polygonOffset == true);
-	}
-
 	/// Make immutable
 	void makeImmutable()
 	{
@@ -118,6 +110,33 @@ public:
 		return m_firstCommand == nullptr;
 	}
 
+	void bindResourceGroup(
+		ResourceGroupPtr rc, U slot, const TransientMemoryInfo* info);
+
+	void drawElements(U32 count,
+		U32 instanceCount = 1,
+		U32 firstIndex = 0,
+		U32 baseVertex = 0,
+		U32 baseInstance = 0);
+
+	void drawArrays(
+		U32 count, U32 instanceCount = 1, U32 first = 0, U32 baseInstance = 0);
+
+	void drawElementsConditional(OcclusionQueryPtr query,
+		U32 count,
+		U32 instanceCount = 1,
+		U32 firstIndex = 0,
+		U32 baseVertex = 0,
+		U32 baseInstance = 0);
+
+	void drawArraysConditional(OcclusionQueryPtr query,
+		U32 count,
+		U32 instanceCount = 1,
+		U32 first = 0,
+		U32 baseInstance = 0);
+
+	void dispatchCompute(U32 groupCountX, U32 groupCountY, U32 groupCountZ);
+
 private:
 	GrManager* m_manager = nullptr;
 	GlCommand* m_firstCommand = nullptr;
@@ -130,6 +149,12 @@ private:
 #endif
 
 	void destroy();
+
+	void checkDrawcall() const
+	{
+		ANKI_ASSERT(m_dbg.m_viewport == true);
+		ANKI_ASSERT(m_dbg.m_polygonOffset == true);
+	}
 };
 
 //==============================================================================

+ 49 - 9
include/anki/gr/gl/DynamicMemoryManager.h

@@ -7,6 +7,7 @@
 
 #include <anki/gr/gl/Common.h>
 #include <anki/gr/common/GpuFrameRingAllocator.h>
+#include <anki/gr/common/GpuBlockAllocator.h>
 
 namespace anki
 {
@@ -36,19 +37,46 @@ public:
 
 	void endFrame();
 
-	ANKI_USE_RESULT void* allocatePerFrame(
-		BufferUsage usage, PtrSize size, DynamicBufferToken& handle);
+	void allocate(PtrSize size,
+		BufferUsage usage,
+		TransientMemoryTokenLifetime lifespan,
+		TransientMemoryToken& token,
+		void*& ptr,
+		Error* outErr);
 
-	void* getBaseAddress(BufferUsage usage) const
+	void free(const TransientMemoryToken& token)
 	{
-		void* addr = m_buffers[usage].m_mappedMem;
+		ANKI_ASSERT(
+			token.m_lifetime == TransientMemoryTokenLifetime::PERSISTENT);
+		m_persistentBuffers[token.m_usage].m_alloc.free(token.m_offset);
+	}
+
+	void* getBaseAddress(const TransientMemoryToken& token) const
+	{
+		void* addr;
+		if(token.m_lifetime == TransientMemoryTokenLifetime::PER_FRAME)
+		{
+			addr = m_perFrameBuffers[token.m_usage].m_mappedMem;
+		}
+		else
+		{
+			addr = m_persistentBuffers[token.m_usage].m_mappedMem;
+		}
 		ANKI_ASSERT(addr);
 		return addr;
 	}
 
-	GLuint getGlName(BufferUsage usage) const
+	GLuint getGlName(const TransientMemoryToken& token) const
 	{
-		GLuint name = m_buffers[usage].m_name;
+		GLuint name;
+		if(token.m_lifetime == TransientMemoryTokenLifetime::PER_FRAME)
+		{
+			name = m_perFrameBuffers[token.m_usage].m_name;
+		}
+		else
+		{
+			name = m_persistentBuffers[token.m_usage].m_name;
+		}
 		ANKI_ASSERT(name);
 		return name;
 	}
@@ -60,18 +88,30 @@ private:
 	};
 
 	// CPU or GPU buffer.
-	class DynamicBuffer
+	class PerFrameBuffer
+	{
+	public:
+		PtrSize m_size = 0;
+		GLuint m_name = 0;
+		DynamicArray<Aligned16Type> m_cpuBuff;
+		U8* m_mappedMem = nullptr;
+		GpuFrameRingAllocator m_alloc;
+	};
+
+	class PersistentBuffer
 	{
 	public:
 		PtrSize m_size = 0;
 		GLuint m_name = 0;
+		U32 m_alignment = 0;
 		DynamicArray<Aligned16Type> m_cpuBuff;
 		U8* m_mappedMem = nullptr;
-		GpuFrameRingAllocator m_frameAlloc;
+		GpuBlockAllocator m_alloc;
 	};
 
 	GenericMemoryPoolAllocator<U8> m_alloc;
-	Array<DynamicBuffer, U(BufferUsage::COUNT)> m_buffers;
+	Array<PerFrameBuffer, U(BufferUsage::COUNT)> m_perFrameBuffers;
+	Array<PersistentBuffer, U(BufferUsage::COUNT)> m_persistentBuffers;
 };
 /// @}
 

+ 1 - 12
include/anki/gr/gl/GlState.h

@@ -31,6 +31,7 @@ enum class GpuVendor : U8
 class GlState
 {
 public:
+	GrManager* m_manager;
 	I32 m_version = -1; ///< Minor major GL version. Something like 430
 	GpuVendor m_gpu = GpuVendor::UNKNOWN;
 	Bool8 m_registerMessages = false;
@@ -78,8 +79,6 @@ public:
 	Bool m_depthWriteMask = true;
 	/// @}
 
-	DynamicMemoryManager m_dynamicMemoryManager;
-
 	GlState(GrManager* manager)
 		: m_manager(manager)
 	{
@@ -94,17 +93,7 @@ public:
 	/// Call this from the rendering thread.
 	void destroy();
 
-	/// Allocate memory for a dynamic buffer.
-	void* allocateDynamicMemory(
-		PtrSize size, BufferUsage usage, DynamicBufferToken& token)
-	{
-		return m_dynamicMemoryManager.allocatePerFrame(usage, size, token);
-	}
-
 	void flushVertexState();
-
-private:
-	GrManager* m_manager;
 };
 /// @}
 

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

@@ -13,6 +13,8 @@ namespace anki
 // Forward
 class RenderingThread;
 class WindowingBackend;
+class GlState;
+class DynamicMemoryManager;
 
 /// @addtogroup opengl
 /// @{
@@ -33,14 +35,40 @@ public:
 
 	const RenderingThread& getRenderingThread() const
 	{
+		ANKI_ASSERT(m_thread);
 		return *m_thread;
 	}
 
 	RenderingThread& getRenderingThread()
 	{
+		ANKI_ASSERT(m_thread);
 		return *m_thread;
 	}
 
+	GlState& getState()
+	{
+		ANKI_ASSERT(m_state);
+		return *m_state;
+	}
+
+	const GlState& getState() const
+	{
+		ANKI_ASSERT(m_state);
+		return *m_state;
+	}
+
+	DynamicMemoryManager& getDynamicMemoryManager()
+	{
+		ANKI_ASSERT(m_dynManager);
+		return *m_dynManager;
+	}
+
+	const DynamicMemoryManager& getDynamicMemoryManager() const
+	{
+		ANKI_ASSERT(m_dynManager);
+		return *m_dynManager;
+	}
+
 	GrAllocator<U8> getAllocator() const;
 
 	void swapBuffers();
@@ -49,8 +77,10 @@ public:
 
 private:
 	GrManager* m_manager;
+	GlState* m_state = nullptr;
 	RenderingThread* m_thread = nullptr;
 	WindowingBackend* m_backend = nullptr; ///< The backend of the backend.
+	DynamicMemoryManager* m_dynManager = nullptr;
 
 	ANKI_USE_RESULT Error createBackend(GrManagerInitInfo& init);
 	void destroyBackend();

+ 5 - 15
include/anki/gr/gl/RenderingThread.h

@@ -6,7 +6,6 @@
 #pragma once
 
 #include <anki/gr/CommandBuffer.h>
-#include <anki/gr/gl/GlState.h>
 #include <anki/util/Thread.h>
 
 namespace anki
@@ -27,19 +26,9 @@ public:
 
 	~RenderingThread();
 
-	GlState& getState()
-	{
-		return m_state;
-	}
-
-	const GlState& getState() const
-	{
-		return m_state;
-	}
-
 	/// Start the working thread
 	/// @note Don't free the context before calling #stop
-	void start(Bool registerMessages, const ConfigSet& config);
+	void start();
 
 	/// Stop the working thread
 	void stop();
@@ -74,15 +63,16 @@ private:
 	ConditionVariable m_condVar; ///< To wake up the thread
 	Thread m_thread;
 
+	/// @name Swap_buffers_vars
+	/// @{
 	CommandBufferPtr m_swapBuffersCommands;
 	ConditionVariable m_frameCondVar;
 	Mutex m_frameMtx;
 	Bool8 m_frameWait = false;
+	/// @}
 
 	Thread::Id m_serverThreadId;
 
-	GlState m_state;
-
 	/// A special command buffer that is called every time we want to wait for
 	/// the server
 	CommandBufferPtr m_syncCommands;
@@ -98,7 +88,7 @@ private:
 	void prepare();
 	void finish();
 
-	void swapBuffersInternal(GlState& state);
+	void swapBuffersInternal();
 };
 /// @}
 

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

@@ -32,13 +32,13 @@ public:
 	void init(const ResourceGroupInitInfo& init);
 
 	/// Set state.
-	void bind(U slot, const DynamicBufferInfo& dynInfo, GlState& state);
+	void bind(U slot, const TransientMemoryInfo& transientInfo, GlState& state);
 
 private:
 	class InternalBufferBinding
 	{
 	public:
-		GLuint m_name = 0; ///< If it's MAX_U32 then it's dynamic
+		GLuint m_name = 0; ///< If it's MAX_U32 then it's transient
 		U32 m_offset = 0;
 		U32 m_range = 0;
 	};
@@ -59,7 +59,7 @@ private:
 
 	Array<GLuint, MAX_VERTEX_ATTRIBUTES> m_vertBuffNames;
 	Array<GLintptr, MAX_VERTEX_ATTRIBUTES> m_vertBuffOffsets;
-	Bool8 m_hasDynamicVertexBuff = false;
+	Bool8 m_hasTransientVertexBuff = false;
 	U8 m_vertBindingsCount = 0;
 
 	GLuint m_indexBuffName = 0;
@@ -74,7 +74,7 @@ private:
 		OutBindings& out,
 		U8& count,
 		U& resourcesCount,
-		U& dynCount);
+		U& transCount);
 
 	void initResourceReferences(const ResourceGroupInitInfo& init, U count);
 };

+ 3 - 3
include/anki/renderer/Renderer.h

@@ -51,7 +51,7 @@ public:
 	class Is
 	{
 	public:
-		DynamicBufferInfo m_dynBufferInfo;
+		TransientMemoryInfo m_dynBufferInfo;
 	} m_is;
 	/// @}
 
@@ -370,7 +370,7 @@ anki_internal:
 		return *m_threadpool;
 	}
 
-	const DynamicBufferToken& getCommonUniformsDynamicBufferToken() const
+	const TransientMemoryToken& getCommonUniformsTransientMemoryToken() const
 	{
 		return m_commonUniformsToken;
 	}
@@ -402,7 +402,7 @@ private:
 
 	Clusterer m_clusterer;
 
-	DynamicBufferToken m_commonUniformsToken;
+	TransientMemoryToken m_commonUniformsToken;
 
 	/// @name Rendering stages
 	/// @{

+ 1 - 1
include/anki/scene/RenderComponent.h

@@ -114,7 +114,7 @@ public:
 	const U8* m_subMeshIndicesArray; ///< @note indices != drawing indices
 	U32 m_subMeshIndicesCount;
 	CommandBufferPtr m_cmdb; ///< A command buffer to append to.
-	DynamicBufferInfo* m_dynamicBufferInfo ANKI_DBG_NULLIFY_PTR;
+	TransientMemoryInfo* m_dynamicBufferInfo ANKI_DBG_NULLIFY_PTR;
 };
 
 /// RenderComponent interface. Implemented by renderable scene nodes

+ 1 - 0
sandbox/config.xml

@@ -45,6 +45,7 @@
 	<gr.storagePerFrameMemorySize>16777216</gr.storagePerFrameMemorySize>
 	<gr.transferPerFrameMemorySize>67108864</gr.transferPerFrameMemorySize>
 	<gr.vertexPerFrameMemorySize>16777216</gr.vertexPerFrameMemorySize>
+	<gr.transferPersistentMemorySize>67108864</gr.transferPersistentMemorySize>
 	<maxTextureSize>1048576</maxTextureSize>
 	<textureAnisotropy>8</textureAnisotropy>
 	<dataPaths>assets:.</dataPaths>

+ 0 - 1
src/core/App.cpp

@@ -227,7 +227,6 @@ Error App::initInternal(const ConfigSet& config_,
 	grInit.m_config = &config;
 	grInit.m_majorVersion = config.getNumber("glmajor");
 	grInit.m_minorVersion = config.getNumber("glminor");
-	grInit.m_debugContext = config.getNumber("debugContext");
 	grInit.m_window = m_window;
 
 	ANKI_CHECK(m_gr->init(grInit));

+ 2 - 1
src/core/Config.cpp

@@ -73,8 +73,9 @@ Config::Config()
 	newOption("gr.uniformPerFrameMemorySize", 1024 * 1024 * 16);
 	newOption("gr.storagePerFrameMemorySize", 1024 * 1024 * 16);
 	newOption("gr.vertexPerFrameMemorySize", 1024 * 1024 * 10);
+	newOption("gr.transferPerFrameMemorySize", 1024 * 1024 * 1);
 	newOption(
-		"gr.transferPerFrameMemorySize", (4096 / 4) * (4096 / 4) * 16 * 4);
+		"gr.transferPersistentMemorySize", (4096 / 4) * (4096 / 4) * 16 * 4);
 
 	//
 	// Resource

+ 6 - 12
src/gr/common/GpuBlockAllocator.cpp

@@ -75,8 +75,7 @@ Bool GpuBlockAllocator::blockHasEnoughSpace(
 }
 
 //==============================================================================
-Error GpuBlockAllocator::allocate(
-	PtrSize size, U alignment, DynamicBufferToken& handle, Bool handleOomError)
+Error GpuBlockAllocator::allocate(PtrSize size, U alignment, PtrSize& outOffset)
 {
 	ANKI_ASSERT(isCreated());
 	ANKI_ASSERT(size < m_blockSize);
@@ -114,29 +113,24 @@ Error GpuBlockAllocator::allocate(
 		++block->m_allocationCount;
 
 		// Update the handle
-		handle.m_offset = outOffset;
-		handle.m_range = size;
-	}
-	else if(handleOomError)
-	{
-		ANKI_LOGF("Out of memory");
+		outOffset = outOffset;
 	}
 	else
 	{
 		err = ErrorCode::OUT_OF_MEMORY;
+		outOffset = MAX_PTR_SIZE;
 	}
 
 	return err;
 }
 
 //==============================================================================
-void GpuBlockAllocator::free(const DynamicBufferToken& handle)
+void GpuBlockAllocator::free(PtrSize offset)
 {
 	ANKI_ASSERT(isCreated());
-	ANKI_ASSERT(handle.m_range > 0);
-	ANKI_ASSERT(handle.m_offset < m_size);
+	ANKI_ASSERT(offset < m_size);
 
-	U blockIdx = handle.m_offset / m_blockSize;
+	U blockIdx = offset / m_blockSize;
 
 	LockGuard<Mutex> lock(m_mtx);
 

+ 4 - 9
src/gr/common/GpuFrameRingAllocator.cpp

@@ -48,8 +48,7 @@ PtrSize GpuFrameRingAllocator::endFrame()
 }
 
 //==============================================================================
-Error GpuFrameRingAllocator::allocate(
-	PtrSize originalSize, DynamicBufferToken& token, Bool handleOomError)
+Error GpuFrameRingAllocator::allocate(PtrSize originalSize, PtrSize& outOffset)
 {
 	ANKI_ASSERT(isCreated());
 	ANKI_ASSERT(originalSize > 0);
@@ -74,17 +73,13 @@ Error GpuFrameRingAllocator::allocate(
 #endif
 
 		// Encode token
-		token.m_offset = offset;
-		token.m_range = originalSize;
+		outOffset = offset;
 
-		ANKI_ASSERT(token.m_offset + token.m_range <= m_size);
-	}
-	else if(handleOomError)
-	{
-		ANKI_LOGF("Out of GPU dynamic memory");
+		ANKI_ASSERT(outOffset + originalSize <= m_size);
 	}
 	else
 	{
+		outOffset = MAX_PTR_SIZE;
 		err = ErrorCode::OUT_OF_MEMORY;
 	}
 

+ 2 - 1
src/gr/gl/Buffer.cpp

@@ -4,6 +4,7 @@
 // http://www.anki3d.org/LICENSE
 
 #include <anki/gr/Buffer.h>
+#include <anki/gr/GrManager.h>
 #include <anki/gr/gl/BufferImpl.h>
 #include <anki/gr/gl/CommandBufferImpl.h>
 
@@ -72,7 +73,7 @@ void Buffer::init(PtrSize size, BufferUsageBit usage, BufferAccessBit access)
 //==============================================================================
 void* Buffer::map(PtrSize offset, PtrSize range, BufferAccessBit access)
 {
-	// Wait for it's creation
+	// Wait for its creation
 	if(m_impl->serializeRenderingThread())
 	{
 		return nullptr;

+ 50 - 171
src/gr/gl/CommandBuffer.cpp

@@ -8,18 +8,21 @@
 #include <anki/gr/GrManager.h>
 #include <anki/gr/gl/GrManagerImpl.h>
 #include <anki/gr/gl/RenderingThread.h>
+#include <anki/gr/gl/GlState.h>
+
 #include <anki/gr/Pipeline.h>
 #include <anki/gr/gl/PipelineImpl.h>
-#include <anki/gr/Framebuffer.h>
-#include <anki/gr/gl/FramebufferImpl.h>
 #include <anki/gr/ResourceGroup.h>
 #include <anki/gr/gl/ResourceGroupImpl.h>
+#include <anki/gr/Framebuffer.h>
+#include <anki/gr/gl/FramebufferImpl.h>
 #include <anki/gr/OcclusionQuery.h>
 #include <anki/gr/gl/OcclusionQueryImpl.h>
 #include <anki/gr/Texture.h>
 #include <anki/gr/gl/TextureImpl.h>
 #include <anki/gr/Buffer.h>
 #include <anki/gr/gl/BufferImpl.h>
+
 #include <anki/core/Trace.h>
 
 namespace anki
@@ -40,7 +43,7 @@ CommandBuffer::~CommandBuffer()
 void CommandBuffer::init(CommandBufferInitInfo& inf)
 {
 	m_impl.reset(getAllocator().newInstance<CommandBufferImpl>(&getManager()));
-	m_impl->init(inf.m_hints);
+	m_impl->init(inf);
 
 #if ANKI_ASSERTS_ENABLED
 	if(inf.m_secondLevel)
@@ -61,6 +64,7 @@ void CommandBuffer::flush()
 		ANKI_ASSERT(!m_impl->m_dbg.m_insideRenderPass);
 	}
 #endif
+
 	getManager().getImplementation().getRenderingThread().flushCommandBuffer(
 		CommandBufferPtr(this));
 }
@@ -226,146 +230,28 @@ void CommandBuffer::endRenderPass()
 }
 
 //==============================================================================
-class BindResourcesCommand final : public GlCommand
-{
-public:
-	ResourceGroupPtr m_rc;
-	U8 m_slot;
-	DynamicBufferInfo m_dynInfo;
-
-	BindResourcesCommand(
-		ResourceGroupPtr rc, U8 slot, const DynamicBufferInfo* dynInfo)
-		: m_rc(rc)
-		, m_slot(slot)
-	{
-		if(dynInfo)
-		{
-			m_dynInfo = *dynInfo;
-		}
-	}
-
-	Error operator()(GlState& state)
-	{
-		ANKI_TRACE_START_EVENT(GL_BIND_RESOURCES);
-		m_rc->getImplementation().bind(m_slot, m_dynInfo, state);
-		ANKI_TRACE_STOP_EVENT(GL_BIND_RESOURCES);
-		return ErrorCode::NONE;
-	}
-};
-
 void CommandBuffer::bindResourceGroup(
-	ResourceGroupPtr rc, U slot, const DynamicBufferInfo* dynInfo)
+	ResourceGroupPtr rc, U slot, const TransientMemoryInfo* info)
 {
-	ANKI_ASSERT(rc.isCreated());
-	m_impl->pushBackNewCommand<BindResourcesCommand>(rc, slot, dynInfo);
+	m_impl->bindResourceGroup(rc, slot, info);
 }
 
 //==============================================================================
-class DrawElementsCondCommand : public GlCommand
-{
-public:
-	DrawElementsIndirectInfo m_info;
-	OcclusionQueryPtr m_query;
-
-	DrawElementsCondCommand(const DrawElementsIndirectInfo& info,
-		OcclusionQueryPtr query = OcclusionQueryPtr())
-		: m_info(info)
-		, m_query(query)
-	{
-	}
-
-	Error operator()(GlState& state)
-	{
-		GLenum indicesType = 0;
-		switch(state.m_indexSize)
-		{
-		case 2:
-			indicesType = GL_UNSIGNED_SHORT;
-			break;
-		case 4:
-			indicesType = GL_UNSIGNED_INT;
-			break;
-		default:
-			ANKI_ASSERT(0);
-			break;
-		};
-
-		if(!m_query.isCreated() || !m_query->getImplementation().skipDrawcall())
-		{
-			state.flushVertexState();
-
-			glDrawElementsInstancedBaseVertexBaseInstance(state.m_topology,
-				m_info.m_count,
-				indicesType,
-				(const void*)(PtrSize)(m_info.m_firstIndex * state.m_indexSize),
-				m_info.m_instanceCount,
-				m_info.m_baseVertex,
-				m_info.m_baseInstance);
-
-			ANKI_TRACE_INC_COUNTER(GR_DRAWCALLS, 1);
-			ANKI_TRACE_INC_COUNTER(
-				GR_VERTICES, m_info.m_instanceCount * m_info.m_count);
-		}
-
-		return ErrorCode::NONE;
-	}
-};
-
 void CommandBuffer::drawElements(U32 count,
 	U32 instanceCount,
 	U32 firstIndex,
 	U32 baseVertex,
 	U32 baseInstance)
 {
-	ANKI_ASSERT(m_impl->m_dbg.m_insideRenderPass);
-	DrawElementsIndirectInfo info(
+	m_impl->drawElements(
 		count, instanceCount, firstIndex, baseVertex, baseInstance);
-
-	m_impl->checkDrawcall();
-	m_impl->pushBackNewCommand<DrawElementsCondCommand>(info);
 }
 
 //==============================================================================
-class DrawArraysCondCommand final : public GlCommand
-{
-public:
-	DrawArraysIndirectInfo m_info;
-	OcclusionQueryPtr m_query;
-
-	DrawArraysCondCommand(const DrawArraysIndirectInfo& info,
-		OcclusionQueryPtr query = OcclusionQueryPtr())
-		: m_info(info)
-		, m_query(query)
-	{
-	}
-
-	Error operator()(GlState& state)
-	{
-		if(!m_query.isCreated() || !m_query->getImplementation().skipDrawcall())
-		{
-			state.flushVertexState();
-
-			glDrawArraysInstancedBaseInstance(state.m_topology,
-				m_info.m_first,
-				m_info.m_count,
-				m_info.m_instanceCount,
-				m_info.m_baseInstance);
-
-			ANKI_TRACE_INC_COUNTER(GR_DRAWCALLS, 1);
-		}
-
-		return ErrorCode::NONE;
-	}
-};
-
 void CommandBuffer::drawArrays(
 	U32 count, U32 instanceCount, U32 first, U32 baseInstance)
 {
-	ANKI_ASSERT(m_impl->m_dbg.m_insideRenderPass);
-	DrawArraysIndirectInfo info(count, instanceCount, first, baseInstance);
-
-	m_impl->checkDrawcall();
-	m_impl->pushBackNewCommand<DrawArraysCondCommand>(info);
+	m_impl->drawArrays(count, instanceCount, first, baseInstance);
 }
 
 //==============================================================================
@@ -376,12 +262,8 @@ void CommandBuffer::drawElementsConditional(OcclusionQueryPtr query,
 	U32 baseVertex,
 	U32 baseInstance)
 {
-	ANKI_ASSERT(m_impl->m_dbg.m_insideRenderPass);
-	DrawElementsIndirectInfo info(
-		count, instanceCount, firstIndex, baseVertex, baseInstance);
-
-	m_impl->checkDrawcall();
-	m_impl->pushBackNewCommand<DrawElementsCondCommand>(info, query);
+	m_impl->drawElementsConditional(
+		query, count, instanceCount, firstIndex, baseVertex, baseInstance);
 }
 
 //==============================================================================
@@ -391,37 +273,15 @@ void CommandBuffer::drawArraysConditional(OcclusionQueryPtr query,
 	U32 first,
 	U32 baseInstance)
 {
-	ANKI_ASSERT(m_impl->m_dbg.m_insideRenderPass);
-	DrawArraysIndirectInfo info(count, instanceCount, first, baseInstance);
-
-	m_impl->checkDrawcall();
-	m_impl->pushBackNewCommand<DrawArraysCondCommand>(info, query);
+	m_impl->drawArraysConditional(
+		query, count, instanceCount, first, baseInstance);
 }
 
 //==============================================================================
-class DispatchCommand final : public GlCommand
-{
-public:
-	Array<U32, 3> m_size;
-
-	DispatchCommand(U32 x, U32 y, U32 z)
-		: m_size({{x, y, z}})
-	{
-	}
-
-	Error operator()(GlState&)
-	{
-		glDispatchCompute(m_size[0], m_size[1], m_size[2]);
-		return ErrorCode::NONE;
-	}
-};
-
 void CommandBuffer::dispatchCompute(
 	U32 groupCountX, U32 groupCountY, U32 groupCountZ)
 {
-	ANKI_ASSERT(!m_impl->m_dbg.m_insideRenderPass);
-	m_impl->pushBackNewCommand<DispatchCommand>(
-		groupCountX, groupCountY, groupCountZ);
+	m_impl->dispatchCompute(groupCountX, groupCountY, groupCountZ);
 }
 
 //==============================================================================
@@ -476,11 +336,11 @@ class TexUploadCommand final : public GlCommand
 public:
 	TexturePtr m_handle;
 	TextureSurfaceInfo m_surf;
-	DynamicBufferToken m_token;
+	TransientMemoryToken m_token;
 
 	TexUploadCommand(const TexturePtr& handle,
 		TextureSurfaceInfo surf,
-		const DynamicBufferToken& token)
+		const TransientMemoryToken& token)
 		: m_handle(handle)
 		, m_surf(surf)
 		, m_token(token)
@@ -489,21 +349,30 @@ public:
 
 	Error operator()(GlState& state)
 	{
-		U8* data = static_cast<U8*>(state.m_dynamicMemoryManager.getBaseAddress(
-					   BufferUsage::TRANSFER))
-			+ m_token.m_offset;
+		void* data = state.m_manager->getImplementation()
+						 .getDynamicMemoryManager()
+						 .getBaseAddress(m_token);
+		data = static_cast<void*>(static_cast<U8*>(data) + m_token.m_offset);
 
 		m_handle->getImplementation().write(m_surf, data, m_token.m_range);
+
+		if(m_token.m_lifetime == TransientMemoryTokenLifetime::PERSISTENT)
+		{
+			state.m_manager->getImplementation().getDynamicMemoryManager().free(
+				m_token);
+		}
+
 		return ErrorCode::NONE;
 	}
 };
 
-void CommandBuffer::textureUpload(TexturePtr tex,
+void CommandBuffer::uploadTextureSurface(TexturePtr tex,
 	const TextureSurfaceInfo& surf,
-	const DynamicBufferToken& token)
+	const TransientMemoryToken& token)
 {
-	ANKI_ASSERT(!m_impl->m_dbg.m_insideRenderPass);
+	ANKI_ASSERT(tex);
 	ANKI_ASSERT(token.m_range > 0);
+	ANKI_ASSERT(!m_impl->m_dbg.m_insideRenderPass);
 
 	m_impl->pushBackNewCommand<TexUploadCommand>(tex, surf, token);
 }
@@ -514,11 +383,11 @@ class BuffWriteCommand final : public GlCommand
 public:
 	BufferPtr m_handle;
 	PtrSize m_offset;
-	DynamicBufferToken m_token;
+	TransientMemoryToken m_token;
 
 	BuffWriteCommand(const BufferPtr& handle,
 		PtrSize offset,
-		const DynamicBufferToken& token)
+		const TransientMemoryToken& token)
 		: m_handle(handle)
 		, m_offset(offset)
 		, m_token(token)
@@ -527,20 +396,30 @@ public:
 
 	Error operator()(GlState& state)
 	{
-		U8* data = static_cast<U8*>(state.m_dynamicMemoryManager.getBaseAddress(
-					   BufferUsage::TRANSFER))
-			+ m_token.m_offset;
+		void* data = state.m_manager->getImplementation()
+						 .getDynamicMemoryManager()
+						 .getBaseAddress(m_token);
+		data = static_cast<void*>(static_cast<U8*>(data) + m_token.m_offset);
 
 		m_handle->getImplementation().write(data, m_offset, m_token.m_range);
 
+		if(m_token.m_lifetime == TransientMemoryTokenLifetime::PERSISTENT)
+		{
+			state.m_manager->getImplementation().getDynamicMemoryManager().free(
+				m_token);
+		}
+
 		return ErrorCode::NONE;
 	}
 };
 
-void CommandBuffer::writeBuffer(
-	BufferPtr buff, PtrSize offset, const DynamicBufferToken& token)
+void CommandBuffer::uploadBuffer(
+	BufferPtr buff, PtrSize offset, const TransientMemoryToken& token)
 {
+	ANKI_ASSERT(token.m_range > 0);
+	ANKI_ASSERT(buff);
 	ANKI_ASSERT(!m_impl->m_dbg.m_insideRenderPass);
+
 	m_impl->pushBackNewCommand<BuffWriteCommand>(buff, offset, token);
 }
 

+ 208 - 5
src/gr/gl/CommandBufferImpl.cpp

@@ -6,8 +6,13 @@
 #include <anki/gr/gl/CommandBufferImpl.h>
 #include <anki/gr/GrManager.h>
 #include <anki/gr/gl/GrManagerImpl.h>
-#include <anki/gr/gl/RenderingThread.h>
+#include <anki/gr/gl/GlState.h>
 #include <anki/gr/gl/Error.h>
+
+#include <anki/gr/gl/ResourceGroupImpl.h>
+#include <anki/gr/OcclusionQuery.h>
+#include <anki/gr/gl/OcclusionQueryImpl.h>
+
 #include <anki/util/Logger.h>
 #include <anki/core/Trace.h>
 #include <cstring>
@@ -16,13 +21,13 @@ namespace anki
 {
 
 //==============================================================================
-void CommandBufferImpl::init(const InitHints& hints)
+void CommandBufferImpl::init(const CommandBufferInitInfo& init)
 {
 	auto& pool = m_manager->getAllocator().getMemoryPool();
 
 	m_alloc = CommandBufferAllocator<GlCommand*>(pool.getAllocationCallback(),
 		pool.getAllocationCallbackUserData(),
-		hints.m_chunkSize,
+		init.m_hints.m_chunkSize,
 		1.0,
 		0,
 		false);
@@ -67,8 +72,7 @@ Error CommandBufferImpl::executeAllCommands()
 #endif
 
 	Error err = ErrorCode::NONE;
-	GlState& state =
-		m_manager->getImplementation().getRenderingThread().getState();
+	GlState& state = m_manager->getImplementation().getState();
 
 	GlCommand* command = m_firstCommand;
 
@@ -98,4 +102,203 @@ GrAllocator<U8> CommandBufferImpl::getAllocator() const
 	return m_manager->getAllocator();
 }
 
+//==============================================================================
+class BindResourcesCommand final : public GlCommand
+{
+public:
+	ResourceGroupPtr m_rc;
+	TransientMemoryInfo m_info;
+	U8 m_slot;
+
+	BindResourcesCommand(
+		ResourceGroupPtr rc, U8 slot, const TransientMemoryInfo* info)
+		: m_rc(rc)
+		, m_slot(slot)
+	{
+		if(info)
+		{
+			m_info = *info;
+		}
+	}
+
+	Error operator()(GlState& state)
+	{
+		ANKI_TRACE_START_EVENT(GL_BIND_RESOURCES);
+		m_rc->getImplementation().bind(m_slot, m_info, state);
+		ANKI_TRACE_STOP_EVENT(GL_BIND_RESOURCES);
+		return ErrorCode::NONE;
+	}
+};
+
+void CommandBufferImpl::bindResourceGroup(
+	ResourceGroupPtr rc, U slot, const TransientMemoryInfo* info)
+{
+	ANKI_ASSERT(rc.isCreated());
+
+	pushBackNewCommand<BindResourcesCommand>(rc, slot, info);
+}
+
+//==============================================================================
+class DrawElementsCondCommand : public GlCommand
+{
+public:
+	DrawElementsIndirectInfo m_info;
+	OcclusionQueryPtr m_query;
+
+	DrawElementsCondCommand(const DrawElementsIndirectInfo& info,
+		OcclusionQueryPtr query = OcclusionQueryPtr())
+		: m_info(info)
+		, m_query(query)
+	{
+	}
+
+	Error operator()(GlState& state)
+	{
+		GLenum indicesType = 0;
+		switch(state.m_indexSize)
+		{
+		case 2:
+			indicesType = GL_UNSIGNED_SHORT;
+			break;
+		case 4:
+			indicesType = GL_UNSIGNED_INT;
+			break;
+		default:
+			ANKI_ASSERT(0);
+			break;
+		};
+
+		if(!m_query.isCreated() || !m_query->getImplementation().skipDrawcall())
+		{
+			state.flushVertexState();
+
+			glDrawElementsInstancedBaseVertexBaseInstance(state.m_topology,
+				m_info.m_count,
+				indicesType,
+				(const void*)(PtrSize)(m_info.m_firstIndex * state.m_indexSize),
+				m_info.m_instanceCount,
+				m_info.m_baseVertex,
+				m_info.m_baseInstance);
+
+			ANKI_TRACE_INC_COUNTER(GR_DRAWCALLS, 1);
+			ANKI_TRACE_INC_COUNTER(
+				GR_VERTICES, m_info.m_instanceCount * m_info.m_count);
+		}
+
+		return ErrorCode::NONE;
+	}
+};
+
+void CommandBufferImpl::drawElements(U32 count,
+	U32 instanceCount,
+	U32 firstIndex,
+	U32 baseVertex,
+	U32 baseInstance)
+{
+	ANKI_ASSERT(m_dbg.m_insideRenderPass);
+	DrawElementsIndirectInfo info(
+		count, instanceCount, firstIndex, baseVertex, baseInstance);
+
+	checkDrawcall();
+	pushBackNewCommand<DrawElementsCondCommand>(info);
+}
+
+//==============================================================================
+class DrawArraysCondCommand final : public GlCommand
+{
+public:
+	DrawArraysIndirectInfo m_info;
+	OcclusionQueryPtr m_query;
+
+	DrawArraysCondCommand(const DrawArraysIndirectInfo& info,
+		OcclusionQueryPtr query = OcclusionQueryPtr())
+		: m_info(info)
+		, m_query(query)
+	{
+	}
+
+	Error operator()(GlState& state)
+	{
+		if(!m_query.isCreated() || !m_query->getImplementation().skipDrawcall())
+		{
+			state.flushVertexState();
+
+			glDrawArraysInstancedBaseInstance(state.m_topology,
+				m_info.m_first,
+				m_info.m_count,
+				m_info.m_instanceCount,
+				m_info.m_baseInstance);
+
+			ANKI_TRACE_INC_COUNTER(GR_DRAWCALLS, 1);
+		}
+
+		return ErrorCode::NONE;
+	}
+};
+
+void CommandBufferImpl::drawArrays(
+	U32 count, U32 instanceCount, U32 first, U32 baseInstance)
+{
+	ANKI_ASSERT(m_dbg.m_insideRenderPass);
+	DrawArraysIndirectInfo info(count, instanceCount, first, baseInstance);
+
+	checkDrawcall();
+	pushBackNewCommand<DrawArraysCondCommand>(info);
+}
+
+//==============================================================================
+void CommandBufferImpl::drawElementsConditional(OcclusionQueryPtr query,
+	U32 count,
+	U32 instanceCount,
+	U32 firstIndex,
+	U32 baseVertex,
+	U32 baseInstance)
+{
+	ANKI_ASSERT(m_dbg.m_insideRenderPass);
+	DrawElementsIndirectInfo info(
+		count, instanceCount, firstIndex, baseVertex, baseInstance);
+
+	checkDrawcall();
+	pushBackNewCommand<DrawElementsCondCommand>(info, query);
+}
+
+//==============================================================================
+void CommandBufferImpl::drawArraysConditional(OcclusionQueryPtr query,
+	U32 count,
+	U32 instanceCount,
+	U32 first,
+	U32 baseInstance)
+{
+	ANKI_ASSERT(m_dbg.m_insideRenderPass);
+	DrawArraysIndirectInfo info(count, instanceCount, first, baseInstance);
+
+	checkDrawcall();
+	pushBackNewCommand<DrawArraysCondCommand>(info, query);
+}
+
+//==============================================================================
+class DispatchCommand final : public GlCommand
+{
+public:
+	Array<U32, 3> m_size;
+
+	DispatchCommand(U32 x, U32 y, U32 z)
+		: m_size({{x, y, z}})
+	{
+	}
+
+	Error operator()(GlState&)
+	{
+		glDispatchCompute(m_size[0], m_size[1], m_size[2]);
+		return ErrorCode::NONE;
+	}
+};
+
+void CommandBufferImpl::dispatchCompute(
+	U32 groupCountX, U32 groupCountY, U32 groupCountZ)
+{
+	ANKI_ASSERT(!m_dbg.m_insideRenderPass);
+	pushBackNewCommand<DispatchCommand>(groupCountX, groupCountY, groupCountZ);
+}
+
 } // end namespace anki

+ 84 - 26
src/gr/gl/DynamicMemoryManager.cpp

@@ -14,16 +14,34 @@ namespace anki
 //==============================================================================
 DynamicMemoryManager::~DynamicMemoryManager()
 {
-	for(DynamicBuffer& buff : m_buffers)
+	for(PerFrameBuffer& buff : m_perFrameBuffers)
 	{
 		ANKI_ASSERT(buff.m_name == 0);
+		(void)buff;
+	}
+
+	for(PersistentBuffer& buff : m_persistentBuffers)
+	{
+		ANKI_ASSERT(buff.m_name == 0);
+		(void)buff;
 	}
 }
 
 //==============================================================================
 void DynamicMemoryManager::destroyRenderThread()
 {
-	for(DynamicBuffer& buff : m_buffers)
+	for(PerFrameBuffer& buff : m_perFrameBuffers)
+	{
+		if(buff.m_name != 0)
+		{
+			glDeleteBuffers(1, &buff.m_name);
+			buff.m_name = 0;
+		}
+
+		buff.m_cpuBuff.destroy(m_alloc);
+	}
+
+	for(PersistentBuffer& buff : m_persistentBuffers)
 	{
 		if(buff.m_name != 0)
 		{
@@ -41,17 +59,20 @@ void DynamicMemoryManager::initMainThread(
 {
 	m_alloc = alloc;
 
-	m_buffers[BufferUsage::UNIFORM].m_size =
+	m_perFrameBuffers[BufferUsage::UNIFORM].m_size =
 		cfg.getNumber("gr.uniformPerFrameMemorySize");
 
-	m_buffers[BufferUsage::STORAGE].m_size =
+	m_perFrameBuffers[BufferUsage::STORAGE].m_size =
 		cfg.getNumber("gr.storagePerFrameMemorySize");
 
-	m_buffers[BufferUsage::VERTEX].m_size =
+	m_perFrameBuffers[BufferUsage::VERTEX].m_size =
 		cfg.getNumber("gr.vertexPerFrameMemorySize");
 
-	m_buffers[BufferUsage::TRANSFER].m_size =
+	m_perFrameBuffers[BufferUsage::TRANSFER].m_size =
 		cfg.getNumber("gr.transferPerFrameMemorySize");
+
+	m_persistentBuffers[BufferUsage::TRANSFER].m_size =
+		cfg.getNumber("gr.transferPersistentMemorySize");
 }
 
 //==============================================================================
@@ -62,7 +83,7 @@ void DynamicMemoryManager::initRenderThread()
 	// Uniform
 	{
 		// Create buffer
-		DynamicBuffer& buff = m_buffers[BufferUsage::UNIFORM];
+		PerFrameBuffer& buff = m_perFrameBuffers[BufferUsage::UNIFORM];
 		PtrSize size = buff.m_size;
 		glGenBuffers(1, &buff.m_name);
 		glBindBuffer(GL_UNIFORM_BUFFER, buff.m_name);
@@ -76,13 +97,13 @@ void DynamicMemoryManager::initRenderThread()
 		// Create the allocator
 		GLint64 blockAlignment;
 		glGetInteger64v(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &blockAlignment);
-		buff.m_frameAlloc.init(size, blockAlignment, MAX_UNIFORM_BLOCK_SIZE);
+		buff.m_alloc.init(size, blockAlignment, MAX_UNIFORM_BLOCK_SIZE);
 	}
 
 	// Storage
 	{
 		// Create buffer
-		DynamicBuffer& buff = m_buffers[BufferUsage::STORAGE];
+		PerFrameBuffer& buff = m_perFrameBuffers[BufferUsage::STORAGE];
 		PtrSize size = buff.m_size;
 		glGenBuffers(1, &buff.m_name);
 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, buff.m_name);
@@ -97,13 +118,13 @@ void DynamicMemoryManager::initRenderThread()
 		GLint64 blockAlignment;
 		glGetInteger64v(
 			GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, &blockAlignment);
-		buff.m_frameAlloc.init(size, blockAlignment, MAX_STORAGE_BLOCK_SIZE);
+		buff.m_alloc.init(size, blockAlignment, MAX_STORAGE_BLOCK_SIZE);
 	}
 
 	// Vertex
 	{
 		// Create buffer
-		DynamicBuffer& buff = m_buffers[BufferUsage::VERTEX];
+		PerFrameBuffer& buff = m_perFrameBuffers[BufferUsage::VERTEX];
 		PtrSize size = buff.m_size;
 		glGenBuffers(1, &buff.m_name);
 		glBindBuffer(GL_ARRAY_BUFFER, buff.m_name);
@@ -115,35 +136,72 @@ void DynamicMemoryManager::initRenderThread()
 		ANKI_ASSERT(buff.m_mappedMem);
 
 		// Create the allocator
-		buff.m_frameAlloc.init(size, 16, MAX_U32);
+		buff.m_alloc.init(size, 16, MAX_U32);
 	}
 
 	// Transfer
 	{
-		DynamicBuffer& buff = m_buffers[BufferUsage::TRANSFER];
+		PerFrameBuffer& buff = m_perFrameBuffers[BufferUsage::TRANSFER];
 		PtrSize size = buff.m_size;
 		buff.m_cpuBuff.create(m_alloc, size);
 
 		buff.m_mappedMem = reinterpret_cast<U8*>(&buff.m_cpuBuff[0]);
-		buff.m_frameAlloc.init(size, 16, MAX_U32);
+		buff.m_alloc.init(size, 16, MAX_U32);
+	}
+
+	{
+		const U BLOCK_SIZE = (4096 * 4096) / 4 * 16;
+
+		PersistentBuffer& buff = m_persistentBuffers[BufferUsage::TRANSFER];
+		PtrSize size = getAlignedRoundUp(BLOCK_SIZE, buff.m_size);
+		size = max(size, 2 * BLOCK_SIZE);
+		buff.m_cpuBuff.create(m_alloc, size);
+
+		buff.m_mappedMem = reinterpret_cast<U8*>(&buff.m_cpuBuff[0]);
+		buff.m_alloc.init(m_alloc, size, BLOCK_SIZE);
+		buff.m_alignment = 16;
 	}
 }
 
 //==============================================================================
-void* DynamicMemoryManager::allocatePerFrame(
-	BufferUsage usage, PtrSize size, DynamicBufferToken& handle)
+void DynamicMemoryManager::allocate(PtrSize size,
+	BufferUsage usage,
+	TransientMemoryTokenLifetime lifespan,
+	TransientMemoryToken& token,
+	void*& ptr,
+	Error* outErr)
 {
-	DynamicBuffer& buff = m_buffers[usage];
-	Error err = buff.m_frameAlloc.allocate(size, handle, false);
+	Error err = ErrorCode::NONE;
+	ptr = nullptr;
+	U8* mappedMemBase;
+
+	if(lifespan == TransientMemoryTokenLifetime::PER_FRAME)
+	{
+		PerFrameBuffer& buff = m_perFrameBuffers[usage];
+		err = buff.m_alloc.allocate(size, token.m_offset);
+		mappedMemBase = buff.m_mappedMem;
+	}
+	else
+	{
+		PersistentBuffer& buff = m_persistentBuffers[usage];
+		err = buff.m_alloc.allocate(size, buff.m_alignment, token.m_offset);
+		mappedMemBase = buff.m_mappedMem;
+	}
+
 	if(!err)
 	{
-		return buff.m_mappedMem + handle.m_offset;
+		token.m_usage = usage;
+		token.m_range = size;
+		token.m_lifetime = lifespan;
+		ptr = mappedMemBase + token.m_offset;
+	}
+	else if(outErr)
+	{
+		*outErr = err;
 	}
 	else
 	{
-		ANKI_LOGW(
-			"Out of per-frame GPU memory. Someone will have to handle this");
-		return nullptr;
+		ANKI_LOGF("Out of dynamic GPU memory");
 	}
 }
 
@@ -153,7 +211,7 @@ void DynamicMemoryManager::endFrame()
 	for(BufferUsage usage = BufferUsage::FIRST; usage < BufferUsage::COUNT;
 		++usage)
 	{
-		DynamicBuffer& buff = m_buffers[usage];
+		PerFrameBuffer& buff = m_perFrameBuffers[usage];
 
 		if(buff.m_mappedMem)
 		{
@@ -162,17 +220,17 @@ void DynamicMemoryManager::endFrame()
 			{
 			case BufferUsage::UNIFORM:
 				ANKI_TRACE_INC_COUNTER(GR_DYNAMIC_UNIFORMS_SIZE,
-					buff.m_frameAlloc.getUnallocatedMemorySize());
+					buff.m_alloc.getUnallocatedMemorySize());
 				break;
 			case BufferUsage::STORAGE:
 				ANKI_TRACE_INC_COUNTER(GR_DYNAMIC_STORAGE_SIZE,
-					buff.m_frameAlloc.getUnallocatedMemorySize());
+					buff.m_alloc.getUnallocatedMemorySize());
 				break;
 			default:
 				break;
 			}
 
-			buff.m_frameAlloc.endFrame();
+			buff.m_alloc.endFrame();
 		}
 	}
 }

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

@@ -6,6 +6,7 @@
 #include <anki/gr/Framebuffer.h>
 #include <anki/gr/gl/FramebufferImpl.h>
 #include <anki/gr/gl/CommandBufferImpl.h>
+#include <anki/gr/GrManager.h>
 
 namespace anki
 {

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

@@ -88,7 +88,7 @@ __stdcall
 //==============================================================================
 void GlState::initMainThread(const ConfigSet& config)
 {
-	m_dynamicMemoryManager.initMainThread(m_manager->getAllocator(), config);
+	m_registerMessages = config.getNumber("debugContext");
 }
 
 //==============================================================================
@@ -151,15 +151,11 @@ void GlState::initRenderThread()
 
 	// Other
 	memset(&m_vertexBindingStrides[0], 0, sizeof(m_vertexBindingStrides));
-
-	// Init dynamic memory
-	m_dynamicMemoryManager.initRenderThread();
 }
 
 //==============================================================================
 void GlState::destroy()
 {
-	m_dynamicMemoryManager.destroyRenderThread();
 	glDeleteVertexArrays(1, &m_defaultVao);
 }
 

+ 10 - 8
src/gr/gl/GrManager.cpp

@@ -6,6 +6,7 @@
 #include <anki/gr/GrManager.h>
 #include <anki/gr/gl/GrManagerImpl.h>
 #include <anki/gr/gl/RenderingThread.h>
+#include <anki/gr/gl/DynamicMemoryManager.h>
 #include <anki/core/Timestamp.h>
 #include <cstring>
 
@@ -48,19 +49,20 @@ void GrManager::swapBuffers()
 }
 
 //==============================================================================
-void* GrManager::allocateFrameHostVisibleMemory(
-	PtrSize size, BufferUsage usage, DynamicBufferToken& token)
+void GrManager::finish()
 {
-	// Will be used in a thread safe way
-	GlState& state = m_impl->getRenderingThread().getState();
-	void* ptr = state.allocateDynamicMemory(size, usage, token);
-	return ptr;
+	m_impl->getRenderingThread().syncClientServer();
 }
 
 //==============================================================================
-void GrManager::finish()
+void* GrManager::allocateFrameTransientMemory(
+	PtrSize size, BufferUsage usage, TransientMemoryToken& token, Error* err)
 {
-	m_impl->getRenderingThread().syncClientServer();
+	void* data = nullptr;
+	m_impl->getDynamicMemoryManager().allocate(
+		size, usage, TransientMemoryTokenLifetime::PER_FRAME, token, data, err);
+
+	return data;
 }
 
 } // end namespace anki

+ 16 - 1
src/gr/gl/GrManagerImpl.cpp

@@ -6,6 +6,7 @@
 #include <anki/gr/gl/GrManagerImpl.h>
 #include <anki/gr/GrManager.h>
 #include <anki/gr/gl/RenderingThread.h>
+#include <anki/gr/gl/GlState.h>
 
 namespace anki
 {
@@ -20,6 +21,11 @@ GrManagerImpl::~GrManagerImpl()
 		m_thread = nullptr;
 	}
 
+	if(m_state)
+	{
+		m_manager->getAllocator().deleteInstance(m_state);
+	}
+
 	destroyBackend();
 	m_manager = nullptr;
 }
@@ -36,12 +42,21 @@ Error GrManagerImpl::init(GrManagerInitInfo& init)
 	// Init the backend of the backend
 	ANKI_CHECK(createBackend(init));
 
+	// First create the state
+	m_state = m_manager->getAllocator().newInstance<GlState>(m_manager);
+	m_state->initMainThread(*init.m_config);
+
+	// Dyn manager
+	m_dynManager =
+		m_manager->getAllocator().newInstance<DynamicMemoryManager>();
+	m_dynManager->initMainThread(m_manager->getAllocator(), *init.m_config);
+
 	// Create thread
 	m_thread =
 		m_manager->getAllocator().newInstance<RenderingThread>(m_manager);
 
 	// Start it
-	m_thread->start(init.m_debugContext, *init.m_config);
+	m_thread->start();
 	m_thread->syncClientServer();
 
 	return ErrorCode::NONE;

+ 2 - 1
src/gr/gl/GrManagerImplSdl.cpp

@@ -9,6 +9,7 @@
 #include <anki/gr/GrManager.h>
 #include <anki/core/NativeWindow.h>
 #include <anki/core/NativeWindowSdl.h>
+#include <anki/core/Config.h>
 #include <SDL.h>
 #include <GL/glew.h>
 
@@ -42,7 +43,7 @@ public:
 			init.m_majorVersion,
 			init.m_minorVersion);
 
-		if(init.m_debugContext)
+		if(init.m_config->getNumber("debugContext"))
 		{
 			if(SDL_GL_SetAttribute(
 				   SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG))

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

@@ -6,6 +6,7 @@
 #include <anki/gr/OcclusionQuery.h>
 #include <anki/gr/gl/OcclusionQueryImpl.h>
 #include <anki/gr/gl/CommandBufferImpl.h>
+#include <anki/gr/GrManager.h>
 
 namespace anki
 {

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

@@ -5,6 +5,7 @@
 
 #include <anki/gr/Pipeline.h>
 #include <anki/gr/gl/PipelineImpl.h>
+#include <anki/gr/GrManager.h>
 #include <anki/gr/gl/CommandBufferImpl.h>
 #include <anki/core/Trace.h>
 

+ 1 - 4
src/gr/gl/PipelineImpl.cpp

@@ -5,10 +5,7 @@
 
 #include <anki/gr/gl/PipelineImpl.h>
 #include <anki/gr/gl/ShaderImpl.h>
-#include <anki/gr/GrManager.h>
-#include <anki/gr/gl/GrManagerImpl.h>
-#include <anki/gr/gl/RenderingThread.h>
-#include <anki/gr/gl/CommandBufferImpl.h>
+#include <anki/gr/gl/GlState.h>
 #include <anki/util/Logger.h>
 #include <anki/util/Hash.h>
 

+ 19 - 42
src/gr/gl/RenderingThread.cpp

@@ -7,6 +7,8 @@
 #include <anki/gr/gl/CommandBufferImpl.h>
 #include <anki/gr/GrManager.h>
 #include <anki/gr/gl/GrManagerImpl.h>
+#include <anki/gr/gl/GlState.h>
+#include <anki/gr/gl/DynamicMemoryManager.h>
 #include <anki/util/Logger.h>
 #include <anki/core/Trace.h>
 #include <cstdlib>
@@ -18,8 +20,6 @@ namespace anki
 // Misc                                                                        =
 //==============================================================================
 
-#define ANKI_DISABLE_GL_RENDERING_THREAD 0
-
 /// Sync rendering thread command.
 class SyncCommand final : public GlCommand
 {
@@ -49,9 +49,9 @@ public:
 	{
 	}
 
-	ANKI_USE_RESULT Error operator()(GlState& state)
+	ANKI_USE_RESULT Error operator()(GlState&)
 	{
-		m_renderingThread->swapBuffersInternal(state);
+		m_renderingThread->swapBuffersInternal();
 		return ErrorCode::NONE;
 	}
 };
@@ -77,7 +77,6 @@ RenderingThread::RenderingThread(GrManager* manager)
 	, m_head(0)
 	, m_renderingThreadSignal(0)
 	, m_thread("anki_gl")
-	, m_state(manager)
 {
 	ANKI_ASSERT(m_manager);
 }
@@ -89,11 +88,10 @@ RenderingThread::~RenderingThread()
 }
 
 //==============================================================================
-void RenderingThread::flushCommandBuffer(CommandBufferPtr commands)
+void RenderingThread::flushCommandBuffer(CommandBufferPtr cmdb)
 {
-	commands->getImplementation().makeImmutable();
+	cmdb->getImplementation().makeImmutable();
 
-#if !ANKI_DISABLE_GL_RENDERING_THREAD
 	{
 		LockGuard<Mutex> lock(m_mtx);
 
@@ -104,7 +102,7 @@ void RenderingThread::flushCommandBuffer(CommandBufferPtr commands)
 		{
 			U64 idx = m_tail % m_queue.getSize();
 
-			m_queue[idx] = commands;
+			m_queue[idx] = cmdb;
 			++m_tail;
 		}
 		else
@@ -114,33 +112,20 @@ void RenderingThread::flushCommandBuffer(CommandBufferPtr commands)
 
 		m_condVar.notifyOne(); // Wake the thread
 	}
-
-#else
-	Error err = commands->getImplementation().executeAllCommands();
-	if(err)
-	{
-		ANKI_LOGF("Error in command buffer execution");
-	}
-#endif
 }
 
 //==============================================================================
 void RenderingThread::finishCommandBuffer(CommandBufferPtr commands)
 {
-#if !ANKI_DISABLE_GL_RENDERING_THREAD
 	flushCommandBuffer(commands);
 
 	syncClientServer();
-#else
-	flushCommandBuffer(commands);
-#endif
 }
 
 //==============================================================================
-void RenderingThread::start(Bool registerMessages, const ConfigSet& config)
+void RenderingThread::start()
 {
 	ANKI_ASSERT(m_tail == 0 && m_head == 0);
-	m_state.m_registerMessages = registerMessages;
 	m_queue.create(m_manager->getAllocator(), QUEUE_SIZE);
 
 	// Swap buffers stuff
@@ -149,10 +134,8 @@ void RenderingThread::start(Bool registerMessages, const ConfigSet& config)
 	m_swapBuffersCommands->getImplementation()
 		.pushBackNewCommand<SwapBuffersCommand>(this);
 
-	m_state.initMainThread(config);
 	m_manager->getImplementation().pinContextToCurrentThread(false);
 
-#if !ANKI_DISABLE_GL_RENDERING_THREAD
 	// Start thread
 	m_thread.start(this, threadCallback);
 
@@ -164,26 +147,17 @@ void RenderingThread::start(Bool registerMessages, const ConfigSet& config)
 	m_emptyCmdb =
 		m_manager->newInstance<CommandBuffer>(CommandBufferInitInfo());
 	m_emptyCmdb->getImplementation().pushBackNewCommand<EmptyCommand>();
-#else
-	prepare();
-
-	ANKI_LOGW("GL queue works in synchronous mode");
-#endif
 }
 
 //==============================================================================
 void RenderingThread::stop()
 {
-#if !ANKI_DISABLE_GL_RENDERING_THREAD
 	syncClientServer();
 	m_renderingThreadSignal = 1;
 	flushCommandBuffer(m_emptyCmdb);
 
 	Error err = m_thread.join();
 	(void)err;
-#else
-	finish();
-#endif
 }
 
 //==============================================================================
@@ -203,7 +177,10 @@ void RenderingThread::prepare()
 	m_serverThreadId = Thread::getCurrentThreadId();
 
 	// Init state
-	m_state.initRenderThread();
+	m_manager->getImplementation().getState().initRenderThread();
+
+	// Init dyn mem
+	m_manager->getImplementation().getDynamicMemoryManager().initRenderThread();
 }
 
 //==============================================================================
@@ -222,8 +199,12 @@ void RenderingThread::finish()
 		}
 	}
 
+	m_manager->getImplementation()
+		.getDynamicMemoryManager()
+		.destroyRenderThread();
+
 	// Cleanup GL
-	m_state.destroy();
+	m_manager->getImplementation().getState().destroy();
 
 	// Cleanup
 	glFinish();
@@ -287,18 +268,16 @@ void RenderingThread::threadLoop()
 //==============================================================================
 void RenderingThread::syncClientServer()
 {
-#if !ANKI_DISABLE_GL_RENDERING_THREAD
 	// Lock because there is only one barrier. If multiple threads call
 	// syncClientServer all of them will hit the same barrier.
 	LockGuard<SpinLock> lock(m_syncLock);
 
 	flushCommandBuffer(m_syncCommands);
 	m_syncBarrier.wait();
-#endif
 }
 
 //==============================================================================
-void RenderingThread::swapBuffersInternal(GlState& state)
+void RenderingThread::swapBuffersInternal()
 {
 	ANKI_TRACE_START_EVENT(SWAP_BUFFERS);
 
@@ -320,7 +299,6 @@ void RenderingThread::swapBuffersInternal(GlState& state)
 void RenderingThread::swapBuffers()
 {
 	ANKI_TRACE_START_EVENT(SWAP_BUFFERS);
-#if !ANKI_DISABLE_GL_RENDERING_THREAD
 	// Wait for the rendering thread to finish swap buffers...
 	{
 		LockGuard<Mutex> lock(m_frameMtx);
@@ -331,9 +309,8 @@ void RenderingThread::swapBuffers()
 
 		m_frameWait = true;
 	}
-#endif
 
-	m_state.m_dynamicMemoryManager.endFrame();
+	m_manager->getImplementation().getDynamicMemoryManager().endFrame();
 
 	// ...and then flush a new swap buffers
 	flushCommandBuffer(m_swapBuffersCommands);

+ 1 - 0
src/gr/gl/ResourceGroup.cpp

@@ -5,6 +5,7 @@
 
 #include <anki/gr/ResourceGroup.h>
 #include <anki/gr/gl/ResourceGroupImpl.h>
+#include <anki/gr/GrManager.h>
 #include <anki/gr/gl/CommandBufferImpl.h>
 #include <anki/gr/Texture.h>
 #include <anki/gr/Sampler.h>

+ 46 - 37
src/gr/gl/ResourceGroupImpl.cpp

@@ -14,6 +14,7 @@
 #include <anki/gr/gl/GrManagerImpl.h>
 #include <anki/gr/GrManager.h>
 #include <anki/gr/gl/RenderingThread.h>
+#include <anki/gr/gl/CommandBufferImpl.h>
 
 namespace anki
 {
@@ -24,7 +25,7 @@ void ResourceGroupImpl::initBuffers(const InBindings& in,
 	OutBindings& out,
 	U8& count,
 	U& resourcesCount,
-	U& dynCount)
+	U& transCount)
 {
 	count = 0;
 
@@ -34,7 +35,7 @@ void ResourceGroupImpl::initBuffers(const InBindings& in,
 
 		if(binding.m_buffer.isCreated())
 		{
-			ANKI_ASSERT(binding.m_dynamic == false);
+			ANKI_ASSERT(binding.m_uploadedMemory == false);
 
 			const BufferImpl& buff = binding.m_buffer->getImplementation();
 			InternalBufferBinding& outBinding = out[count];
@@ -52,11 +53,11 @@ void ResourceGroupImpl::initBuffers(const InBindings& in,
 			++resourcesCount;
 			count = i + 1;
 		}
-		else if(binding.m_dynamic)
+		else if(binding.m_uploadedMemory)
 		{
 			InternalBufferBinding& outBinding = out[count];
 			outBinding.m_name = MAX_U32;
-			++dynCount;
+			++transCount;
 			count = i + 1;
 		}
 	}
@@ -66,7 +67,7 @@ void ResourceGroupImpl::initBuffers(const InBindings& in,
 void ResourceGroupImpl::init(const ResourceGroupInitInfo& init)
 {
 	U resourcesCount = 0;
-	U dynCount = 0;
+	U transCount = 0;
 
 	// Init textures & samplers
 	m_textureNamesCount = 0;
@@ -100,14 +101,14 @@ void ResourceGroupImpl::init(const ResourceGroupInitInfo& init)
 
 	// Init shader buffers
 	initBuffers(
-		init.m_uniformBuffers, m_ubos, m_ubosCount, resourcesCount, dynCount);
+		init.m_uniformBuffers, m_ubos, m_ubosCount, resourcesCount, transCount);
 	initBuffers(
-		init.m_storageBuffers, m_ssbos, m_ssbosCount, resourcesCount, dynCount);
+		init.m_storageBuffers, m_ssbos, m_ssbosCount, resourcesCount, transCount);
 	initBuffers(init.m_atomicBuffers,
 		m_atomics,
 		m_atomicsCount,
 		resourcesCount,
-		dynCount);
+		transCount);
 
 	// Init vert buffers
 	m_vertBindingsCount = 0;
@@ -116,7 +117,7 @@ void ResourceGroupImpl::init(const ResourceGroupInitInfo& init)
 		const BufferBinding& binding = init.m_vertexBuffers[i];
 		if(binding.m_buffer.isCreated())
 		{
-			ANKI_ASSERT(!binding.m_dynamic);
+			ANKI_ASSERT(!binding.m_uploadedMemory);
 
 			m_vertBuffNames[i] =
 				binding.m_buffer->getImplementation().getGlName();
@@ -125,20 +126,15 @@ void ResourceGroupImpl::init(const ResourceGroupInitInfo& init)
 			++m_vertBindingsCount;
 			++resourcesCount;
 		}
-		else if(binding.m_dynamic)
+		else if(binding.m_uploadedMemory)
 		{
-			++dynCount;
-			const GlState& state = getManager()
-									   .getImplementation()
-									   .getRenderingThread()
-									   .getState();
+			++transCount;
 
-			m_vertBuffNames[i] =
-				state.m_dynamicMemoryManager.getGlName(BufferUsage::VERTEX);
+			m_vertBuffNames[i] = 0;
 			m_vertBuffOffsets[i] = MAX_U32;
 
 			++m_vertBindingsCount;
-			m_hasDynamicVertexBuff = true;
+			m_hasTransientVertexBuff = true;
 		}
 		else
 		{
@@ -160,7 +156,7 @@ void ResourceGroupImpl::init(const ResourceGroupInitInfo& init)
 		++resourcesCount;
 	}
 
-	ANKI_ASSERT((resourcesCount > 0 || dynCount > 0) && "Resource group empty");
+	ANKI_ASSERT((resourcesCount > 0 || transCount > 0) && "Resource group empty");
 
 	// Hold references
 	initResourceReferences(init, resourcesCount);
@@ -233,7 +229,7 @@ void ResourceGroupImpl::initResourceReferences(
 
 //==============================================================================
 void ResourceGroupImpl::bind(
-	U slot, const DynamicBufferInfo& dynInfo, GlState& state)
+	U slot, const TransientMemoryInfo& transientInfo, GlState& state)
 {
 	ANKI_ASSERT(slot < MAX_RESOURCE_GROUPS);
 
@@ -263,16 +259,18 @@ void ResourceGroupImpl::bind(
 		const auto& binding = m_ubos[i];
 		if(binding.m_name == MAX_U32)
 		{
-			// Dynamic
-			DynamicBufferToken token = dynInfo.m_uniformBuffers[i];
+			// Transient
+			TransientMemoryToken token = transientInfo.m_uniformBuffers[i];
 			ANKI_ASSERT(token.m_range != 0);
 
 			if(token.m_range != MAX_U32)
 			{
 				glBindBufferRange(GL_UNIFORM_BUFFER,
 					MAX_UNIFORM_BUFFER_BINDINGS * slot + i,
-					state.m_dynamicMemoryManager.getGlName(
-						BufferUsage::UNIFORM),
+					getManager()
+						.getImplementation()
+						.getDynamicMemoryManager()
+						.getGlName(token),
 					token.m_offset,
 					token.m_range);
 			}
@@ -298,16 +296,18 @@ void ResourceGroupImpl::bind(
 		const auto& binding = m_ssbos[i];
 		if(binding.m_name == MAX_U32)
 		{
-			// Dynamic
-			DynamicBufferToken token = dynInfo.m_storageBuffers[i];
+			// Transient
+			TransientMemoryToken token = transientInfo.m_storageBuffers[i];
 			ANKI_ASSERT(token.m_range != 0);
 
 			if(token.m_range != MAX_U32)
 			{
 				glBindBufferRange(GL_SHADER_STORAGE_BUFFER,
 					MAX_STORAGE_BUFFER_BINDINGS * slot + i,
-					state.m_dynamicMemoryManager.getGlName(
-						BufferUsage::STORAGE),
+					getManager()
+						.getImplementation()
+						.getDynamicMemoryManager()
+						.getGlName(token),
 					token.m_offset,
 					token.m_range);
 			}
@@ -333,7 +333,7 @@ void ResourceGroupImpl::bind(
 		const auto& binding = m_atomics[i];
 		if(binding.m_name == MAX_U32)
 		{
-			// Dynamic
+			// Transient
 			ANKI_ASSERT(0);
 		}
 		else if(binding.m_name != 0)
@@ -352,27 +352,37 @@ void ResourceGroupImpl::bind(
 	{
 		ANKI_ASSERT(slot == 0 && "Only slot 0 can have vertex buffers");
 
-		if(!m_hasDynamicVertexBuff)
+		if(!m_hasTransientVertexBuff)
 		{
 			memcpy(&state.m_vertBuffOffsets[0],
 				&m_vertBuffOffsets[0],
 				sizeof(m_vertBuffOffsets[0]) * m_vertBindingsCount);
+
+			memcpy(&state.m_vertBuffNames[0],
+				&m_vertBuffNames[0],
+				sizeof(m_vertBuffNames[0]) * m_vertBindingsCount);
 		}
 		else
 		{
 			// Copy the offsets
 			Array<GLintptr, MAX_VERTEX_ATTRIBUTES> offsets = m_vertBuffOffsets;
+			Array<GLuint, MAX_VERTEX_ATTRIBUTES> names = m_vertBuffNames;
+
 			for(U i = 0; i < MAX_VERTEX_ATTRIBUTES; ++i)
 			{
 				if(offsets[i] == MAX_U32)
 				{
 					// It's dynamic
-					ANKI_ASSERT(dynInfo.m_vertexBuffers[i].m_range != 0);
-					offsets[i] = dynInfo.m_vertexBuffers[i].m_offset;
+					ANKI_ASSERT(transientInfo.m_vertexBuffers[i].m_range != 0);
+					offsets[i] = transientInfo.m_vertexBuffers[i].m_offset;
+					names[i] = getManager()
+								   .getImplementation()
+								   .getDynamicMemoryManager()
+								   .getGlName(transientInfo.m_vertexBuffers[i]);
 				}
 				else
 				{
-					ANKI_ASSERT(dynInfo.m_vertexBuffers[i].m_range == 0);
+					ANKI_ASSERT(transientInfo.m_vertexBuffers[i].m_range == 0);
 				}
 			}
 
@@ -380,11 +390,10 @@ void ResourceGroupImpl::bind(
 			memcpy(&state.m_vertBuffOffsets[0],
 				&offsets[0],
 				sizeof(offsets[0]) * m_vertBindingsCount);
-		}
 
-		memcpy(&state.m_vertBuffNames[0],
-			&m_vertBuffNames[0],
-			sizeof(m_vertBuffNames[0]) * m_vertBindingsCount);
+			memcpy(
+				&names[0], &names[0], sizeof(names[0]) * m_vertBindingsCount);
+		}
 
 		state.m_vertBindingCount = m_vertBindingsCount;
 		state.m_vertBindingsDirty = true;

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

@@ -6,6 +6,7 @@
 #include <anki/gr/Sampler.h>
 #include <anki/gr/gl/SamplerImpl.h>
 #include <anki/gr/gl/CommandBufferImpl.h>
+#include <anki/gr/GrManager.h>
 
 namespace anki
 {

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

@@ -6,6 +6,7 @@
 #include <anki/gr/Shader.h>
 #include <anki/gr/gl/ShaderImpl.h>
 #include <anki/gr/gl/CommandBufferImpl.h>
+#include <anki/gr/GrManager.h>
 
 namespace anki
 {

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

@@ -6,6 +6,7 @@
 #include <anki/gr/Texture.h>
 #include <anki/gr/gl/TextureImpl.h>
 #include <anki/gr/gl/CommandBufferImpl.h>
+#include <anki/gr/GrManager.h>
 
 namespace anki
 {

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

@@ -255,7 +255,7 @@ TextureImpl::~TextureImpl()
 	else
 	{
 		DeleteTextureCommand cmd(m_glName, m_texViews, getAllocator());
-		cmd(thread.getState());
+		cmd(manager.getImplementation().getState());
 	}
 
 	m_glName = 0;

+ 3 - 3
src/renderer/Bloom.cpp

@@ -116,7 +116,7 @@ Error Bloom::initInternal(const ConfigSet& config)
 	{
 		ResourceGroupInitInfo descInit;
 		descInit.m_textures[0].m_texture = m_r->getIs().getRt();
-		descInit.m_uniformBuffers[0].m_dynamic = true;
+		descInit.m_uniformBuffers[0].m_uploadedMemory = true;
 
 		descInit.m_storageBuffers[0].m_buffer =
 			m_r->getTm().getAverageLuminanceBuffer();
@@ -162,9 +162,9 @@ void Bloom::run(RenderingContext& ctx)
 	cmdb->setViewport(0, 0, m_width, m_height);
 	cmdb->bindPipeline(m_tonePpline);
 
-	DynamicBufferInfo dyn;
+	TransientMemoryInfo dyn;
 	Vec4* uniforms =
-		static_cast<Vec4*>(getGrManager().allocateFrameHostVisibleMemory(
+		static_cast<Vec4*>(getGrManager().allocateFrameTransientMemory(
 			sizeof(Vec4), BufferUsage::UNIFORM, dyn.m_uniformBuffers[0]));
 	*uniforms = Vec4(m_threshold, m_scale, 0.0, 0.0);
 

+ 2 - 2
src/renderer/Drawer.cpp

@@ -34,7 +34,7 @@ public:
 	Array<Mat4, MAX_INSTANCES> m_cachedTrfs;
 	U m_cachedTrfCount = 0;
 	const MaterialVariant* m_variant = nullptr;
-	DynamicBufferInfo m_dynBufferInfo;
+	TransientMemoryInfo m_dynBufferInfo;
 	F32 m_flod = 0.0;
 	VisibleNode* m_visibleNode = nullptr;
 	VisibleNode* m_nextVisibleNode = nullptr;
@@ -214,7 +214,7 @@ void RenderableDrawer::setupUniforms(DrawContext& ctx,
 
 	// Get some memory for uniforms
 	U8* uniforms =
-		static_cast<U8*>(m_r->getGrManager().allocateFrameHostVisibleMemory(
+		static_cast<U8*>(m_r->getGrManager().allocateFrameTransientMemory(
 			variant.getDefaultBlockSize(),
 			BufferUsage::UNIFORM,
 			ctx.m_dynBufferInfo.m_uniformBuffers[0]));

+ 5 - 5
src/renderer/Fs.cpp

@@ -56,12 +56,12 @@ Error Fs::init(const ConfigSet&)
 			init.m_textures[2].m_texture = m_r->getSm().getOmniTextureArray();
 		}
 
-		init.m_uniformBuffers[0].m_dynamic = true;
-		init.m_uniformBuffers[1].m_dynamic = true;
-		init.m_uniformBuffers[2].m_dynamic = true;
+		init.m_uniformBuffers[0].m_uploadedMemory = true;
+		init.m_uniformBuffers[1].m_uploadedMemory = true;
+		init.m_uniformBuffers[2].m_uploadedMemory = true;
 
-		init.m_storageBuffers[0].m_dynamic = true;
-		init.m_storageBuffers[1].m_dynamic = true;
+		init.m_storageBuffers[0].m_uploadedMemory = true;
+		init.m_storageBuffers[1].m_uploadedMemory = true;
 
 		m_globalResources = getGrManager().newInstance<ResourceGroup>(init);
 	}

+ 3 - 3
src/renderer/Ir.cpp

@@ -162,7 +162,7 @@ Error Ir::initIrradiance()
 
 	// Create the resources
 	ResourceGroupInitInfo rcInit;
-	rcInit.m_uniformBuffers[0].m_dynamic = true;
+	rcInit.m_uniformBuffers[0].m_uploadedMemory = true;
 	rcInit.m_textures[0].m_texture = m_envCubemapArr;
 
 	m_computeIrradianceResources =
@@ -282,9 +282,9 @@ Error Ir::renderReflection(RenderingContext& ctx,
 	cmdb->setViewport(0, 0, IRRADIANCE_TEX_SIZE, IRRADIANCE_TEX_SIZE);
 	for(U i = 0; i < 6; ++i)
 	{
-		DynamicBufferInfo dinf;
+		TransientMemoryInfo dinf;
 		UVec4* faceIdxArrayIdx =
-			static_cast<UVec4*>(getGrManager().allocateFrameHostVisibleMemory(
+			static_cast<UVec4*>(getGrManager().allocateFrameTransientMemory(
 				sizeof(UVec4), BufferUsage::UNIFORM, dinf.m_uniformBuffers[0]));
 		faceIdxArrayIdx->x() = i;
 		faceIdxArrayIdx->y() = cubemapIdx;

+ 20 - 15
src/renderer/Is.cpp

@@ -61,6 +61,12 @@ struct ShaderProbe
 	F32 m_radiusSq;
 	F32 m_cubemapIndex;
 	U32 _m_pading[3];
+
+	ShaderProbe()
+	{
+		// To avoid warnings
+		_m_pading[0] = _m_pading[1] = _m_pading[2] = 0;
+	}
 };
 
 struct ShaderCommonUniforms
@@ -454,13 +460,13 @@ Error Is::initInternal(const ConfigSet& config)
 				m_r->getIr().getIntegrationLutSampler();
 		}
 
-		init.m_uniformBuffers[0].m_dynamic = true;
-		init.m_uniformBuffers[1].m_dynamic = true;
-		init.m_uniformBuffers[2].m_dynamic = true;
-		init.m_uniformBuffers[3].m_dynamic = true;
+		init.m_uniformBuffers[0].m_uploadedMemory = true;
+		init.m_uniformBuffers[1].m_uploadedMemory = true;
+		init.m_uniformBuffers[2].m_uploadedMemory = true;
+		init.m_uniformBuffers[3].m_uploadedMemory = true;
 
-		init.m_storageBuffers[0].m_dynamic = true;
-		init.m_storageBuffers[1].m_dynamic = true;
+		init.m_storageBuffers[0].m_uploadedMemory = true;
+		init.m_storageBuffers[1].m_uploadedMemory = true;
 
 		m_rcGroup = getGrManager().newInstance<ResourceGroup>(init);
 	}
@@ -506,7 +512,7 @@ Error Is::populateBuffers(RenderingContext& ctx)
 	if(visiblePointLightsCount)
 	{
 		ShaderPointLight* data = static_cast<ShaderPointLight*>(
-			getGrManager().allocateFrameHostVisibleMemory(
+			getGrManager().allocateFrameTransientMemory(
 				sizeof(ShaderPointLight) * visiblePointLightsCount,
 				BufferUsage::UNIFORM,
 				ctx.m_is.m_dynBufferInfo.m_uniformBuffers[P_LIGHTS_LOCATION]));
@@ -527,7 +533,7 @@ Error Is::populateBuffers(RenderingContext& ctx)
 	if(visibleSpotLightsCount)
 	{
 		ShaderSpotLight* data = static_cast<ShaderSpotLight*>(
-			getGrManager().allocateFrameHostVisibleMemory(
+			getGrManager().allocateFrameTransientMemory(
 				sizeof(ShaderSpotLight) * visibleSpotLightsCount,
 				BufferUsage::UNIFORM,
 				ctx.m_is.m_dynBufferInfo.m_uniformBuffers[S_LIGHTS_LOCATION]));
@@ -548,7 +554,7 @@ Error Is::populateBuffers(RenderingContext& ctx)
 	if(m_r->getIrEnabled() && visibleProbeCount)
 	{
 		ShaderProbe* data = static_cast<ShaderProbe*>(
-			getGrManager().allocateFrameHostVisibleMemory(
+			getGrManager().allocateFrameTransientMemory(
 				sizeof(ShaderProbe) * visibleProbeCount,
 				BufferUsage::UNIFORM,
 				ctx.m_is.m_dynBufferInfo.m_uniformBuffers[PROBES_LOCATION]));
@@ -567,8 +573,8 @@ Error Is::populateBuffers(RenderingContext& ctx)
 	taskData.m_is = this;
 
 	// Get mem for clusters
-	ShaderCluster* data = static_cast<ShaderCluster*>(
-		getGrManager().allocateFrameHostVisibleMemory(
+	ShaderCluster* data =
+		static_cast<ShaderCluster*>(getGrManager().allocateFrameTransientMemory(
 			sizeof(ShaderCluster) * clusterCount,
 			BufferUsage::STORAGE,
 			ctx.m_is.m_dynBufferInfo.m_storageBuffers[CLUSTERS_LOCATION]));
@@ -576,9 +582,8 @@ Error Is::populateBuffers(RenderingContext& ctx)
 	taskData.m_clusters = WeakArray<ShaderCluster>(data, clusterCount);
 
 	// Allocate light IDs
-	U32* data2 =
-		static_cast<U32*>(getGrManager().allocateFrameHostVisibleMemory(
-			m_maxLightIds * sizeof(U32),
+	U32* data2 = static_cast<U32*>(
+		getGrManager().allocateFrameTransientMemory(m_maxLightIds * sizeof(U32),
 			BufferUsage::STORAGE,
 			ctx.m_is.m_dynBufferInfo.m_storageBuffers[LIGHT_IDS_LOCATION]));
 
@@ -978,7 +983,7 @@ void Is::run(RenderingContext& ctx)
 void Is::updateCommonBlock(const FrustumComponent& fr, RenderingContext& ctx)
 {
 	ShaderCommonUniforms* blk = static_cast<ShaderCommonUniforms*>(
-		getGrManager().allocateFrameHostVisibleMemory(
+		getGrManager().allocateFrameTransientMemory(
 			sizeof(ShaderCommonUniforms),
 			BufferUsage::UNIFORM,
 			ctx.m_is.m_dynBufferInfo.m_uniformBuffers[COMMON_VARS_LOCATION]));

+ 10 - 10
src/renderer/Lf.cpp

@@ -135,8 +135,8 @@ Error Lf::initOcclusion(const ConfigSet& config)
 	// Init resource group
 	{
 		ResourceGroupInitInfo rcInit;
-		rcInit.m_vertexBuffers[0].m_dynamic = true;
-		rcInit.m_uniformBuffers[0].m_dynamic = true;
+		rcInit.m_vertexBuffers[0].m_uploadedMemory = true;
+		rcInit.m_uniformBuffers[0].m_uploadedMemory = true;
 		m_occlusionRcGroup = getGrManager().newInstance<ResourceGroup>(rcInit);
 	}
 
@@ -171,22 +171,22 @@ void Lf::runOcclusionTests(RenderingContext& ctx)
 	if(totalCount > 0)
 	{
 		// Setup MVP UBO
-		DynamicBufferToken token;
+		TransientMemoryToken token;
 		Mat4* mvp =
-			static_cast<Mat4*>(getGrManager().allocateFrameHostVisibleMemory(
+			static_cast<Mat4*>(getGrManager().allocateFrameTransientMemory(
 				sizeof(Mat4), BufferUsage::UNIFORM, token));
 		*mvp = camFr.getViewProjectionMatrix();
 
 		// Alloc dyn mem
-		DynamicBufferToken token2;
+		TransientMemoryToken token2;
 		Vec3* positions =
-			static_cast<Vec3*>(getGrManager().allocateFrameHostVisibleMemory(
+			static_cast<Vec3*>(getGrManager().allocateFrameTransientMemory(
 				sizeof(Vec3) * totalCount, BufferUsage::VERTEX, token2));
 		const Vec3* initialPositions = positions;
 
 		// Setup state
 		cmdb->bindPipeline(m_occlusionPpline);
-		DynamicBufferInfo dyn;
+		TransientMemoryInfo dyn;
 		dyn.m_uniformBuffers[0] = token;
 		dyn.m_vertexBuffers[0] = token2;
 		cmdb->bindResourceGroup(m_occlusionRcGroup, 0, &dyn);
@@ -255,9 +255,9 @@ void Lf::run(RenderingContext& ctx)
 			U spritesCount = max<U>(1, m_maxSpritesPerFlare); // TODO
 
 			// Get uniform memory
-			DynamicBufferToken token;
+			TransientMemoryToken token;
 			Sprite* tmpSprites = static_cast<Sprite*>(
-				getGrManager().allocateFrameHostVisibleMemory(
+				getGrManager().allocateFrameTransientMemory(
 					spritesCount * sizeof(Sprite),
 					BufferUsage::UNIFORM,
 					token));
@@ -286,7 +286,7 @@ void Lf::run(RenderingContext& ctx)
 
 			if(!queryInvalid)
 			{
-				DynamicBufferInfo dyn;
+				TransientMemoryInfo dyn;
 				dyn.m_uniformBuffers[0] = token;
 				cmdb->bindResourceGroup(lf.getResourceGroup(), 0, &dyn);
 				cmdb->drawArraysConditional(query, 4);

+ 1 - 2
src/renderer/Renderer.cpp

@@ -226,8 +226,7 @@ Error Renderer::render(RenderingContext& ctx)
 	// Write the common uniforms
 	RendererCommonUniforms* commonUniforms =
 		static_cast<RendererCommonUniforms*>(
-			getGrManager().allocateFrameHostVisibleMemory(
-				sizeof(*commonUniforms),
+			getGrManager().allocateFrameTransientMemory(sizeof(*commonUniforms),
 				BufferUsage::UNIFORM,
 				m_commonUniformsToken));
 

+ 7 - 7
src/renderer/Ssao.cpp

@@ -122,13 +122,13 @@ Error Ssao::initInternal(const ConfigSet& config)
 
 	PtrSize noiseSize = NOISE_TEX_SIZE * NOISE_TEX_SIZE * sizeof(Vec3);
 
-	DynamicBufferToken token;
-	Vec3* noise = static_cast<Vec3*>(gr.allocateFrameHostVisibleMemory(
+	TransientMemoryToken token;
+	Vec3* noise = static_cast<Vec3*>(gr.allocateFrameTransientMemory(
 		noiseSize, BufferUsage::TRANSFER, token));
 
 	genNoise(noise, noise + NOISE_TEX_SIZE * NOISE_TEX_SIZE);
 
-	cmdb->textureUpload(m_noiseTex, TextureSurfaceInfo(0, 0, 0), token);
+	cmdb->uploadTextureSurface(m_noiseTex, TextureSurfaceInfo(0, 0, 0), token);
 	cmdb->flush();
 
 	//
@@ -240,7 +240,7 @@ Error Ssao::initInternal(const ConfigSet& config)
 
 	rcinit.m_textures[2].m_texture = m_noiseTex;
 
-	rcinit.m_uniformBuffers[0].m_dynamic = true;
+	rcinit.m_uniformBuffers[0].m_uploadedMemory = true;
 	m_rcFirst = gr.newInstance<ResourceGroup>(rcinit);
 
 	rcinit = ResourceGroupInitInfo();
@@ -279,9 +279,9 @@ void Ssao::run(RenderingContext& ctx)
 	cmdb->setViewport(0, 0, m_width, m_height);
 	cmdb->bindPipeline(m_ssaoPpline);
 
-	DynamicBufferInfo dyn;
-	dyn.m_uniformBuffers[0] = m_r->getCommonUniformsDynamicBufferToken();
-	cmdb->bindResourceGroup(m_rcFirst, 0, &dyn);
+	TransientMemoryInfo inf;
+	inf.m_uniformBuffers[0] = m_r->getCommonUniformsTransientMemoryToken();
+	cmdb->bindResourceGroup(m_rcFirst, 0, &inf);
 
 	// Draw
 	m_r->drawQuad(cmdb);

+ 3 - 3
src/renderer/Tm.cpp

@@ -41,11 +41,11 @@ Error Tm::create(const ConfigSet& initializer)
 
 	CommandBufferPtr cmdb =
 		getGrManager().newInstance<CommandBuffer>(CommandBufferInitInfo());
-	DynamicBufferToken token;
-	void* data = getGrManager().allocateFrameHostVisibleMemory(
+	TransientMemoryToken token;
+	void* data = getGrManager().allocateFrameTransientMemory(
 		sizeof(Vec4), BufferUsage::TRANSFER, token);
 	*static_cast<Vec4*>(data) = Vec4(0.5);
-	cmdb->writeBuffer(m_luminanceBuff, 0, token);
+	cmdb->uploadBuffer(m_luminanceBuff, 0, token);
 	cmdb->flush();
 
 	// Create descriptors

+ 3 - 3
src/renderer/Upsample.cpp

@@ -44,7 +44,7 @@ Error Upsample::init(const ConfigSet& config)
 		rcInit.m_textures[4].m_texture = m_r->getSsao().getRt();
 	}
 
-	rcInit.m_uniformBuffers[0].m_dynamic = true;
+	rcInit.m_uniformBuffers[0].m_uploadedMemory = true;
 
 	m_rcGroup = getGrManager().newInstance<ResourceGroup>(rcInit);
 
@@ -93,10 +93,10 @@ Error Upsample::init(const ConfigSet& config)
 void Upsample::run(RenderingContext& ctx)
 {
 	CommandBufferPtr cmdb = ctx.m_commandBuffer;
-	DynamicBufferInfo dyn;
+	TransientMemoryInfo dyn;
 
 	Vec4* linearDepth =
-		static_cast<Vec4*>(getGrManager().allocateFrameHostVisibleMemory(
+		static_cast<Vec4*>(getGrManager().allocateFrameTransientMemory(
 			sizeof(Vec4), BufferUsage::UNIFORM, dyn.m_uniformBuffers[0]));
 	const Frustum& fr = ctx.m_frustumComponent->getFrustum();
 	computeLinearizeDepthOptimal(

+ 3 - 3
src/renderer/Volumetric.cpp

@@ -34,7 +34,7 @@ Error Volumetric::init(const ConfigSet& config)
 	// Create the resource group
 	ResourceGroupInitInfo rcInit;
 	rcInit.m_textures[0].m_texture = m_r->getMs().getDepthRt();
-	rcInit.m_uniformBuffers[0].m_dynamic = true;
+	rcInit.m_uniformBuffers[0].m_uploadedMemory = true;
 
 	m_rcGroup = getGrManager().newInstance<ResourceGroup>(rcInit);
 
@@ -48,9 +48,9 @@ void Volumetric::run(RenderingContext& ctx)
 	CommandBufferPtr& cmdb = ctx.m_commandBuffer;
 
 	// Update uniforms
-	DynamicBufferInfo dyn;
+	TransientMemoryInfo dyn;
 	Vec4* uniforms =
-		static_cast<Vec4*>(getGrManager().allocateFrameHostVisibleMemory(
+		static_cast<Vec4*>(getGrManager().allocateFrameTransientMemory(
 			sizeof(Vec4) * 2, BufferUsage::UNIFORM, dyn.m_uniformBuffers[0]));
 
 	computeLinearizeDepthOptimal(

+ 1 - 1
src/resource/Material.cpp

@@ -440,7 +440,7 @@ Error Material::createProgramSourceToCache(
 //==============================================================================
 void Material::fillResourceGroupInitInfo(ResourceGroupInitInfo& rcinit)
 {
-	rcinit.m_uniformBuffers[0].m_dynamic = true;
+	rcinit.m_uniformBuffers[0].m_uploadedMemory = true;
 
 	UpdateTexturesVisitor visitor;
 	visitor.m_init = &rcinit;

+ 12 - 10
src/resource/Mesh.cpp

@@ -44,16 +44,17 @@ Error MeshLoadTask::operator()(AsyncLoaderTaskContext& ctx)
 	// Write vert buff
 	if(m_vertBuff)
 	{
-		DynamicBufferToken token;
-		void* data = gr.allocateFrameHostVisibleMemory(
-			m_loader.getVertexDataSize(), BufferUsage::TRANSFER, token);
+		TransientMemoryToken token;
+		Error err = ErrorCode::NONE;
+		void* data = gr.allocateFrameTransientMemory(
+			m_loader.getVertexDataSize(), BufferUsage::TRANSFER, token, &err);
 
-		if(data)
+		if(!err)
 		{
 			memcpy(
 				data, m_loader.getVertexData(), m_loader.getVertexDataSize());
 			cmdb = gr.newInstance<CommandBuffer>(CommandBufferInitInfo());
-			cmdb->writeBuffer(m_vertBuff, 0, token);
+			cmdb->uploadBuffer(m_vertBuff, 0, token);
 			m_vertBuff.reset(nullptr);
 		}
 		else
@@ -66,11 +67,12 @@ Error MeshLoadTask::operator()(AsyncLoaderTaskContext& ctx)
 
 	// Create index buffer
 	{
-		DynamicBufferToken token;
-		void* data = gr.allocateFrameHostVisibleMemory(
-			m_loader.getIndexDataSize(), BufferUsage::TRANSFER, token);
+		TransientMemoryToken token;
+		Error err = ErrorCode::NONE;
+		void* data = gr.allocateFrameTransientMemory(
+			m_loader.getIndexDataSize(), BufferUsage::TRANSFER, token, &err);
 
-		if(data)
+		if(!err)
 		{
 			memcpy(data, m_loader.getIndexData(), m_loader.getIndexDataSize());
 
@@ -79,7 +81,7 @@ Error MeshLoadTask::operator()(AsyncLoaderTaskContext& ctx)
 				cmdb = gr.newInstance<CommandBuffer>(CommandBufferInitInfo());
 			}
 
-			cmdb->writeBuffer(m_indicesBuff, 0, token);
+			cmdb->uploadBuffer(m_indicesBuff, 0, token);
 			cmdb->flush();
 		}
 		else

+ 6 - 5
src/resource/TextureResource.cpp

@@ -56,11 +56,12 @@ Error TexUploadTask::operator()(AsyncLoaderTaskContext& ctx)
 				U surfIdx = max(depth, face);
 				const auto& surf = m_loader.getSurface(mip, surfIdx);
 
-				DynamicBufferToken token;
-				void* data = m_gr->allocateFrameHostVisibleMemory(
-					surf.m_data.getSize(), BufferUsage::TRANSFER, token);
+				TransientMemoryToken token;
+				Error err = ErrorCode::NONE;
+				void* data = m_gr->allocateFrameTransientMemory(
+					surf.m_data.getSize(), BufferUsage::TRANSFER, token, &err);
 
-				if(data)
+				if(!err)
 				{
 					// There is enough transfer memory
 
@@ -72,7 +73,7 @@ Error TexUploadTask::operator()(AsyncLoaderTaskContext& ctx)
 							CommandBufferInitInfo());
 					}
 
-					cmdb->textureUpload(
+					cmdb->uploadTextureSurface(
 						m_tex, TextureSurfaceInfo(mip, depth, face), token);
 				}
 				else

+ 1 - 1
src/scene/LensFlareComponent.cpp

@@ -40,7 +40,7 @@ Error LensFlareComponent::init(const CString& textureFilename)
 	// Resource group
 	ResourceGroupInitInfo rcInit;
 	rcInit.m_textures[0].m_texture = m_tex->getGrTexture();
-	rcInit.m_uniformBuffers[0].m_dynamic = true;
+	rcInit.m_uniformBuffers[0].m_uploadedMemory = true;
 	m_rcGroup = gr.newInstance<ResourceGroup>(rcInit);
 
 	return ErrorCode::NONE;

+ 3 - 3
src/ui/UiInterfaceImpl.cpp

@@ -220,11 +220,11 @@ Error UiInterfaceImpl::createR8Image(
 	// Load data
 	CommandBufferPtr cmdb =
 		m_gr->newInstance<CommandBuffer>(CommandBufferInitInfo());
-	DynamicBufferToken token;
-	void* loadData = m_gr->allocateFrameHostVisibleMemory(
+	TransientMemoryToken token;
+	void* loadData = m_gr->allocateFrameTransientMemory(
 		data.getSize(), BufferUsage::TRANSFER, token);
 	memcpy(loadData, &data[0], data.getSize());
-	cmdb->textureUpload(tex, TextureSurfaceInfo(0, 0, 0), token);
+	cmdb->uploadTextureSurface(tex, TextureSurfaceInfo(0, 0, 0), token);
 
 	// Gen mips
 	cmdb->generateMipmaps(tex, 0, 0);