Browse Source

Refactoring the way GPU dynamic memory works

Panagiotis Christopoulos Charitos 10 years ago
parent
commit
40382c383f

+ 0 - 16
include/anki/Config.h.cmake

@@ -146,20 +146,4 @@
 // GL
 #define ANKI_GL_MAX_SUB_DRAWCALLS 64
 
-namespace anki {
-
-/// Max size of the dynamic uniforms ring buffer. You will get a warning it's
-/// not enough
-const unsigned GR_DYNAMIC_UNIFORMS_SIZE = 1024 * 1024 * 16;
-
-/// Max size of the dynamic storage ring buffer. You will get a warning it's
-/// not enough
-const unsigned GR_DYNAMIC_STORAGE_SIZE = 1024 * 1024 * 16;
-
-/// Max size of the dynamic vertex ring buffer. You will get a warning it's
-/// not enough
-const unsigned GR_DYNAMIC_VERTEX_SIZE = 1024 * 1024 * 2;
-
-} // end namespace anki
-
 /// @}

+ 9 - 39
include/anki/gr/CommandBuffer.h

@@ -145,36 +145,15 @@ public:
 	/// @name Resource upload
 	/// @{
 
-	/// Used to upload data to a texture.
-	template<typename Type>
-	void textureUpload(TexturePtr tex, U32 mipmap, U32 slice, PtrSize dataSize,
-		Type*& data)
-	{
-		void* vdata = nullptr;
-		textureUploadInternal(tex, mipmap, slice, dataSize, vdata);
-		data = static_cast<Type*>(vdata);
-	}
-
-	/// Write data to a buffer.
-	template<typename Type>
-	void writeBuffer(BufferPtr buff, PtrSize offset, PtrSize range,
-		Type*& data)
-	{
-		void* vdata = nullptr;
-		writeBufferInternal(buff, offset, range, vdata);
-		data = static_cast<Type*>(vdata);
-	}
-
-	/// Allocate memory for dynamic buffers.
-	template<typename Type>
-	Type* allocateDynamicMemory(U32 count, BufferUsage usage,
-		DynamicBufferToken& token)
-	{
-		void* ptr = allocateDynamicMemoryInternal(count * sizeof(Type),
-			usage, token);
-		ANKI_ASSERT(isAligned(alignof(Type), static_cast<U8*>(ptr)));
-		return static_cast<Type*>(ptr);
-	}
+	/// Upload data to a texture.
+	void textureUpload(TexturePtr tex, U32 mipmap, U32 slice,
+		const DynamicBufferToken& 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);
 	/// @}
 
 	/// @name Other
@@ -194,15 +173,6 @@ public:
 
 private:
 	UniquePtr<CommandBufferImpl> m_impl;
-
-	void textureUploadInternal(TexturePtr tex, U32 mipmap, U32 slice,
-		PtrSize dataSize, void*& data);
-
-	void writeBufferInternal(BufferPtr buff, PtrSize offset, PtrSize range,
-		void*& data);
-
-	void* allocateDynamicMemoryInternal(U32 size, BufferUsage usage,
-		DynamicBufferToken& token);
 };
 /// @}
 

+ 14 - 0
include/anki/gr/Common.h

@@ -45,6 +45,20 @@ ANKI_GR_CLASS(ResourceGroup)
 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;
+	}
+};
+
 // Some constants
 // WARNING: If you change those update the shaders
 const U MAX_VERTEX_ATTRIBUTES = 8;

+ 1 - 0
include/anki/gr/Enums.h

@@ -290,6 +290,7 @@ enum class BufferUsage: U8
 	INDEX,
 	VERTEX,
 	INDIRECT,
+	TRANSFER, ///< For texture upload and buffer write.
 
 	COUNT,
 	FIRST = UNIFORM

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

@@ -10,6 +10,9 @@
 
 namespace anki {
 
+// Forward
+class ConfigSet;
+
 /// @addtogroup graphics
 /// @{
 
@@ -40,6 +43,8 @@ public:
 
 	CString m_cacheDirectory;
 	Bool m_registerDebugMessages = false;
+
+	const ConfigSet* m_config = nullptr;
 };
 
 /// The graphics manager, owner of all graphics objects.
@@ -65,6 +70,11 @@ public:
 	template<typename T, typename... Args>
 	IntrusivePtr<T> newInstance(Args&&... args);
 
+	/// Allocate memory for dynamic buffers. The memory will be reclaimed at
+	/// the begining of the next frame.
+	void* allocateFrameHostVisibleMemory(PtrSize size, BufferUsage usage,
+		DynamicBufferToken& token);
+
 anki_internal:
 	GrAllocator<U8>& getAllocator()
 	{

+ 0 - 14
include/anki/gr/ResourceGroup.h

@@ -45,20 +45,6 @@ public:
 	I8 m_indexSize = -1; ///< Index size in bytes. 2 or 4
 };
 
-/// 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 invalidate()
-	{
-		m_offset = m_range = MAX_U32;
-	}
-};
-
 /// Struct to help update the offset of the dynamic buffers.
 class DynamicBufferInfo
 {

+ 27 - 14
include/anki/gr/gl/GlState.h

@@ -10,6 +10,9 @@
 
 namespace anki {
 
+// Forward
+class ConfigSet;
+
 /// @addtogroup opengl
 /// @{
 
@@ -79,13 +82,13 @@ public:
 	class DynamicBuffer
 	{
 	public:
-		GLuint m_name;
-		U8* m_address;
-		PtrSize m_size; ///< This is aligned compared to GLOBAL_XXX_SIZE
-		U32 m_alignment;
-		U32 m_maxAllocationSize; ///< For debugging.
+		GLuint m_name = 0;
+		U8* m_address = nullptr; ///< Host address of the buffer.
+		PtrSize m_size = 0; ///< This is aligned compared to GLOBAL_XXX_SIZE
+		U32 m_alignment = 0; ///< Always work in that alignment.
+		U32 m_maxAllocationSize = 0; ///< For debugging.
 		Atomic<PtrSize> m_currentOffset = {0};
-		Atomic<PtrSize> m_bytesUsed = {0}; ///< Per frame. Mainly for debug
+		Atomic<PtrSize> m_bytesUsed = {0}; ///< Per frame. For debugging.
 	};
 
 	Array<DynamicBuffer, U(BufferUsage::COUNT)> m_dynamicBuffers;
@@ -95,34 +98,40 @@ public:
 		: m_manager(manager)
 	{}
 
+	/// Call this from the main thread.
+	void init0(const ConfigSet& config);
+
 	/// Call this from the rendering thread.
-	void init();
+	void init1();
 
 	/// Call this from the rendering thread.
 	void destroy();
 
 	/// Allocate memory for a dynamic buffer.
-	void* allocateDynamicMemory(PtrSize size, BufferUsage usage);
+	void* allocateDynamicMemory(PtrSize size, BufferUsage usage,
+		DynamicBufferToken& token);
 
 	void checkDynamicMemoryConsumption();
 
 private:
 	GrManager* m_manager;
+	DArray<U8> m_transferBuffer;
 
-	void initDynamicBuffer(GLenum target, U32 aligment, PtrSize size,
-		U32 maxAllocationSize, BufferUsage usage);
+	void initDynamicBuffer(GLenum target, U32 aligment, U32 maxAllocationSize,
+		BufferUsage usage);
 };
 
 //==============================================================================
-inline void* GlState::allocateDynamicMemory(PtrSize size, BufferUsage usage)
+inline void* GlState::allocateDynamicMemory(PtrSize originalSize,
+	BufferUsage usage, DynamicBufferToken& token)
 {
-	ANKI_ASSERT(size > 0);
+	ANKI_ASSERT(originalSize > 0);
 
 	DynamicBuffer& buff = m_dynamicBuffers[usage];
-	ANKI_ASSERT(buff.m_name != 0);
+	ANKI_ASSERT(buff.m_address);
 
 	// Align size
-	size = getAlignedRoundUp(buff.m_alignment, size);
+	PtrSize size = getAlignedRoundUp(buff.m_alignment, originalSize);
 	ANKI_ASSERT(size <= buff.m_maxAllocationSize && "Too high!");
 
 	// Allocate
@@ -141,6 +150,10 @@ inline void* GlState::allocateDynamicMemory(PtrSize size, BufferUsage usage)
 
 	buff.m_bytesUsed.fetchAdd(size);
 
+	// Encode token
+	token.m_offset = offset;
+	token.m_range = originalSize;
+
 	return static_cast<void*>(buff.m_address + offset);
 }
 /// @}

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

@@ -40,7 +40,8 @@ public:
 
 	/// Start the working thread
 	/// @note Don't free the context before calling #stop
-	void start(WeakPtr<GrManagerInterface> interface, Bool registerMessages);
+	void start(WeakPtr<GrManagerInterface> interface, Bool registerMessages,
+		const ConfigSet& config);
 
 	/// Stop the working thread
 	void stop();

+ 1 - 0
include/anki/renderer/DebugDrawer.h

@@ -92,6 +92,7 @@ private:
 		Vec4 m_color;
 	};
 
+	Renderer* m_r;
 	ShaderResourcePtr m_frag;
 	ShaderResourcePtr m_vert;
 	PipelinePtr m_pplineLinesDepth;

+ 1 - 0
src/core/App.cpp

@@ -231,6 +231,7 @@ Error App::createInternal(const ConfigSet& config_,
 	grInit.m_interface = m_grInterface;
 	grInit.m_cacheDirectory = m_cacheDir.toCString();
 	grInit.m_registerDebugMessages = nwinit.m_debugContext;
+	grInit.m_config = &config;
 
 	ANKI_CHECK(m_gr->create(grInit));
 

+ 7 - 1
src/core/Config.cpp

@@ -79,7 +79,13 @@ Config::Config()
 	newOption("sceneFrameAllocatorSize", 1024 * 1024);
 	newOption("clusterSizeZ", 32);
 
-	newOption("offscreen", false);
+	//
+	// GR
+	//
+	newOption("gr.frameUniformsSize", 1024 * 1024 * 16);
+	newOption("gr.frameStorageSize", 1024 * 1024 * 16);
+	newOption("gr.frameVertexSize", 1024 * 1024 * 2);
+	newOption("gr.frameTransferSize", 1024 * 1024 * 16);
 
 	//
 	// Resource

+ 25 - 62
src/gr/gl/CommandBuffer.cpp

@@ -313,27 +313,6 @@ void CommandBuffer::dispatchCompute(
 		groupCountX, groupCountY, groupCountZ);
 }
 
-//==============================================================================
-void* CommandBuffer::allocateDynamicMemoryInternal(U32 size, BufferUsage usage,
-	DynamicBufferToken& token)
-{
-	// Will be used in a thread safe way
-	GlState& state =
-		getManager().getImplementation().getRenderingThread().getState();
-
-	void* data = state.allocateDynamicMemory(size, usage);
-	ANKI_ASSERT(data);
-
-	// Encode token
-	PtrSize offset =
-		static_cast<U8*>(data) - state.m_dynamicBuffers[usage].m_address;
-	ANKI_ASSERT(offset < MAX_U32 && size < MAX_U32);
-	token.m_offset = offset;
-	token.m_range = size;
-
-	return data;
-}
-
 //==============================================================================
 class OqBeginCommand final: public GlCommand
 {
@@ -385,42 +364,35 @@ public:
 	TexturePtr m_handle;
 	U32 m_mipmap;
 	U32 m_slice;
-	PtrSize m_dataSize;
-	void* m_data;
-	CommandBufferAllocator<U8> m_alloc; ///< Alloc that was used for m_data.
+	DynamicBufferToken m_token;
 
 	TexUploadCommand(const TexturePtr& handle, U32 mipmap, U32 slice,
-		PtrSize dataSize, void* data, const CommandBufferAllocator<U8>& alloc)
+		const DynamicBufferToken& token)
 		: m_handle(handle)
 		, m_mipmap(mipmap)
 		, m_slice(slice)
-		, m_dataSize(dataSize)
-		, m_data(data)
-		, m_alloc(alloc)
+		, m_token(token)
 	{}
 
-	Error operator()(GlState&)
+	Error operator()(GlState& state)
 	{
-		m_handle->getImplementation().write(
-			m_mipmap, m_slice, m_data, m_dataSize);
+		U8* data =
+			state.m_dynamicBuffers[BufferUsage::TRANSFER].m_address
+			+ m_token.m_offset;
 
-		// Cleanup to avoid warnings
-		m_alloc.deallocate(m_data, 1);
+		m_handle->getImplementation().write(
+			m_mipmap, m_slice, data, m_token.m_range);
 
 		return ErrorCode::NONE;
 	}
 };
 
-void CommandBuffer::textureUploadInternal(TexturePtr tex, U32 mipmap, U32 slice,
-	PtrSize dataSize, void*& data)
+void CommandBuffer::textureUpload(TexturePtr tex, U32 mipmap, U32 slice,
+	const DynamicBufferToken& token)
 {
-	ANKI_ASSERT(dataSize > 0);
-
-	// Allocate memory to write
-	data = m_impl->getInternalAllocator().allocate(dataSize);
+	ANKI_ASSERT(token.m_range > 0);
 
-	m_impl->pushBackNewCommand<TexUploadCommand>(
-		tex, mipmap, slice, dataSize, data, m_impl->getInternalAllocator());
+	m_impl->pushBackNewCommand<TexUploadCommand>(tex, mipmap, slice, token);
 }
 
 //==============================================================================
@@ -429,40 +401,31 @@ class BuffWriteCommand final: public GlCommand
 public:
 	BufferPtr m_handle;
 	PtrSize m_offset;
-	PtrSize m_range;
-	void* m_data;
-	CommandBufferAllocator<U8> m_alloc;
+	DynamicBufferToken m_token;
 
-	BuffWriteCommand(const BufferPtr& handle, PtrSize offset, PtrSize range,
-		void* data, const CommandBufferAllocator<U8>& alloc)
+	BuffWriteCommand(const BufferPtr& handle, PtrSize offset,
+		const DynamicBufferToken& token)
 		: m_handle(handle)
 		, m_offset(offset)
-		, m_range(range)
-		, m_data(data)
-		, m_alloc(alloc)
+		, m_token(token)
 	{}
 
-	Error operator()(GlState&)
+	Error operator()(GlState& state)
 	{
-		m_handle->getImplementation().write(m_data, m_offset, m_range);
+		U8* data =
+			state.m_dynamicBuffers[BufferUsage::TRANSFER].m_address
+			+ m_token.m_offset;
 
-		// Cleanup to avoid warnings
-		m_alloc.deallocate(m_data, 1);
+		m_handle->getImplementation().write(data, m_offset, m_token.m_range);
 
 		return ErrorCode::NONE;
 	}
 };
 
-void CommandBuffer::writeBufferInternal(BufferPtr buff, PtrSize offset,
-	PtrSize range, void*& data)
+void CommandBuffer::writeBuffer(BufferPtr buff, PtrSize offset,
+	const DynamicBufferToken& token)
 {
-	ANKI_ASSERT(range > 0);
-
-	// Allocate memory to write
-	data = m_impl->getInternalAllocator().allocate(range);
-
-	m_impl->pushBackNewCommand<BuffWriteCommand>(
-		buff, offset, range, data, m_impl->getInternalAllocator());
+	m_impl->pushBackNewCommand<BuffWriteCommand>(buff, offset, token);
 }
 
 //==============================================================================

+ 43 - 14
src/gr/gl/GlState.cpp

@@ -8,6 +8,7 @@
 #include <anki/gr/GrManager.h>
 #include <anki/util/Logger.h>
 #include <anki/core/Counters.h>
+#include <anki/misc/ConfigSet.h>
 #include <algorithm>
 #include <cstring>
 
@@ -80,7 +81,23 @@ void oglMessagesCallback(GLenum source,
 #endif
 
 //==============================================================================
-void GlState::init()
+void GlState::init0(const ConfigSet& config)
+{
+	m_dynamicBuffers[BufferUsage::UNIFORM].m_size =
+		config.getNumber("gr.frameUniformsSize");
+
+	m_dynamicBuffers[BufferUsage::STORAGE].m_size =
+		config.getNumber("gr.frameStorageSize");
+
+	m_dynamicBuffers[BufferUsage::VERTEX].m_size =
+		config.getNumber("gr.frameVertexSize");
+
+	m_dynamicBuffers[BufferUsage::TRANSFER].m_size =
+		config.getNumber("gr.frameTransferSize");
+}
+
+//==============================================================================
+void GlState::init1()
 {
 	// GL version
 	GLint major, minor;
@@ -140,34 +157,44 @@ void GlState::init()
 	// Init ring buffers
 	GLint64 blockAlignment;
 	glGetInteger64v(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &blockAlignment);
-	initDynamicBuffer(GL_UNIFORM_BUFFER, blockAlignment,
-		GR_DYNAMIC_UNIFORMS_SIZE, MAX_UNIFORM_BLOCK_SIZE, BufferUsage::UNIFORM);
+	initDynamicBuffer(GL_UNIFORM_BUFFER, blockAlignment, MAX_UNIFORM_BLOCK_SIZE,
+		BufferUsage::UNIFORM);
 
 	glGetInteger64v(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, &blockAlignment);
 	initDynamicBuffer(GL_SHADER_STORAGE_BUFFER, blockAlignment,
-		GR_DYNAMIC_STORAGE_SIZE, MAX_STORAGE_BLOCK_SIZE, BufferUsage::STORAGE);
+		MAX_STORAGE_BLOCK_SIZE, BufferUsage::STORAGE);
+
+	initDynamicBuffer(GL_ARRAY_BUFFER, 8, MAX_U32, BufferUsage::VERTEX);
 
-	initDynamicBuffer(GL_ARRAY_BUFFER, 8, GR_DYNAMIC_VERTEX_SIZE,
-		MAX_U32, BufferUsage::VERTEX);
+	{
+		m_transferBuffer.create(m_manager->getAllocator(),
+			m_dynamicBuffers[BufferUsage::TRANSFER].m_size);
+
+		auto& buff = m_dynamicBuffers[BufferUsage::TRANSFER];
+		buff.m_address = &m_transferBuffer[0];
+		buff.m_alignment = 8;
+		buff.m_maxAllocationSize = MAX_U32;
+	}
 }
 
 //==============================================================================
-void GlState::initDynamicBuffer(GLenum target, U32 alignment, PtrSize size,
+void GlState::initDynamicBuffer(GLenum target, U32 alignment,
 	U32 maxAllocationSize, BufferUsage usage)
 {
 	DynamicBuffer& buff = m_dynamicBuffers[usage];
+	ANKI_ASSERT(buff.m_size > 0);
 
 	const U FLAGS = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT;
 
-	alignRoundUp(alignment, size);
+	alignRoundUp(alignment, buff.m_size);
 
 	glGenBuffers(1, &buff.m_name);
 
 	glBindBuffer(target, buff.m_name);
-	glBufferStorage(target, size, nullptr, FLAGS);
+	glBufferStorage(target, buff.m_size, nullptr, FLAGS);
 
-	buff.m_address = static_cast<U8*>(glMapBufferRange(target, 0, size, FLAGS));
-	buff.m_size = size;
+	buff.m_address = static_cast<U8*>(
+		glMapBufferRange(target, 0, buff.m_size, FLAGS));
 	buff.m_alignment = alignment;
 	buff.m_maxAllocationSize = maxAllocationSize;
 }
@@ -180,13 +207,14 @@ void GlState::checkDynamicMemoryConsumption()
 	{
 		DynamicBuffer& buff = m_dynamicBuffers[usage];
 
-		if(buff.m_name)
+		if(buff.m_address)
 		{
 			auto bytesUsed = buff.m_bytesUsed.exchange(0);
 			if(bytesUsed >= buff.m_size / MAX_FRAMES_IN_FLIGHT)
 			{
-				ANKI_LOGW("Using too much dynamic memory (type: %u). "
-					"Increase the limit", U(usage));
+				ANKI_LOGW("Using too much dynamic memory (mem_type: %u, "
+					"mem_used: %u). Increase the limit", U(usage),
+					U(bytesUsed));
 			}
 
 			// Increase the counters
@@ -217,6 +245,7 @@ void GlState::destroy()
 	}
 
 	glDeleteVertexArrays(1, &m_defaultVao);
+	m_transferBuffer.destroy(m_manager->getAllocator());
 }
 
 } // end namespace anki

+ 20 - 0
src/gr/gl/GrManager.cpp

@@ -40,4 +40,24 @@ void GrManager::swapBuffers()
 	m_impl->getRenderingThread().swapBuffers();
 }
 
+//==============================================================================
+void* GrManager::allocateFrameHostVisibleMemory(PtrSize size, BufferUsage usage,
+	DynamicBufferToken& token)
+{
+	// Will be used in a thread safe way
+	GlState& state = m_impl->getRenderingThread().getState();
+
+	void* data = state.allocateDynamicMemory(size, usage, token);
+	ANKI_ASSERT(data);
+
+	// Encode token
+	PtrSize offset =
+		static_cast<U8*>(data) - state.m_dynamicBuffers[usage].m_address;
+	ANKI_ASSERT(offset < MAX_U32 && size < MAX_U32);
+	token.m_offset = offset;
+	token.m_range = size;
+
+	return data;
+}
+
 } // end namespace anki

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

@@ -36,7 +36,8 @@ void GrManagerImpl::create(GrManagerInitializer& init)
 		m_manager->getAllocator().newInstance<RenderingThread>(m_manager);
 
 	// Start it
-	m_thread->start(init.m_interface, init.m_registerDebugMessages);
+	m_thread->start(init.m_interface, init.m_registerDebugMessages,
+		*init.m_config);
 	m_thread->syncClientServer();
 }
 

+ 4 - 2
src/gr/gl/RenderingThread.cpp

@@ -133,7 +133,7 @@ void RenderingThread::finishCommandBuffer(CommandBufferPtr commands)
 
 //==============================================================================
 void RenderingThread::start(WeakPtr<GrManagerInterface> interface,
-	Bool registerMessages)
+	Bool registerMessages, const ConfigSet& config)
 {
 	ANKI_ASSERT(m_tail == 0 && m_head == 0);
 	ANKI_ASSERT(interface);
@@ -146,6 +146,8 @@ void RenderingThread::start(WeakPtr<GrManagerInterface> interface,
 	m_swapBuffersCommands->getImplementation().
 		pushBackNewCommand<SwapBuffersCommand>(this);
 
+	m_state.init0(config);
+
 #if !ANKI_DISABLE_GL_RENDERING_THREAD
 	// Start thread
 	m_thread.start(this, threadCallback);
@@ -195,7 +197,7 @@ void RenderingThread::prepare()
 	m_serverThreadId = Thread::getCurrentThreadId();
 
 	// Init state
-	m_state.init();
+	m_state.init1();
 }
 
 //==============================================================================

+ 4 - 2
src/renderer/Bloom.cpp

@@ -203,8 +203,10 @@ void Bloom::run(CommandBufferPtr& cmdb)
 //==============================================================================
 void Bloom::updateDefaultBlock(CommandBufferPtr& cmdb)
 {
-	void* uniforms = nullptr;
-	cmdb->writeBuffer(m_commonBuff, 0, sizeof(Vec4), uniforms);
+	DynamicBufferToken token;
+	void* uniforms = getGrManager().allocateFrameHostVisibleMemory(
+		sizeof(Vec4), BufferUsage::TRANSFER, token);
+	cmdb->writeBuffer(m_commonBuff, 0, token);
 	*static_cast<Vec4*>(uniforms) = Vec4(m_threshold, m_scale, 0.0, 0.0);
 }
 

+ 5 - 2
src/renderer/DebugDrawer.cpp

@@ -32,6 +32,7 @@ DebugDrawer::~DebugDrawer()
 //==============================================================================
 Error DebugDrawer::create(Renderer* r)
 {
+	m_r = r;
 	GrManager& gr = r->getGrManager();
 
 	ANKI_CHECK(
@@ -165,9 +166,11 @@ Error DebugDrawer::flushInternal(PrimitiveTopology topology)
 
 	U size = sizeof(Vertex) * clientVerts;
 
-	void* data = nullptr;
-	m_cmdb->writeBuffer(m_vertBuff, 0, size, data);
+	DynamicBufferToken token;
+	void* data = m_r->getGrManager().allocateFrameHostVisibleMemory(
+		size, BufferUsage::TRANSFER, token);
 	memcpy(data, vertBuff, size);
+	m_cmdb->writeBuffer(m_vertBuff, 0, token);
 
 	if(m_depthTestEnabled)
 	{

+ 3 - 2
src/renderer/Drawer.cpp

@@ -247,9 +247,10 @@ void RenderableDrawer::setupUniforms(RenderContext& ctx,
 	ctx.m_variant = &variant;
 
 	// Get some memory for uniforms
-	U8* uniforms = ctx.m_cmdb->allocateDynamicMemory<U8>(
+	U8* uniforms = static_cast<U8*>(
+		m_r->getGrManager().allocateFrameHostVisibleMemory(
 		variant.getDefaultBlockSize(), BufferUsage::UNIFORM,
-		ctx.m_dynBufferInfo.m_uniformBuffers[0]);
+		ctx.m_dynBufferInfo.m_uniformBuffers[0]));
 
 	// Call the visitor
 	SetupRenderableVariableVisitor visitor;

+ 1 - 1
src/renderer/Ir.cpp

@@ -103,7 +103,7 @@ Error Ir::run(CommandBufferPtr cmdb)
 	const VisibleNode* end = visRez.getReflectionProbesEnd();
 	U probCount = end - it;
 
-	U8* data = cmdb->allocateDynamicMemory<U8>(
+	void* data = getGrManager().allocateFrameHostVisibleMemory(
 		sizeof(ShaderReflectionProbe) * m_cubemapArrSize + sizeof(UVec4),
 		BufferUsage::STORAGE, m_probesToken);
 

+ 20 - 12
src/renderer/Is.cpp

@@ -408,28 +408,32 @@ Error Is::lightPass(CommandBufferPtr& cmdb)
 
 	if(visiblePointLightsCount)
 	{
-		ShaderPointLight* data = cmdb->allocateDynamicMemory<ShaderPointLight>(
-			visiblePointLightsCount, BufferUsage::STORAGE, m_pLightsToken);
+		ShaderPointLight* data = static_cast<ShaderPointLight*>(
+			getGrManager().allocateFrameHostVisibleMemory(
+			sizeof(ShaderPointLight) * visiblePointLightsCount,
+			BufferUsage::STORAGE, m_pLightsToken));
 
 		taskData.m_pointLights = SArray<ShaderPointLight>(data,
 			visiblePointLightsCount);
 	}
 	else
 	{
-		m_pLightsToken.invalidate();
+		m_pLightsToken.markUnused();
 	}
 
 	if(visibleSpotLightsCount)
 	{
-		ShaderSpotLight* data = cmdb->allocateDynamicMemory<ShaderSpotLight>(
-			visibleSpotLightsCount, BufferUsage::STORAGE, m_sLightsToken);
+		ShaderSpotLight* data = static_cast<ShaderSpotLight*>(
+			getGrManager().allocateFrameHostVisibleMemory(
+			sizeof(ShaderSpotLight) * visibleSpotLightsCount,
+			BufferUsage::STORAGE, m_sLightsToken));
 
 		taskData.m_spotLights = SArray<ShaderSpotLight>(data,
 			visibleSpotLightsCount);
 	}
 	else
 	{
-		m_sLightsToken.invalidate();
+		m_sLightsToken.markUnused();
 	}
 
 	taskData.m_lightsBegin = vi.getLightsBegin();
@@ -438,14 +442,17 @@ Error Is::lightPass(CommandBufferPtr& cmdb)
 	taskData.m_is = this;
 
 	// Get mem for clusters
-	ShaderCluster* data = cmdb->allocateDynamicMemory<ShaderCluster>(
-		clusterCount, BufferUsage::STORAGE, m_clustersToken);
+	ShaderCluster* data = static_cast<ShaderCluster*>(
+		getGrManager().allocateFrameHostVisibleMemory(
+		sizeof(ShaderCluster) * clusterCount, BufferUsage::STORAGE,
+		m_clustersToken));
 
 	taskData.m_clusters = SArray<ShaderCluster>(data, clusterCount);
 
 	// Allocate light IDs
-	Lid* data2 = cmdb->allocateDynamicMemory<Lid>(m_maxLightIds,
-		BufferUsage::STORAGE, m_lightIdsToken);
+	Lid* data2 = static_cast<Lid*>(
+		getGrManager().allocateFrameHostVisibleMemory(
+		m_maxLightIds * sizeof(Lid), BufferUsage::STORAGE, m_lightIdsToken));
 
 	taskData.m_lightIds = SArray<Lid>(data2, m_maxLightIds);
 
@@ -764,8 +771,9 @@ Error Is::run(CommandBufferPtr& cmdb)
 void Is::updateCommonBlock(CommandBufferPtr& cmdb, const FrustumComponent& fr)
 {
 	ShaderCommonUniforms* blk =
-		cmdb->allocateDynamicMemory<ShaderCommonUniforms>(1,
-		BufferUsage::STORAGE, m_commonVarsToken);
+		static_cast<ShaderCommonUniforms*>(
+		getGrManager().allocateFrameHostVisibleMemory(
+		sizeof(ShaderCommonUniforms), BufferUsage::STORAGE, m_commonVarsToken));
 
 	// Start writing
 	blk->m_projectionParams = m_r->getProjectionParameters();

+ 9 - 6
src/renderer/Lf.cpp

@@ -167,14 +167,16 @@ void Lf::runOcclusionTests(CommandBufferPtr& cmdb)
 	{
 		// Setup MVP UBO
 		DynamicBufferToken token;
-		Mat4* mvp = cmdb->allocateDynamicMemory<Mat4>(1, BufferUsage::UNIFORM,
-			token);
+		Mat4* mvp = static_cast<Mat4*>(
+			getGrManager().allocateFrameHostVisibleMemory(sizeof(Mat4),
+			BufferUsage::UNIFORM, token));
 		*mvp = camFr.getViewProjectionMatrix();
 
 		// Alloc dyn mem
 		DynamicBufferToken token2;
-		Vec3* positions = cmdb->allocateDynamicMemory<Vec3>(totalCount,
-			BufferUsage::VERTEX, token2);
+		Vec3* positions = static_cast<Vec3*>(
+			getGrManager().allocateFrameHostVisibleMemory(
+			sizeof(Vec3) * totalCount, BufferUsage::VERTEX, token2));
 		const Vec3* initialPositions = positions;
 
 		// Setup state
@@ -246,8 +248,9 @@ void Lf::run(CommandBufferPtr& cmdb)
 
 			// Get uniform memory
 			DynamicBufferToken token;
-			Sprite* tmpSprites = cmdb->allocateDynamicMemory<Sprite>(
-				spritesCount, BufferUsage::UNIFORM, token);
+			Sprite* tmpSprites = static_cast<Sprite*>(
+				getGrManager().allocateFrameHostVisibleMemory(
+				spritesCount * sizeof(Sprite), BufferUsage::UNIFORM, token));
 			SArray<Sprite> sprites(tmpSprites, spritesCount);
 
 			// misc

+ 5 - 2
src/renderer/Pps.cpp

@@ -215,8 +215,11 @@ void Pps::run(CommandBufferPtr& cmdb)
 	if(m_uniformsDirty)
 	{
 		m_uniformsDirty = false;
-		Uniforms* unis = nullptr;
-		cmdb->writeBuffer(m_uniformsBuff, 0, sizeof(*unis), unis);
+		DynamicBufferToken token;
+		Uniforms* unis = static_cast<Uniforms*>(
+			getGrManager().allocateFrameHostVisibleMemory(
+			sizeof(*unis), BufferUsage::TRANSFER, token));
+		cmdb->writeBuffer(m_uniformsBuff, 0, token);
 		unis->m_fogColorFogFactor = Vec4(m_fogColor, m_fogFactor);
 
 		const FrustumComponent& frc = m_r->getActiveFrustumComponent();

+ 11 - 6
src/renderer/Ssao.cpp

@@ -137,11 +137,14 @@ Error Ssao::initInternal(const ConfigSet& config)
 
 	PtrSize noiseSize = NOISE_TEX_SIZE * NOISE_TEX_SIZE * sizeof(Vec3);
 
-	Vec3* noise = nullptr;
-	cmdb->textureUpload(m_noiseTex, 0, 0, noiseSize, noise);
+	DynamicBufferToken token;
+	Vec3* noise = static_cast<Vec3*>(
+		getGrManager().allocateFrameHostVisibleMemory(noiseSize,
+		BufferUsage::TRANSFER, token));
 
 	genNoise(noise, noise + NOISE_TEX_SIZE * NOISE_TEX_SIZE);
 
+	cmdb->textureUpload(m_noiseTex, 0, 0, token);
 	cmdb->flush();
 
 	//
@@ -277,14 +280,16 @@ void Ssao::run(CommandBufferPtr& cmdb)
 		|| m_commonUboUpdateTimestamp < camFr.getTimestamp()
 		|| m_commonUboUpdateTimestamp == 1)
 	{
-		ShaderCommonUniforms* blk;
-		void* data;
-		cmdb->writeBuffer(m_uniformsBuff, 0, sizeof(*blk), data);
-		blk = static_cast<ShaderCommonUniforms*>(data);
+		DynamicBufferToken token;
+		ShaderCommonUniforms* blk = static_cast<ShaderCommonUniforms*>(
+			getGrManager().allocateFrameHostVisibleMemory(
+			sizeof(ShaderCommonUniforms), BufferUsage::TRANSFER, token));
 
 		blk->m_projectionParams = m_r->getProjectionParameters();
 		blk->m_projectionMatrix = camFr.getProjectionMatrix();
 
+		cmdb->writeBuffer(m_uniformsBuff, 0, token);
+
 		m_commonUboUpdateTimestamp = getGlobalTimestamp();
 	}
 

+ 4 - 2
src/renderer/Tm.cpp

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

+ 7 - 3
src/resource/Mesh.cpp

@@ -68,16 +68,20 @@ void Mesh::createBuffers(const MeshLoader& loader)
 	m_vertBuff = gr.newInstance<Buffer>(loader.getVertexDataSize(),
 		BufferUsageBit::VERTEX, BufferAccessBit::CLIENT_WRITE);
 
-	void* data = nullptr;
-	cmdb->writeBuffer(m_vertBuff, 0, loader.getVertexDataSize(), data);
+	DynamicBufferToken token;
+	void* data = gr.allocateFrameHostVisibleMemory(loader.getVertexDataSize(),
+		BufferUsage::TRANSFER, token);
 	memcpy(data, loader.getVertexData(), loader.getVertexDataSize());
+	cmdb->writeBuffer(m_vertBuff, 0, token);
 
 	// Create index buffer
 	m_indicesBuff = gr.newInstance<Buffer>(loader.getIndexDataSize(),
 		BufferUsageBit::INDEX, BufferAccessBit::CLIENT_WRITE);
 
-	cmdb->writeBuffer(m_indicesBuff, 0, loader.getIndexDataSize(), data);
+	data = gr.allocateFrameHostVisibleMemory(loader.getIndexDataSize(),
+		BufferUsage::TRANSFER, token);
 	memcpy(data, loader.getIndexData(), loader.getIndexDataSize());
+	cmdb->writeBuffer(m_indicesBuff, 0, token);
 
 	cmdb->flush();
 }

+ 5 - 4
src/resource/TextureResource.cpp

@@ -144,11 +144,12 @@ Error TextureResource::load(const ResourceFilename& filename)
 		{
 			const auto& surf = img->getSurface(level, layer);
 
-			void* data;
-			cmdb->textureUpload(
-				m_tex, level, layer, surf.m_data.getSize(), data);
-
+			DynamicBufferToken token;
+			void* data = gr.allocateFrameHostVisibleMemory(
+				surf.m_data.getSize(), BufferUsage::TRANSFER, token);
 			memcpy(data, &surf.m_data[0], surf.m_data.getSize());
+
+			cmdb->textureUpload(m_tex, level, layer, token);
 		}
 	}
 

+ 4 - 2
src/ui/UiInterfaceImpl.cpp

@@ -212,9 +212,11 @@ Error UiInterfaceImpl::createR8Image(const SArray<U8>& data, const UVec2& size,
 
 	// Load data
 	CommandBufferPtr cmdb = m_gr->newInstance<CommandBuffer>();
-	void* loadData = nullptr;
-	cmdb->textureUpload(tex, 0, 0, data.getSize(), loadData);
+	DynamicBufferToken token;
+	void* loadData = m_gr->allocateFrameHostVisibleMemory(data.getSize(),
+		BufferUsage::TRANSFER, token);
 	memcpy(loadData, &data[0], data.getSize());
+	cmdb->textureUpload(tex, 0, 0, token);
 
 	// Gen mips
 	cmdb->generateMipmaps(tex);

+ 2 - 2
testapp/Main.cpp

@@ -89,8 +89,8 @@ Error init()
 #if !PLAYER
 	cam->getComponent<MoveComponent>().
 		setLocalTransform(Transform(
-		//Vec4(147.392776, -10.132728, 16.607138, 0.0),
-		Vec4(0.0, 10, 0, 0),
+		Vec4(147.392776, -10.132728, 16.607138, 0.0),
+		//Vec4(0.0, 10, 0, 0),
 		Mat3x4(Euler(toRad(0.0), toRad(90.0), toRad(0.0))),
 		1.0));
 #endif