Browse Source

Move staging memory out of GR

Panagiotis Christopoulos Charitos 9 years ago
parent
commit
1c74d88894
56 changed files with 637 additions and 810 deletions
  1. 4 5
      sandbox/config.xml
  2. 17 2
      src/anki/core/App.cpp
  3. 2 0
      src/anki/core/App.h
  4. 1 1
      src/anki/core/CMakeLists.txt
  5. 6 13
      src/anki/core/Config.cpp
  6. 123 0
      src/anki/core/StagingGpuMemoryManager.cpp
  7. 102 0
      src/anki/core/StagingGpuMemoryManager.h
  8. 3 3
      src/anki/core/Trace.cpp
  9. 2 2
      src/anki/core/Trace.h
  10. 29 44
      src/anki/gr/CommandBuffer.h
  11. 0 38
      src/anki/gr/Common.h
  12. 8 11
      src/anki/gr/GrManager.h
  13. 8 7
      src/anki/gr/gl/BufferImpl.h
  14. 72 191
      src/anki/gr/gl/CommandBuffer.cpp
  15. 2 2
      src/anki/gr/gl/FramebufferImpl.cpp
  16. 13 0
      src/anki/gr/gl/GlState.cpp
  17. 5 0
      src/anki/gr/gl/GlState.h
  18. 17 20
      src/anki/gr/gl/GrManager.cpp
  19. 0 5
      src/anki/gr/gl/GrManagerImpl.cpp
  20. 0 14
      src/anki/gr/gl/GrManagerImpl.h
  21. 0 8
      src/anki/gr/gl/RenderingThread.cpp
  22. 1 0
      src/anki/gr/gl/ShaderProgram.cpp
  23. 5 35
      src/anki/gr/gl/StateTracker.h
  24. 0 153
      src/anki/gr/gl/TransientMemoryManager.cpp
  25. 0 85
      src/anki/gr/gl/TransientMemoryManager.h
  26. 2 5
      src/anki/renderer/Bloom.cpp
  27. 1 0
      src/anki/renderer/Common.h
  28. 7 6
      src/anki/renderer/Drawer.cpp
  29. 6 10
      src/anki/renderer/Fs.cpp
  30. 1 5
      src/anki/renderer/FsUpscale.cpp
  31. 11 31
      src/anki/renderer/Ir.cpp
  32. 10 10
      src/anki/renderer/Is.cpp
  33. 9 14
      src/anki/renderer/Lf.cpp
  34. 20 20
      src/anki/renderer/LightBin.cpp
  35. 8 8
      src/anki/renderer/LightBin.h
  36. 3 1
      src/anki/renderer/MainRenderer.cpp
  37. 2 0
      src/anki/renderer/MainRenderer.h
  38. 1 1
      src/anki/renderer/Pps.cpp
  39. 2 0
      src/anki/renderer/Renderer.cpp
  40. 19 10
      src/anki/renderer/Renderer.h
  41. 6 0
      src/anki/renderer/RenderingPass.cpp
  42. 40 0
      src/anki/renderer/RenderingPass.h
  43. 12 2
      src/anki/renderer/Smaa.cpp
  44. 8 10
      src/anki/renderer/Ssao.cpp
  45. 6 4
      src/anki/renderer/Tm.cpp
  46. 9 14
      src/anki/renderer/Volumetric.cpp
  47. 9 8
      src/anki/resource/Mesh.cpp
  48. 1 0
      src/anki/resource/ResourceManager.cpp
  49. 9 0
      src/anki/resource/ResourceManager.h
  50. 7 5
      src/anki/resource/TextureResource.cpp
  51. 2 2
      src/anki/scene/ParticleEmitter.cpp
  52. 1 1
      src/anki/scene/ParticleEmitter.h
  53. 3 2
      src/anki/scene/RenderComponent.h
  54. 0 1
      src/anki/scene/SceneGraph.cpp
  55. 0 1
      src/anki/scene/Sector.cpp
  56. 2 0
      src/anki/ui/UiInterfaceImpl.cpp

+ 4 - 5
sandbox/config.xml

@@ -39,11 +39,10 @@
 	<tessellation>1</tessellation>
 	<clusterSizeZ>32</clusterSizeZ>
 	<imageReflectionMaxDistance>30</imageReflectionMaxDistance>
-	<gr.uniformPerFrameMemorySize>16777216</gr.uniformPerFrameMemorySize>
-	<gr.storagePerFrameMemorySize>16777216</gr.storagePerFrameMemorySize>
-	<gr.transferPerFrameMemorySize>67108864</gr.transferPerFrameMemorySize>
-	<gr.vertexPerFrameMemorySize>16777216</gr.vertexPerFrameMemorySize>
-	<gr.transferPersistentMemorySize>67108864</gr.transferPersistentMemorySize>
+	<core.uniformPerFrameMemorySize>16777216</core.uniformPerFrameMemorySize>
+	<core.storagePerFrameMemorySize>16777216</core.storagePerFrameMemorySize>
+	<core.transferPerFrameMemorySize>67108864</core.transferPerFrameMemorySize>
+	<core.vertexPerFrameMemorySize>16777216</core.vertexPerFrameMemorySize>
 	<maxTextureSize>1048576</maxTextureSize>
 	<textureAnisotropy>8</textureAnisotropy>
 	<dataPaths>assets:.</dataPaths>

+ 17 - 2
src/anki/core/App.cpp

@@ -22,6 +22,7 @@
 #include <anki/script/ScriptManager.h>
 #include <anki/resource/ResourceFilesystem.h>
 #include <anki/resource/AsyncLoader.h>
+#include <anki/core/StagingGpuMemoryManager.h>
 
 #if ANKI_OS == ANKI_OS_ANDROID
 #include <android_native_app_glue.h>
@@ -84,6 +85,12 @@ void App::cleanup()
 		m_physics = nullptr;
 	}
 
+	if(m_stagingMem)
+	{
+		m_heapAlloc.deleteInstance(m_stagingMem);
+		m_stagingMem = nullptr;
+	}
+
 	if(m_gr)
 	{
 		m_heapAlloc.deleteInstance(m_gr);
@@ -216,6 +223,12 @@ Error App::initInternal(const ConfigSet& config_, AllocAlignedCallback allocCb,
 
 	ANKI_CHECK(m_gr->init(grInit));
 
+	//
+	// Staging mem
+	//
+	m_stagingMem = m_heapAlloc.newInstance<StagingGpuMemoryManager>();
+	ANKI_CHECK(m_stagingMem->init(m_gr, config));
+
 	//
 	// Physics
 	//
@@ -234,6 +247,7 @@ Error App::initInternal(const ConfigSet& config_, AllocAlignedCallback allocCb,
 	//
 	ResourceManagerInitInfo rinit;
 	rinit.m_gr = m_gr;
+	rinit.m_stagingMem = m_stagingMem;
 	rinit.m_physics = m_physics;
 	rinit.m_resourceFs = m_resourceFs;
 	rinit.m_config = &config;
@@ -255,8 +269,8 @@ Error App::initInternal(const ConfigSet& config_, AllocAlignedCallback allocCb,
 
 	m_renderer = m_heapAlloc.newInstance<MainRenderer>();
 
-	ANKI_CHECK(
-		m_renderer->create(m_threadpool, m_resources, m_gr, m_allocCb, m_allocCbData, config, &m_globalTimestamp));
+	ANKI_CHECK(m_renderer->create(
+		m_threadpool, m_resources, m_gr, m_stagingMem, m_allocCb, m_allocCbData, config, &m_globalTimestamp));
 
 	m_resources->_setShadersPrependedSource(m_renderer->getMaterialShaderSource().toCString());
 
@@ -361,6 +375,7 @@ Error App::mainLoop()
 		m_resources->getAsyncLoader().pause();
 
 		m_gr->swapBuffers();
+		m_stagingMem->endFrame();
 
 		// Update the trace info with some async loader stats
 		U64 asyncTaskCount = m_resources->getAsyncLoader().getCompletedTaskCount();

+ 2 - 0
src/anki/core/App.h

@@ -33,6 +33,7 @@ class SceneGraph;
 class ScriptManager;
 class ResourceManager;
 class ResourceFilesystem;
+class StagingGpuMemoryManager;
 
 /// The core class of the engine.
 class App
@@ -148,6 +149,7 @@ private:
 	NativeWindow* m_window = nullptr;
 	Input* m_input = nullptr;
 	GrManager* m_gr = nullptr;
+	StagingGpuMemoryManager* m_stagingMem = nullptr;
 	PhysicsWorld* m_physics = nullptr;
 	ResourceFilesystem* m_resourceFs = nullptr;
 	ResourceManager* m_resources = nullptr;

+ 1 - 1
src/anki/core/CMakeLists.txt

@@ -1,4 +1,4 @@
-set(ANKI_CORE_SOURCES App.cpp StdinListener.cpp Config.cpp Trace.cpp)
+set(ANKI_CORE_SOURCES App.cpp StdinListener.cpp Config.cpp Trace.cpp StagingGpuMemoryManager.cpp)
 
 if(SDL)
 	set(ANKI_CORE_SOURCES ${ANKI_CORE_SOURCES} NativeWindowSdl.cpp)

+ 6 - 13
src/anki/core/Config.cpp

@@ -66,30 +66,23 @@ Config::Config()
 	newOption("clusterSizeZ", 32);
 	newOption("imageReflectionMaxDistance", 30.0);
 
-	//
-	// GR
-	//
-	newOption("gr.uniformPerFrameMemorySize", 1024 * 1024 * 16);
-	newOption("gr.storagePerFrameMemorySize", 1024 * 1024 * 16);
-	newOption("gr.vertexPerFrameMemorySize", 1024 * 1024 * 10);
-	newOption("gr.transferPerFrameMemorySize", 1024 * 1024 * 128);
-	newOption("gr.transferPersistentMemorySize", (4096 / 4) * (4096 / 4) * 16 * 4);
-
-	//
 	// Resource
-	//
 	newOption("maxTextureSize", 1024 * 1024);
 	newOption("textureAnisotropy", 8);
 	newOption("dataPaths", ".");
 
-	//
 	// Window
-	//
 	newOption("glmajor", 4);
 	newOption("glminor", 5);
 	newOption("fullscreenDesktopResolution", false);
 	newOption("debugContext", false);
 	newOption("vsync", false);
+
+	// Core
+	newOption("core.uniformPerFrameMemorySize", 1024 * 1024 * 16);
+	newOption("core.storagePerFrameMemorySize", 1024 * 1024 * 16);
+	newOption("core.vertexPerFrameMemorySize", 1024 * 1024 * 10);
+	newOption("core.transferPerFrameMemorySize", 1024 * 1024 * 128);
 }
 
 Config::~Config()

+ 123 - 0
src/anki/core/StagingGpuMemoryManager.cpp

@@ -0,0 +1,123 @@
+// Copyright (C) 2009-2016, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <anki/core/StagingGpuMemoryManager.h>
+#include <anki/misc/ConfigSet.h>
+#include <anki/gr/GrManager.h>
+#include <anki/core/Trace.h>
+
+namespace anki
+{
+
+StagingGpuMemoryManager::~StagingGpuMemoryManager()
+{
+	m_gr->finish();
+
+	for(auto& it : m_perFrameBuffers)
+	{
+		it.m_buff = {};
+	}
+}
+
+Error StagingGpuMemoryManager::init(GrManager* gr, const ConfigSet& cfg)
+{
+	m_gr = gr;
+
+	m_perFrameBuffers[StagingGpuMemoryType::UNIFORM].m_size = cfg.getNumber("core.uniformPerFrameMemorySize");
+	m_perFrameBuffers[StagingGpuMemoryType::STORAGE].m_size = cfg.getNumber("core.storagePerFrameMemorySize");
+	m_perFrameBuffers[StagingGpuMemoryType::VERTEX].m_size = cfg.getNumber("core.vertexPerFrameMemorySize");
+	m_perFrameBuffers[StagingGpuMemoryType::TRANSFER].m_size = cfg.getNumber("core.transferPerFrameMemorySize");
+
+	U32 alignment;
+	PtrSize maxSize;
+
+	gr->getUniformBufferInfo(alignment, maxSize);
+	initBuffer(StagingGpuMemoryType::UNIFORM, alignment, maxSize, BufferUsageBit::UNIFORM_ALL, *gr);
+
+	gr->getStorageBufferInfo(alignment, maxSize);
+	initBuffer(StagingGpuMemoryType::STORAGE, alignment, maxSize, BufferUsageBit::STORAGE_ALL, *gr);
+
+	initBuffer(StagingGpuMemoryType::VERTEX, 16, MAX_U32, BufferUsageBit::VERTEX, *gr);
+	initBuffer(StagingGpuMemoryType::TRANSFER,
+		16,
+		MAX_U32,
+		BufferUsageBit::BUFFER_UPLOAD_SOURCE | BufferUsageBit::TEXTURE_UPLOAD_SOURCE,
+		*gr);
+
+	return ErrorCode::NONE;
+}
+
+void StagingGpuMemoryManager::initBuffer(
+	StagingGpuMemoryType type, U32 alignment, PtrSize maxAllocSize, BufferUsageBit usage, GrManager& gr)
+{
+	auto& perframe = m_perFrameBuffers[type];
+
+	perframe.m_buff = gr.newInstance<Buffer>(perframe.m_size, usage, BufferMapAccessBit::WRITE);
+	perframe.m_alloc.init(perframe.m_size, alignment, maxAllocSize);
+	perframe.m_mappedMem = static_cast<U8*>(perframe.m_buff->map(0, perframe.m_size, BufferMapAccessBit::WRITE));
+}
+
+void* StagingGpuMemoryManager::allocatePerFrame(PtrSize size, StagingGpuMemoryType usage, StagingGpuMemoryToken& token)
+{
+	PerFrameBuffer& buff = m_perFrameBuffers[usage];
+	Error err = buff.m_alloc.allocate(size, token.m_offset);
+	if(err)
+	{
+		ANKI_LOGF("Out of staging GPU memory. Usage: %u", usage);
+	}
+
+	token.m_buffer = buff.m_buff;
+	token.m_range = size;
+	token.m_type = usage;
+
+	return buff.m_mappedMem + token.m_offset;
+}
+
+void* StagingGpuMemoryManager::tryAllocatePerFrame(
+	PtrSize size, StagingGpuMemoryType usage, StagingGpuMemoryToken& token)
+{
+	PerFrameBuffer& buff = m_perFrameBuffers[usage];
+	Error err = buff.m_alloc.allocate(size, token.m_offset);
+	if(!err)
+	{
+		token.m_buffer = buff.m_buff;
+		token.m_range = size;
+		token.m_type = usage;
+		return buff.m_mappedMem + token.m_offset;
+	}
+	else
+	{
+		token = {};
+		return nullptr;
+	}
+}
+
+void StagingGpuMemoryManager::endFrame()
+{
+	for(StagingGpuMemoryType usage = StagingGpuMemoryType::UNIFORM; usage < StagingGpuMemoryType::COUNT; ++usage)
+	{
+		PerFrameBuffer& buff = m_perFrameBuffers[usage];
+
+		if(buff.m_mappedMem)
+		{
+			// Increase the counters
+			switch(usage)
+			{
+			case StagingGpuMemoryType::UNIFORM:
+				ANKI_TRACE_INC_COUNTER(STAGING_UNIFORMS_SIZE, buff.m_alloc.getUnallocatedMemorySize());
+				break;
+			case StagingGpuMemoryType::STORAGE:
+				ANKI_TRACE_INC_COUNTER(STAGING_STORAGE_SIZE, buff.m_alloc.getUnallocatedMemorySize());
+				break;
+			default:
+				break;
+			}
+
+			buff.m_alloc.endFrame();
+		}
+	}
+}
+
+} // end namespace anki

+ 102 - 0
src/anki/core/StagingGpuMemoryManager.h

@@ -0,0 +1,102 @@
+// Copyright (C) 2009-2016, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <anki/gr/Buffer.h>
+#include <anki/gr/common/FrameGpuAllocator.h>
+
+namespace anki
+{
+
+// Forward
+class ConfigSet;
+
+/// @addtogroup core
+/// @{
+
+enum class StagingGpuMemoryType
+{
+	UNIFORM,
+	STORAGE,
+	VERTEX,
+	TRANSFER,
+	COUNT
+};
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(StagingGpuMemoryType, inline)
+
+/// Token that gets returned when requesting for memory to write to a resource.
+class StagingGpuMemoryToken
+{
+public:
+	BufferPtr m_buffer;
+	PtrSize m_offset = 0;
+	PtrSize m_range = 0;
+	StagingGpuMemoryType m_type = StagingGpuMemoryType::COUNT;
+
+	StagingGpuMemoryToken() = default;
+
+	~StagingGpuMemoryToken() = default;
+
+	operator Bool() const
+	{
+		return m_range != 0;
+	}
+
+	Bool operator==(const StagingGpuMemoryToken& b) const
+	{
+		return m_buffer == b.m_buffer && m_offset == b.m_offset && m_range == b.m_range && m_type == b.m_type;
+	}
+
+	void markUnused()
+	{
+		m_offset = m_range = MAX_U32;
+	}
+
+	Bool isUnused() const
+	{
+		return m_offset == MAX_U32 && m_range == MAX_U32;
+	}
+};
+
+/// Manages staging GPU memory.
+class StagingGpuMemoryManager : public NonCopyable
+{
+public:
+	StagingGpuMemoryManager() = default;
+
+	~StagingGpuMemoryManager();
+
+	ANKI_USE_RESULT Error init(GrManager* gr, const ConfigSet& cfg);
+
+	void endFrame();
+
+	/// Allocate staging memory for various operations. The memory will be reclaimed at the begining of the
+	/// N-(MAX_FRAMES_IN_FLIGHT-1) frame.
+	void* allocatePerFrame(PtrSize size, StagingGpuMemoryType usage, StagingGpuMemoryToken& token);
+
+	/// Allocate staging memory for various operations. The memory will be reclaimed at the begining of the
+	/// N-(MAX_FRAMES_IN_FLIGHT-1) frame.
+	void* tryAllocatePerFrame(PtrSize size, StagingGpuMemoryType usage, StagingGpuMemoryToken& token);
+
+private:
+	class PerFrameBuffer
+	{
+	public:
+		PtrSize m_size = 0;
+		BufferPtr m_buff;
+		U8* m_mappedMem = nullptr; ///< Cache it
+		FrameGpuAllocator m_alloc;
+	};
+
+	GrManager* m_gr = nullptr;
+	Array<PerFrameBuffer, U(StagingGpuMemoryType::COUNT)> m_perFrameBuffers;
+
+	void initBuffer(
+		StagingGpuMemoryType type, U32 alignment, PtrSize maxAllocSize, BufferUsageBit usage, GrManager& gr);
+};
+/// @}
+
+} // end namespace anki

+ 3 - 3
src/anki/core/Trace.cpp

@@ -41,8 +41,6 @@ static Array<const char*, U(TraceEventType::COUNT)> eventNames = {{"SCENE_UPDATE
 	"BARRIER_WAIT"}};
 
 static Array<const char*, U(TraceCounterType::COUNT)> counterNames = {{"GR_DRAWCALLS",
-	"GR_DYNAMIC_UNIFORMS_SIZE",
-	"GR_DYNAMIC_STORAGE_SIZE",
 	"GR_VERTICES",
 	"GL_PROGS_SKIPPED",
 	"VK_PIPELINES_CREATED",
@@ -55,7 +53,9 @@ static Array<const char*, U(TraceCounterType::COUNT)> counterNames = {{"GR_DRAWC
 	"RENDERER_MERGED_DRAWCALLS",
 	"RENDERER_REFLECTIONS",
 	"RESOURCE_ASYNC_TASKS",
-	"SCENE_NODES_UPDATED"}};
+	"SCENE_NODES_UPDATED",
+	"STAGING_UNIFORMS_SIZE",
+	"STAGING_STORAGE_SIZE"}};
 
 #define ANKI_TRACE_FILE_ERROR()                                                                                        \
 	if(err)                                                                                                            \

+ 2 - 2
src/anki/core/Trace.h

@@ -59,8 +59,6 @@ enum class TraceEventType
 enum class TraceCounterType
 {
 	GR_DRAWCALLS,
-	GR_DYNAMIC_UNIFORMS_SIZE,
-	GR_DYNAMIC_STORAGE_SIZE,
 	GR_VERTICES,
 	GL_PROGS_SKIPPED,
 	VK_PIPELINES_CREATED,
@@ -74,6 +72,8 @@ enum class TraceCounterType
 	RENDERER_REFLECTIONS,
 	RESOURCE_ASYNC_TASKS,
 	SCENE_NODES_UPDATED,
+	STAGING_UNIFORMS_SIZE,
+	STAGING_STORAGE_SIZE,
 
 	COUNT
 };

+ 29 - 44
src/anki/gr/CommandBuffer.h

@@ -144,18 +144,12 @@ public:
 	/// Bind vertex buffer.
 	void bindVertexBuffer(U32 binding, BufferPtr buff, PtrSize offset, PtrSize stride);
 
-	/// Bind transient vertex buffer.
-	void bindVertexBuffer(U32 binding, const TransientMemoryToken& token, PtrSize stride);
-
 	/// Setup a vertex attribute.
 	void setVertexAttribute(U32 location, U32 buffBinding, const PixelFormat& fmt, PtrSize relativeOffset);
 
 	/// Bind index buffer.
 	void bindIndexBuffer(BufferPtr buff, PtrSize offset, IndexType type);
 
-	/// Bind transient index buffer.
-	void bindIndexBuffer(const TransientMemoryToken& token, IndexType type);
-
 	/// Enable primitive restart.
 	void setPrimitiveRestart(Bool enable);
 
@@ -237,16 +231,22 @@ public:
 		DepthStencilAspectBit aspect = DepthStencilAspectBit::DEPTH);
 
 	/// Bind uniform buffer.
-	void bindUniformBuffer(U32 set, U32 binding, BufferPtr buff, PtrSize offset);
-
-	/// Bind transient uniform buffer.
-	void bindUniformBuffer(U32 set, U32 binding, const TransientMemoryToken& token);
+	/// @param set The set to bind to.
+	/// @param binding The binding to bind to.
+	/// @param[in,out] buff The buffer to bind.
+	/// @param offset The base of the binding.
+	/// @param range The bytes to bind starting from the offset. If it's MAX_PTR_SIZE then map from offset to the end
+	///              of the buffer.
+	void bindUniformBuffer(U32 set, U32 binding, BufferPtr buff, PtrSize offset, PtrSize range);
 
 	/// Bind storage buffer.
-	void bindStorageBuffer(U32 set, U32 binding, BufferPtr buff, PtrSize offset);
-
-	/// Bind transient storage buffer.
-	void bindStorageBuffer(U32 set, U32 binding, const TransientMemoryToken& token);
+	/// @param set The set to bind to.
+	/// @param binding The binding to bind to.
+	/// @param[in,out] buff The buffer to bind.
+	/// @param offset The base of the binding.
+	/// @param range The bytes to bind starting from the offset. If it's MAX_PTR_SIZE then map from offset to the end
+	///              of the buffer.
+	void bindStorageBuffer(U32 set, U32 binding, BufferPtr buff, PtrSize offset, PtrSize range);
 
 	/// Bind load/store image.
 	void bindImage(U32 set, U32 binding, TexturePtr img, U32 level);
@@ -315,6 +315,14 @@ public:
 		const ClearValue& clearValue,
 		DepthStencilAspectBit aspect = DepthStencilAspectBit::NONE);
 
+	/// Copy a buffer to a texture surface.
+	void copyBufferToTextureSurface(
+		BufferPtr buff, PtrSize offset, PtrSize range, TexturePtr tex, const TextureSurfaceInfo& surf);
+
+	/// Copy buffer to a texture volume.
+	void copyBufferToTextureVolume(
+		BufferPtr buff, PtrSize offset, PtrSize range, TexturePtr tex, const TextureVolumeInfo& vol);
+
 	/// Fill a buffer with some value.
 	/// @param[in,out] buff The buffer to fill.
 	/// @param offset From where to start filling. Must be multiple of 4.
@@ -327,35 +335,14 @@ public:
 	/// @param offset The offset inside the buffer to write the result.
 	/// @param buff The buffer to update.
 	void writeOcclusionQueryResultToBuffer(OcclusionQueryPtr query, PtrSize offset, BufferPtr buff);
-	/// @}
-
-	/// @name Resource upload
-	/// @{
-
-	/// Upload data to a texture surface. It's the base of all texture surface upload methods.
-	void uploadTextureSurface(TexturePtr tex, const TextureSurfaceInfo& surf, const TransientMemoryToken& token);
-
-	/// Same as uploadTextureSurface but it will perform the transient allocation as well. If that allocation fails
-	/// expect the defaul OOM behaviour (crash).
-	void uploadTextureSurfaceData(TexturePtr tex, const TextureSurfaceInfo& surf, void*& data, PtrSize& dataSize);
-
-	/// Same as uploadTextureSurfaceData but it will return a nullptr in @a data if there is a OOM condition.
-	void tryUploadTextureSurfaceData(TexturePtr tex, const TextureSurfaceInfo& surf, void*& data, PtrSize& dataSize);
 
-	/// Same as uploadTextureSurface but it will perform the transient allocation and copy to it the @a data. If that
-	/// allocation fails expect the defaul OOM behaviour (crash).
-	void uploadTextureSurfaceCopyData(
-		TexturePtr tex, const TextureSurfaceInfo& surf, const void* data, PtrSize dataSize);
-
-	/// Upload data to a texture volume. It's the base of all texture volume upload methods.
-	void uploadTextureVolume(TexturePtr tex, const TextureVolumeInfo& vol, const TransientMemoryToken& token);
-
-	/// Same as uploadTextureVolume but it will perform the transient allocation and copy to it the @a data. If that
-	/// allocation fails expect the defaul OOM behaviour (crash).
-	void uploadTextureVolumeCopyData(TexturePtr tex, const TextureVolumeInfo& surf, const void* data, PtrSize dataSize);
-
-	/// Upload data to a buffer.
-	void uploadBuffer(BufferPtr buff, PtrSize offset, const TransientMemoryToken& token);
+	/// Copy buffer to buffer.
+	/// @param[in] src Source buffer.
+	/// @param srcOffset Offset in the src buffer.
+	/// @param[out] dst Destination buffer.
+	/// @param dstOffset Offset in the destination buffer.
+	/// @param range Size to copy.
+	void copyBufferToBuffer(BufferPtr src, PtrSize srcOffset, BufferPtr dst, PtrSize dstOffset, PtrSize range);
 	/// @}
 
 	/// @name Sync
@@ -405,5 +392,3 @@ anki_internal:
 /// @}
 
 } // end namespace anki
-
-#include <anki/gr/CommandBuffer.inl.h>

+ 0 - 38
src/anki/gr/Common.h

@@ -163,44 +163,6 @@ const U MAX_BOUND_RESOURCE_GROUPS = 2;
 /// An anoying limit for Vulkan.
 const U MAX_RESOURCE_GROUPS = 1024;
 
-/// 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
-{
-public:
-	operator Bool() const
-	{
-		return m_range != 0;
-	}
-
-	Bool operator==(const TransientMemoryToken& b) const
-	{
-		return m_offset == b.m_offset && m_range == b.m_range && m_lifetime == b.m_lifetime && m_usage == b.m_usage;
-	}
-
-anki_internal:
-	PtrSize m_offset = 0;
-	PtrSize m_range = 0;
-	TransientMemoryTokenLifetime m_lifetime = TransientMemoryTokenLifetime::PER_FRAME;
-	BufferUsageBit m_usage = BufferUsageBit::NONE;
-
-	void markUnused()
-	{
-		m_offset = m_range = MAX_U32;
-	}
-
-	Bool isUnused() const
-	{
-		return m_offset == MAX_U32 && m_range == MAX_U32;
-	}
-};
-
 /// Compute max number of mipmaps for a 2D texture.
 inline U computeMaxMipmapCount2d(U w, U h, U minSizeOfLastMip = 1)
 {

+ 8 - 11
src/anki/gr/GrManager.h

@@ -61,7 +61,7 @@ public:
 
 	/// Create a new graphics object.
 	template<typename T, typename... Args>
-	GrObjectPtr<T> newInstanceCached(U64 hash, GrObjectCache* cache, Args&&... args)
+	ANKI_USE_RESULT GrObjectPtr<T> newInstanceCached(U64 hash, GrObjectCache* cache, Args&&... args)
 	{
 		GrObjectPtr<T> ptr(m_alloc.newInstance<T>(this, hash, cache));
 		ptr->init(args...);
@@ -70,20 +70,11 @@ public:
 
 	/// Create a new graphics object.
 	template<typename T, typename... Args>
-	GrObjectPtr<T> newInstance(Args&&... args)
+	ANKI_USE_RESULT GrObjectPtr<T> newInstance(Args&&... args)
 	{
 		return newInstanceCached<T>(0, nullptr, args...);
 	}
 
-	/// Allocate transient memory for various operations. The memory will be reclaimed at the begining of the
-	/// N-(MAX_FRAMES_IN_FLIGHT-1) frame.
-	ANKI_USE_RESULT void* allocateFrameTransientMemory(PtrSize size, BufferUsageBit usage, TransientMemoryToken& token);
-
-	/// Allocate transient memory for various operations. The memory will be reclaimed at the begining of the
-	/// N-(MAX_FRAMES_IN_FLIGHT-1) frame.
-	ANKI_USE_RESULT void* tryAllocateFrameTransientMemory(
-		PtrSize size, BufferUsageBit usage, TransientMemoryToken& token);
-
 	/// Call this before calling allocateFrameTransientMemory or tryAllocateFrameTransientMemory to get the exact memory
 	/// that will be required for the CommandBuffer::uploadTextureSurface.
 	///
@@ -97,6 +88,12 @@ public:
 	void getTextureVolumeUploadInfo(
 		TexturePtr tex, const TextureVolumeInfo& vol, PtrSize& expectedTransientAllocationSize);
 
+	/// Get some buffer alignment and size info.
+	void getUniformBufferInfo(U32& bindOffsetAlignment, PtrSize& maxUniformBlockSize) const;
+
+	/// Get some buffer alignment info.
+	void getStorageBufferInfo(U32& bindOffsetAlignment, PtrSize& maxStorageBlockSize) const;
+
 anki_internal:
 	GrAllocator<U8>& getAllocator()
 	{

+ 8 - 7
src/anki/gr/gl/BufferImpl.h

@@ -38,19 +38,20 @@ public:
 
 	void init(PtrSize size, BufferUsageBit usage, BufferMapAccessBit access);
 
-	void bind(GLenum target, U32 binding, PtrSize offset, PtrSize size) const
+	void bind(GLenum target, U32 binding, PtrSize offset, PtrSize range) const
 	{
 		ANKI_ASSERT(isCreated());
-		ANKI_ASSERT(offset + size <= m_size);
-		ANKI_ASSERT(size > 0);
-		glBindBufferRange(target, binding, m_glName, offset, size);
+
+		range = (range == MAX_PTR_SIZE) ? (m_size - offset) : range;
+		ANKI_ASSERT(range > 0);
+		ANKI_ASSERT(offset + range <= m_size);
+
+		glBindBufferRange(target, binding, m_glName, offset, range);
 	}
 
 	void bind(GLenum target, U32 binding, PtrSize offset) const
 	{
-		ANKI_ASSERT(isCreated());
-		ANKI_ASSERT(offset < m_size);
-		glBindBufferRange(target, binding, m_glName, offset, m_size - offset);
+		bind(target, binding, offset, MAX_PTR_SIZE);
 	}
 
 	void write(GLuint pbo, U32 pboOffset, U32 offset, U32 size) const

+ 72 - 191
src/anki/gr/gl/CommandBuffer.cpp

@@ -9,7 +9,6 @@
 #include <anki/gr/gl/GrManagerImpl.h>
 #include <anki/gr/gl/RenderingThread.h>
 #include <anki/gr/gl/GlState.h>
-#include <anki/gr/gl/TransientMemoryManager.h>
 
 #include <anki/gr/Framebuffer.h>
 #include <anki/gr/gl/FramebufferImpl.h>
@@ -110,46 +109,6 @@ void CommandBuffer::bindVertexBuffer(U32 binding, BufferPtr buff, PtrSize offset
 	}
 }
 
-void CommandBuffer::bindVertexBuffer(U32 binding, const TransientMemoryToken& token, PtrSize stride)
-{
-	class Cmd final : public GlCommand
-	{
-	public:
-		U32 m_binding;
-		TransientMemoryToken m_token;
-		PtrSize m_stride;
-		GLuint m_name;
-
-		Cmd(U32 binding, const TransientMemoryToken& token, PtrSize stride, GLuint name)
-			: m_binding(binding)
-			, m_token(token)
-			, m_stride(stride)
-			, m_name(name)
-		{
-		}
-
-		Error operator()(GlState& state)
-		{
-			glBindVertexBuffer(m_binding, m_name, m_token.m_offset, m_stride);
-			return ErrorCode::NONE;
-		}
-	};
-
-	ANKI_ASSERT(token);
-	ANKI_ASSERT(stride > 0);
-
-	if(!token.isUnused())
-	{
-		ANKI_ASSERT(token.m_usage == BufferUsageBit::VERTEX);
-		GLuint name = getManager().getImplementation().getTransientMemoryManager().getGlName(token);
-
-		if(m_impl->m_state.bindVertexBuffer(binding, token, stride))
-		{
-			m_impl->pushBackNewCommand<Cmd>(binding, token, stride, name);
-		}
-	}
-}
-
 void CommandBuffer::setVertexAttribute(U32 location, U32 buffBinding, const PixelFormat& fmt, PtrSize relativeOffset)
 {
 	class Cmd final : public GlCommand
@@ -219,11 +178,6 @@ void CommandBuffer::bindIndexBuffer(BufferPtr buff, PtrSize offset, IndexType ty
 	}
 }
 
-void CommandBuffer::bindIndexBuffer(const TransientMemoryToken& token, IndexType type)
-{
-	ANKI_ASSERT(!"TODO");
-}
-
 void CommandBuffer::setPrimitiveRestart(Bool enable)
 {
 	class Cmd final : public GlCommand
@@ -696,143 +650,73 @@ void CommandBuffer::bindTextureAndSampler(
 	}
 }
 
-void CommandBuffer::bindUniformBuffer(U32 set, U32 binding, BufferPtr buff, PtrSize offset)
+void CommandBuffer::bindUniformBuffer(U32 set, U32 binding, BufferPtr buff, PtrSize offset, PtrSize range)
 {
 	class Cmd final : public GlCommand
 	{
 	public:
-		U32 m_binding;
 		BufferPtr m_buff;
+		PtrSize m_binding;
 		PtrSize m_offset;
+		PtrSize m_range;
 
-		Cmd(U32 binding, BufferPtr buff, PtrSize offset)
-			: m_binding(binding)
-			, m_buff(buff)
+		Cmd(U32 binding, BufferPtr buff, PtrSize offset, PtrSize range)
+			: m_buff(buff)
+			, m_binding(binding)
 			, m_offset(offset)
+			, m_range(range)
 		{
 		}
 
 		Error operator()(GlState&)
 		{
-			m_buff->m_impl->bind(GL_UNIFORM_BUFFER, m_binding, m_offset);
+			m_buff->m_impl->bind(GL_UNIFORM_BUFFER, m_binding, m_offset, m_range);
 			return ErrorCode::NONE;
 		}
 	};
 
 	ANKI_ASSERT(buff);
+	ANKI_ASSERT(range > 0);
 
-	if(m_impl->m_state.bindUniformBuffer(set, binding, buff, offset))
+	if(m_impl->m_state.bindUniformBuffer(set, binding, buff, offset, range))
 	{
 		binding = binding + MAX_UNIFORM_BUFFER_BINDINGS * set;
-		m_impl->pushBackNewCommand<Cmd>(binding, buff, offset);
+		m_impl->pushBackNewCommand<Cmd>(binding, buff, offset, range);
 	}
 }
 
-void CommandBuffer::bindUniformBuffer(U32 set, U32 binding, const TransientMemoryToken& token)
+void CommandBuffer::bindStorageBuffer(U32 set, U32 binding, BufferPtr buff, PtrSize offset, PtrSize range)
 {
 	class Cmd final : public GlCommand
 	{
 	public:
-		U32 m_binding;
-		TransientMemoryToken m_token;
-		GLuint m_name;
-
-		Cmd(U32 binding, const TransientMemoryToken& token, GLuint name)
-			: m_binding(binding)
-			, m_token(token)
-			, m_name(name)
-		{
-		}
-
-		Error operator()(GlState& state)
-		{
-			glBindBufferRange(GL_UNIFORM_BUFFER, m_binding, m_name, m_token.m_offset, m_token.m_range);
-			return ErrorCode::NONE;
-		}
-	};
-
-	ANKI_ASSERT(token);
-
-	if(!token.isUnused())
-	{
-		ANKI_ASSERT(!!(token.m_usage & BufferUsageBit::UNIFORM_ALL));
-
-		if(m_impl->m_state.bindUniformBuffer(set, binding, token))
-		{
-			binding = binding + MAX_UNIFORM_BUFFER_BINDINGS * set;
-			GLuint name = getManager().getImplementation().getTransientMemoryManager().getGlName(token);
-			m_impl->pushBackNewCommand<Cmd>(binding, token, name);
-		}
-	}
-}
-
-void CommandBuffer::bindStorageBuffer(U32 set, U32 binding, BufferPtr buff, PtrSize offset)
-{
-	class Cmd final : public GlCommand
-	{
-	public:
-		U32 m_binding;
 		BufferPtr m_buff;
+		PtrSize m_binding;
 		PtrSize m_offset;
+		PtrSize m_range;
 
-		Cmd(U32 binding, BufferPtr buff, PtrSize offset)
-			: m_binding(binding)
-			, m_buff(buff)
+		Cmd(U32 binding, BufferPtr buff, PtrSize offset, PtrSize range)
+			: m_buff(buff)
+			, m_binding(binding)
 			, m_offset(offset)
+			, m_range(range)
 		{
 		}
 
 		Error operator()(GlState&)
 		{
-			m_buff->m_impl->bind(GL_SHADER_STORAGE_BUFFER, m_binding, m_offset);
+			m_buff->m_impl->bind(GL_SHADER_STORAGE_BUFFER, m_binding, m_offset, m_range);
 			return ErrorCode::NONE;
 		}
 	};
 
 	ANKI_ASSERT(buff);
+	ANKI_ASSERT(range > 0);
 
-	if(m_impl->m_state.bindStorageBuffer(set, binding, buff, offset))
+	if(m_impl->m_state.bindStorageBuffer(set, binding, buff, offset, range))
 	{
 		binding = binding + MAX_STORAGE_BUFFER_BINDINGS * set;
-		m_impl->pushBackNewCommand<Cmd>(binding, buff, offset);
-	}
-}
-
-void CommandBuffer::bindStorageBuffer(U32 set, U32 binding, const TransientMemoryToken& token)
-{
-	class Cmd final : public GlCommand
-	{
-	public:
-		U32 m_binding;
-		TransientMemoryToken m_token;
-		GLuint m_name;
-
-		Cmd(U32 binding, const TransientMemoryToken& token, GLuint name)
-			: m_binding(binding)
-			, m_token(token)
-			, m_name(name)
-		{
-		}
-
-		Error operator()(GlState& state)
-		{
-			glBindBufferRange(GL_SHADER_STORAGE_BUFFER, m_binding, m_name, m_token.m_offset, m_token.m_range);
-			return ErrorCode::NONE;
-		}
-	};
-
-	ANKI_ASSERT(token);
-
-	if(!token.isUnused())
-	{
-		ANKI_ASSERT(!!(token.m_usage & BufferUsageBit::STORAGE_ALL));
-
-		if(m_impl->m_state.bindStorageBuffer(set, binding, token))
-		{
-			binding = binding + MAX_STORAGE_BUFFER_BINDINGS * set;
-			GLuint name = getManager().getImplementation().getTransientMemoryManager().getGlName(token);
-			m_impl->pushBackNewCommand<Cmd>(binding, token, name);
-		}
+		m_impl->pushBackNewCommand<Cmd>(binding, buff, offset, range);
 	}
 }
 
@@ -1181,116 +1065,113 @@ void CommandBuffer::endOcclusionQuery(OcclusionQueryPtr query)
 	m_impl->pushBackNewCommand<OqEndCommand>(query);
 }
 
-void CommandBuffer::uploadTextureSurface(
-	TexturePtr tex, const TextureSurfaceInfo& surf, const TransientMemoryToken& token)
+void CommandBuffer::copyBufferToTextureSurface(
+	BufferPtr buff, PtrSize offset, PtrSize range, TexturePtr tex, const TextureSurfaceInfo& surf)
 {
 	class TexSurfUploadCommand final : public GlCommand
 	{
 	public:
-		TexturePtr m_handle;
+		BufferPtr m_buff;
+		PtrSize m_offset;
+		PtrSize m_range;
+		TexturePtr m_tex;
 		TextureSurfaceInfo m_surf;
-		TransientMemoryToken m_token;
 
-		TexSurfUploadCommand(const TexturePtr& handle, TextureSurfaceInfo surf, const TransientMemoryToken& token)
-			: m_handle(handle)
+		TexSurfUploadCommand(
+			BufferPtr buff, PtrSize offset, PtrSize range, TexturePtr tex, const TextureSurfaceInfo& surf)
+			: m_buff(buff)
+			, m_offset(offset)
+			, m_range(range)
+			, m_tex(tex)
 			, m_surf(surf)
-			, m_token(token)
 		{
 		}
 
 		Error operator()(GlState& state)
 		{
-			GLuint pbo = state.m_manager->getImplementation().getTransientMemoryManager().getGlName(m_token);
-			m_handle->m_impl->writeSurface(m_surf, pbo, m_token.m_offset, m_token.m_range);
-
-			if(m_token.m_lifetime == TransientMemoryTokenLifetime::PERSISTENT)
-			{
-				state.m_manager->getImplementation().getTransientMemoryManager().free(m_token);
-			}
-
+			m_tex->m_impl->writeSurface(m_surf, m_buff->m_impl->getGlName(), m_offset, m_range);
 			return ErrorCode::NONE;
 		}
 	};
 
 	ANKI_ASSERT(tex);
-	ANKI_ASSERT(token);
+	ANKI_ASSERT(buff);
+	ANKI_ASSERT(range > 0);
 	ANKI_ASSERT(!m_impl->m_state.insideRenderPass());
 
-	m_impl->pushBackNewCommand<TexSurfUploadCommand>(tex, surf, token);
+	m_impl->pushBackNewCommand<TexSurfUploadCommand>(buff, offset, range, tex, surf);
 }
 
-void CommandBuffer::uploadTextureVolume(TexturePtr tex, const TextureVolumeInfo& vol, const TransientMemoryToken& token)
+void CommandBuffer::copyBufferToTextureVolume(
+	BufferPtr buff, PtrSize offset, PtrSize range, TexturePtr tex, const TextureVolumeInfo& vol)
 {
 	class TexVolUploadCommand final : public GlCommand
 	{
 	public:
-		TexturePtr m_handle;
+		BufferPtr m_buff;
+		PtrSize m_offset;
+		PtrSize m_range;
+		TexturePtr m_tex;
 		TextureVolumeInfo m_vol;
-		TransientMemoryToken m_token;
 
-		TexVolUploadCommand(const TexturePtr& handle, TextureVolumeInfo vol, const TransientMemoryToken& token)
-			: m_handle(handle)
+		TexVolUploadCommand(BufferPtr buff, PtrSize offset, PtrSize range, TexturePtr tex, const TextureVolumeInfo& vol)
+			: m_buff(buff)
+			, m_offset(offset)
+			, m_range(range)
+			, m_tex(tex)
 			, m_vol(vol)
-			, m_token(token)
 		{
 		}
 
 		Error operator()(GlState& state)
 		{
-			GLuint pbo = state.m_manager->getImplementation().getTransientMemoryManager().getGlName(m_token);
-			m_handle->m_impl->writeVolume(m_vol, pbo, m_token.m_offset, m_token.m_range);
-
-			if(m_token.m_lifetime == TransientMemoryTokenLifetime::PERSISTENT)
-			{
-				state.m_manager->getImplementation().getTransientMemoryManager().free(m_token);
-			}
-
+			m_tex->m_impl->writeVolume(m_vol, m_buff->m_impl->getGlName(), m_offset, m_range);
 			return ErrorCode::NONE;
 		}
 	};
 
 	ANKI_ASSERT(tex);
-	ANKI_ASSERT(token);
+	ANKI_ASSERT(buff);
+	ANKI_ASSERT(range > 0);
 	ANKI_ASSERT(!m_impl->m_state.insideRenderPass());
 
-	m_impl->pushBackNewCommand<TexVolUploadCommand>(tex, vol, token);
+	m_impl->pushBackNewCommand<TexVolUploadCommand>(buff, offset, range, tex, vol);
 }
 
-void CommandBuffer::uploadBuffer(BufferPtr buff, PtrSize offset, const TransientMemoryToken& token)
+void CommandBuffer::copyBufferToBuffer(
+	BufferPtr src, PtrSize srcOffset, BufferPtr dst, PtrSize dstOffset, PtrSize range)
 {
-	class BuffWriteCommand final : public GlCommand
+	class Cmd final : public GlCommand
 	{
 	public:
-		BufferPtr m_handle;
-		PtrSize m_offset;
-		TransientMemoryToken m_token;
+		BufferPtr m_src;
+		PtrSize m_srcOffset;
+		BufferPtr m_dst;
+		PtrSize m_dstOffset;
+		PtrSize m_range;
 
-		BuffWriteCommand(const BufferPtr& handle, PtrSize offset, const TransientMemoryToken& token)
-			: m_handle(handle)
-			, m_offset(offset)
-			, m_token(token)
+		Cmd(BufferPtr src, PtrSize srcOffset, BufferPtr dst, PtrSize dstOffset, PtrSize range)
+			: m_src(src)
+			, m_srcOffset(srcOffset)
+			, m_dst(dst)
+			, m_dstOffset(dstOffset)
+			, m_range(range)
 		{
 		}
 
 		Error operator()(GlState& state)
 		{
-			GLuint pbo = state.m_manager->getImplementation().getTransientMemoryManager().getGlName(m_token);
-			m_handle->m_impl->write(pbo, m_token.m_offset, m_offset, m_token.m_range);
-
-			if(m_token.m_lifetime == TransientMemoryTokenLifetime::PERSISTENT)
-			{
-				state.m_manager->getImplementation().getTransientMemoryManager().free(m_token);
-			}
-
+			m_dst->m_impl->write(m_src->m_impl->getGlName(), m_srcOffset, m_dstOffset, m_range);
 			return ErrorCode::NONE;
 		}
 	};
 
-	ANKI_ASSERT(token);
-	ANKI_ASSERT(buff);
+	ANKI_ASSERT(src);
+	ANKI_ASSERT(dst);
+	ANKI_ASSERT(range > 0);
 	ANKI_ASSERT(!m_impl->m_state.insideRenderPass());
 
-	m_impl->pushBackNewCommand<BuffWriteCommand>(buff, offset, token);
+	m_impl->pushBackNewCommand<Cmd>(src, srcOffset, dst, dstOffset, range);
 }
 
 void CommandBuffer::generateMipmaps2d(TexturePtr tex, U face, U layer)

+ 2 - 2
src/anki/gr/gl/FramebufferImpl.cpp

@@ -248,8 +248,8 @@ void FramebufferImpl::bind(const GlState& state)
 				glStencilMaskSeparate(GL_FRONT, MAX_U32);
 			}
 
-			GLuint clearVal = m_in.m_depthStencilAttachment.m_clearValue.m_depthStencil.m_stencil;
-			glClearBufferuiv(GL_STENCIL, 0, &clearVal);
+			GLint clearVal = m_in.m_depthStencilAttachment.m_clearValue.m_depthStencil.m_stencil;
+			glClearBufferiv(GL_STENCIL, 0, &clearVal);
 
 			if(state.m_stencilWriteMask[0] != MAX_U32)
 			{

+ 13 - 0
src/anki/gr/gl/GlState.cpp

@@ -140,6 +140,19 @@ void GlState::initRenderThread()
 	{
 		glEnableVertexAttribArray(i);
 	}
+
+	I64 val;
+	glGetInteger64v(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &val);
+	m_uboAlignment = val;
+
+	glGetInteger64v(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, &val);
+	m_ssboAlignment = val;
+
+	glGetInteger64v(GL_MAX_UNIFORM_BLOCK_SIZE, &val);
+	m_uniBlockMaxSize = val;
+
+	glGetInteger64v(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &val);
+	m_storageBlockMaxSize = val;
 }
 
 void GlState::destroy()

+ 5 - 0
src/anki/gr/gl/GlState.h

@@ -28,6 +28,11 @@ public:
 
 	GLuint m_defaultVao = 0;
 
+	U32 m_uboAlignment = 0;
+	U32 m_ssboAlignment = 0;
+	U32 m_uniBlockMaxSize = 0;
+	U32 m_storageBlockMaxSize = 0;
+
 	/// @name FB
 	/// @{
 	Array2d<Bool, MAX_COLOR_ATTACHMENTS, 4> m_colorWriteMasks = {{{{true, true, true, true}},

+ 17 - 20
src/anki/gr/gl/GrManager.cpp

@@ -6,8 +6,8 @@
 #include <anki/gr/GrManager.h>
 #include <anki/gr/gl/GrManagerImpl.h>
 #include <anki/gr/gl/RenderingThread.h>
-#include <anki/gr/gl/TransientMemoryManager.h>
 #include <anki/gr/gl/TextureImpl.h>
+#include <anki/gr/gl/GlState.h>
 #include <anki/core/Timestamp.h>
 #include <cstring>
 
@@ -52,25 +52,6 @@ void GrManager::finish()
 	m_impl->getRenderingThread().syncClientServer();
 }
 
-void* GrManager::allocateFrameTransientMemory(PtrSize size, BufferUsageBit usage, TransientMemoryToken& token)
-{
-	void* data = nullptr;
-	m_impl->getTransientMemoryManager().allocate(
-		size, usage, TransientMemoryTokenLifetime::PER_FRAME, token, data, nullptr);
-
-	return data;
-}
-
-void* GrManager::tryAllocateFrameTransientMemory(PtrSize size, BufferUsageBit usage, TransientMemoryToken& token)
-{
-	void* data = nullptr;
-	Error err = ErrorCode::NONE;
-	m_impl->getTransientMemoryManager().allocate(
-		size, usage, TransientMemoryTokenLifetime::PER_FRAME, token, data, &err);
-
-	return (!err) ? data : nullptr;
-}
-
 void GrManager::getTextureSurfaceUploadInfo(TexturePtr tex, const TextureSurfaceInfo& surf, PtrSize& allocationSize)
 {
 	const TextureImpl& impl = *tex->m_impl;
@@ -92,4 +73,20 @@ void GrManager::getTextureVolumeUploadInfo(TexturePtr tex, const TextureVolumeIn
 	allocationSize = computeVolumeSize(width, height, depth, impl.m_pformat);
 }
 
+void GrManager::getUniformBufferInfo(U32& bindOffsetAlignment, PtrSize& maxUniformBlockSize) const
+{
+	bindOffsetAlignment = m_impl->getState().m_uboAlignment;
+	maxUniformBlockSize = m_impl->getState().m_uniBlockMaxSize;
+
+	ANKI_ASSERT(bindOffsetAlignment > 0 && maxUniformBlockSize > 0);
+}
+
+void GrManager::getStorageBufferInfo(U32& bindOffsetAlignment, PtrSize& maxStorageBlockSize) const
+{
+	bindOffsetAlignment = m_impl->getState().m_ssboAlignment;
+	maxStorageBlockSize = m_impl->getState().m_storageBlockMaxSize;
+
+	ANKI_ASSERT(bindOffsetAlignment > 0 && maxStorageBlockSize > 0);
+}
+
 } // end namespace anki

+ 0 - 5
src/anki/gr/gl/GrManagerImpl.cpp

@@ -7,7 +7,6 @@
 #include <anki/gr/GrManager.h>
 #include <anki/gr/gl/RenderingThread.h>
 #include <anki/gr/gl/GlState.h>
-#include <anki/gr/gl/TransientMemoryManager.h>
 
 namespace anki
 {
@@ -44,10 +43,6 @@ Error GrManagerImpl::init(GrManagerInitInfo& init)
 	m_state = m_manager->getAllocator().newInstance<GlState>(m_manager);
 	m_state->initMainThread(*init.m_config);
 
-	// Dyn manager
-	m_transManager = m_manager->getAllocator().newInstance<TransientMemoryManager>();
-	m_transManager->initMainThread(m_manager->getAllocator(), *init.m_config);
-
 	// Create thread
 	m_thread = m_manager->getAllocator().newInstance<RenderingThread>(m_manager);
 

+ 0 - 14
src/anki/gr/gl/GrManagerImpl.h

@@ -14,7 +14,6 @@ namespace anki
 class RenderingThread;
 class WindowingBackend;
 class GlState;
-class TransientMemoryManager;
 
 /// @addtogroup opengl
 /// @{
@@ -57,18 +56,6 @@ public:
 		return *m_state;
 	}
 
-	TransientMemoryManager& getTransientMemoryManager()
-	{
-		ANKI_ASSERT(m_transManager);
-		return *m_transManager;
-	}
-
-	const TransientMemoryManager& getTransientMemoryManager() const
-	{
-		ANKI_ASSERT(m_transManager);
-		return *m_transManager;
-	}
-
 	GrAllocator<U8> getAllocator() const;
 
 	void swapBuffers();
@@ -80,7 +67,6 @@ private:
 	GlState* m_state = nullptr;
 	RenderingThread* m_thread = nullptr;
 	WindowingBackend* m_backend = nullptr; ///< The backend of the backend.
-	TransientMemoryManager* m_transManager = nullptr;
 
 	ANKI_USE_RESULT Error createBackend(GrManagerInitInfo& init);
 	void destroyBackend();

+ 0 - 8
src/anki/gr/gl/RenderingThread.cpp

@@ -8,7 +8,6 @@
 #include <anki/gr/GrManager.h>
 #include <anki/gr/gl/GrManagerImpl.h>
 #include <anki/gr/gl/GlState.h>
-#include <anki/gr/gl/TransientMemoryManager.h>
 #include <anki/util/Logger.h>
 #include <anki/core/Trace.h>
 #include <cstdlib>
@@ -160,9 +159,6 @@ void RenderingThread::prepare()
 
 	// Init state
 	m_manager->getImplementation().getState().initRenderThread();
-
-	// Init dyn mem
-	m_manager->getImplementation().getTransientMemoryManager().initRenderThread();
 }
 
 void RenderingThread::finish()
@@ -180,8 +176,6 @@ void RenderingThread::finish()
 		}
 	}
 
-	m_manager->getImplementation().getTransientMemoryManager().destroyRenderThread();
-
 	// Cleanup GL
 	m_manager->getImplementation().getState().destroy();
 
@@ -284,8 +278,6 @@ void RenderingThread::swapBuffers()
 		m_frameWait = true;
 	}
 
-	m_manager->getImplementation().getTransientMemoryManager().endFrame();
-
 	// ...and then flush a new swap buffers
 	flushCommandBuffer(m_swapBuffersCommands);
 	ANKI_TRACE_STOP_EVENT(SWAP_BUFFERS);

+ 1 - 0
src/anki/gr/gl/ShaderProgram.cpp

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

+ 5 - 35
src/anki/gr/gl/StateTracker.h

@@ -64,7 +64,6 @@ public:
 		BufferImpl* m_buff = nullptr;
 		PtrSize m_offset = 0;
 		PtrSize m_stride = 0;
-		TransientMemoryToken m_token;
 	};
 
 	Array<VertexBuffer, MAX_VERTEX_ATTRIBUTES> m_vertBuffs;
@@ -75,17 +74,6 @@ public:
 		b.m_buff = buff->m_impl.get();
 		b.m_offset = offset;
 		b.m_stride = stride;
-		b.m_token = {};
-		return true;
-	}
-
-	Bool bindVertexBuffer(U32 binding, const TransientMemoryToken& token, PtrSize stride)
-	{
-		VertexBuffer& b = m_vertBuffs[binding];
-		b.m_buff = nullptr;
-		b.m_offset = 0;
-		b.m_stride = stride;
-		b.m_token = token;
 		return true;
 	}
 
@@ -480,46 +468,28 @@ public:
 	public:
 		BufferImpl* m_buff = nullptr;
 		PtrSize m_offset;
-		TransientMemoryToken m_token;
+		PtrSize m_range;
 	};
 
 	Array2d<ShaderBufferBinding, MAX_BOUND_RESOURCE_GROUPS, MAX_UNIFORM_BUFFER_BINDINGS> m_ubos;
 
-	Bool bindUniformBuffer(U32 set, U32 binding, BufferPtr buff, PtrSize offset)
+	Bool bindUniformBuffer(U32 set, U32 binding, BufferPtr buff, PtrSize offset, PtrSize range)
 	{
 		ShaderBufferBinding& b = m_ubos[set][binding];
 		b.m_buff = buff->m_impl.get();
 		b.m_offset = offset;
-		b.m_token = {};
-		return true;
-	}
-
-	Bool bindUniformBuffer(U32 set, U32 binding, const TransientMemoryToken& token)
-	{
-		ShaderBufferBinding& b = m_ubos[set][binding];
-		b.m_buff = nullptr;
-		b.m_offset = 0;
-		b.m_token = token;
+		b.m_range = range;
 		return true;
 	}
 
 	Array2d<ShaderBufferBinding, MAX_BOUND_RESOURCE_GROUPS, MAX_STORAGE_BUFFER_BINDINGS> m_ssbos;
 
-	Bool bindStorageBuffer(U32 set, U32 binding, BufferPtr buff, PtrSize offset)
+	Bool bindStorageBuffer(U32 set, U32 binding, BufferPtr buff, PtrSize offset, PtrSize range)
 	{
 		ShaderBufferBinding& b = m_ssbos[set][binding];
 		b.m_buff = buff->m_impl.get();
 		b.m_offset = offset;
-		b.m_token = {};
-		return true;
-	}
-
-	Bool bindStorageBuffer(U32 set, U32 binding, const TransientMemoryToken& token)
-	{
-		ShaderBufferBinding& b = m_ssbos[set][binding];
-		b.m_buff = nullptr;
-		b.m_offset = 0;
-		b.m_token = token;
+		b.m_range = range;
 		return true;
 	}
 

+ 0 - 153
src/anki/gr/gl/TransientMemoryManager.cpp

@@ -1,153 +0,0 @@
-// Copyright (C) 2009-2016, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#include <anki/gr/gl/TransientMemoryManager.h>
-#include <anki/gr/gl/Error.h>
-#include <anki/core/Config.h>
-#include <anki/core/Trace.h>
-
-namespace anki
-{
-
-TransientMemoryManager::~TransientMemoryManager()
-{
-	for(PerFrameBuffer& buff : m_perFrameBuffers)
-	{
-		ANKI_ASSERT(buff.m_name == 0);
-		(void)buff;
-	}
-}
-
-void TransientMemoryManager::destroyRenderThread()
-{
-	for(PerFrameBuffer& buff : m_perFrameBuffers)
-	{
-		if(buff.m_name != 0)
-		{
-			glDeleteBuffers(1, &buff.m_name);
-			buff.m_name = 0;
-		}
-	}
-}
-
-void TransientMemoryManager::initMainThread(GenericMemoryPoolAllocator<U8> alloc, const ConfigSet& cfg)
-{
-	m_alloc = alloc;
-
-	m_perFrameBuffers[TransientBufferType::UNIFORM].m_size = cfg.getNumber("gr.uniformPerFrameMemorySize");
-	m_perFrameBuffers[TransientBufferType::STORAGE].m_size = cfg.getNumber("gr.storagePerFrameMemorySize");
-	m_perFrameBuffers[TransientBufferType::VERTEX].m_size = cfg.getNumber("gr.vertexPerFrameMemorySize");
-	m_perFrameBuffers[TransientBufferType::TRANSFER].m_size = cfg.getNumber("gr.transferPerFrameMemorySize");
-}
-
-void TransientMemoryManager::initBuffer(TransientBufferType type, U32 alignment, PtrSize maxAllocSize, GLenum target)
-{
-	const U BUFF_FLAGS = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT;
-
-	// Create buffer
-	PerFrameBuffer& buff = m_perFrameBuffers[type];
-	glGenBuffers(1, &buff.m_name);
-	glBindBuffer(target, buff.m_name);
-
-	// Map it
-	glBufferStorage(target, buff.m_size, nullptr, BUFF_FLAGS);
-	buff.m_mappedMem = static_cast<U8*>(glMapBufferRange(target, 0, buff.m_size, BUFF_FLAGS));
-	ANKI_ASSERT(buff.m_mappedMem);
-
-	// Create the allocator
-	buff.m_alloc.init(buff.m_size, alignment, maxAllocSize);
-
-	glBindBuffer(target, 0);
-}
-
-void TransientMemoryManager::initRenderThread()
-{
-	// Uniform
-	{
-		GLint64 blockAlignment;
-		glGetInteger64v(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &blockAlignment);
-		initBuffer(TransientBufferType::UNIFORM, blockAlignment, MAX_UNIFORM_BLOCK_SIZE, GL_UNIFORM_BUFFER);
-	}
-
-	// Storage
-	{
-		GLint64 blockAlignment;
-		glGetInteger64v(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, &blockAlignment);
-		initBuffer(TransientBufferType::STORAGE, blockAlignment, MAX_STORAGE_BLOCK_SIZE, GL_SHADER_STORAGE_BUFFER);
-	}
-
-	// Vertex
-	initBuffer(TransientBufferType::VERTEX, 16, MAX_U32, GL_ARRAY_BUFFER);
-
-	// Transfer
-	initBuffer(TransientBufferType::TRANSFER, 16, MAX_U32, GL_PIXEL_UNPACK_BUFFER);
-}
-
-void TransientMemoryManager::allocate(PtrSize size,
-	BufferUsageBit usage,
-	TransientMemoryTokenLifetime lifespan,
-	TransientMemoryToken& token,
-	void*& ptr,
-	Error* outErr)
-{
-	Error err = ErrorCode::NONE;
-	ptr = nullptr;
-	U8* mappedMemBase;
-
-	if(lifespan == TransientMemoryTokenLifetime::PER_FRAME)
-	{
-		PerFrameBuffer& buff = m_perFrameBuffers[bufferUsageToTransient(usage)];
-		err = buff.m_alloc.allocate(size, token.m_offset);
-		mappedMemBase = buff.m_mappedMem;
-	}
-	else
-	{
-		ANKI_ASSERT(0);
-	}
-
-	if(!err)
-	{
-		token.m_usage = usage;
-		token.m_range = size;
-		token.m_lifetime = lifespan;
-		ptr = mappedMemBase + token.m_offset;
-	}
-	else if(outErr)
-	{
-		*outErr = err;
-	}
-	else
-	{
-		ANKI_LOGF("Out of transient GPU memory");
-	}
-}
-
-void TransientMemoryManager::endFrame()
-{
-	for(TransientBufferType usage = TransientBufferType::UNIFORM; usage < TransientBufferType::COUNT; ++usage)
-	{
-		PerFrameBuffer& buff = m_perFrameBuffers[usage];
-
-		if(buff.m_mappedMem)
-		{
-			// Increase the counters
-			switch(usage)
-			{
-			case TransientBufferType::UNIFORM:
-				ANKI_TRACE_INC_COUNTER(GR_DYNAMIC_UNIFORMS_SIZE, buff.m_alloc.getUnallocatedMemorySize());
-				break;
-			case TransientBufferType::STORAGE:
-				ANKI_TRACE_INC_COUNTER(GR_DYNAMIC_STORAGE_SIZE, buff.m_alloc.getUnallocatedMemorySize());
-				break;
-			default:
-				break;
-			}
-
-			buff.m_alloc.endFrame();
-		}
-	}
-}
-
-} // end namespace anki

+ 0 - 85
src/anki/gr/gl/TransientMemoryManager.h

@@ -1,85 +0,0 @@
-// Copyright (C) 2009-2016, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#pragma once
-
-#include <anki/gr/gl/Common.h>
-#include <anki/gr/common/FrameGpuAllocator.h>
-#include <anki/gr/common/GpuBlockAllocator.h>
-#include <anki/gr/common/Misc.h>
-
-namespace anki
-{
-
-// Forward
-class ConfigSet;
-
-/// @addtogroup opengl
-/// @{
-
-/// Manages all dynamic memory.
-class TransientMemoryManager : public NonCopyable
-{
-public:
-	TransientMemoryManager()
-	{
-	}
-
-	~TransientMemoryManager();
-
-	void initMainThread(GenericMemoryPoolAllocator<U8> alloc, const ConfigSet& cfg);
-
-	void initRenderThread();
-
-	void destroyRenderThread();
-
-	void endFrame();
-
-	void allocate(PtrSize size,
-		BufferUsageBit usage,
-		TransientMemoryTokenLifetime lifespan,
-		TransientMemoryToken& token,
-		void*& ptr,
-		Error* outErr);
-
-	void free(const TransientMemoryToken& token)
-	{
-		ANKI_ASSERT(token.m_lifetime == TransientMemoryTokenLifetime::PERSISTENT);
-	}
-
-	GLuint getGlName(const TransientMemoryToken& token) const
-	{
-		GLuint name;
-		if(token.m_lifetime == TransientMemoryTokenLifetime::PER_FRAME)
-		{
-			name = m_perFrameBuffers[bufferUsageToTransient(token.m_usage)].m_name;
-		}
-		else
-		{
-			name = 0;
-		}
-		ANKI_ASSERT(name);
-		return name;
-	}
-
-private:
-	// GPU buffer.
-	class PerFrameBuffer
-	{
-	public:
-		PtrSize m_size = 0;
-		GLuint m_name = 0;
-		U8* m_mappedMem = nullptr;
-		FrameGpuAllocator m_alloc;
-	};
-
-	GenericMemoryPoolAllocator<U8> m_alloc;
-	Array<PerFrameBuffer, U(TransientBufferType::COUNT)> m_perFrameBuffers;
-
-	void initBuffer(TransientBufferType type, U32 alignment, PtrSize maxAllocSize, GLenum target);
-};
-/// @}
-
-} // end namespace anki

+ 2 - 5
src/anki/renderer/Bloom.cpp

@@ -82,13 +82,10 @@ void BloomExposure::run(RenderingContext& ctx)
 	cmdb->bindShaderProgram(m_prog);
 	cmdb->bindTexture(0, 0, m_r->getIs().getRt());
 
-	TransientMemoryToken token;
-	Vec4* uniforms = static_cast<Vec4*>(
-		getGrManager().allocateFrameTransientMemory(sizeof(Vec4), BufferUsageBit::UNIFORM_ALL, token));
+	Vec4* uniforms = allocateAndBindUniforms<Vec4*>(sizeof(Vec4), cmdb, 0, 0);
 	*uniforms = Vec4(m_threshold, m_scale, 0.0, 0.0);
 
-	cmdb->bindUniformBuffer(0, 0, token);
-	cmdb->bindStorageBuffer(0, 0, m_r->getTm().m_luminanceBuff, 0);
+	cmdb->bindStorageBuffer(0, 0, m_r->getTm().m_luminanceBuff, 0, MAX_PTR_SIZE);
 
 	cmdb->setBlendFactors(0, BlendFactor::SRC_ALPHA, BlendFactor::ONE_MINUS_SRC_ALPHA);
 

+ 1 - 0
src/anki/renderer/Common.h

@@ -6,6 +6,7 @@
 #pragma once
 
 #include <anki/Gr.h>
+#include <anki/core/StagingGpuMemoryManager.h>
 #include <anki/util/Ptr.h>
 
 namespace anki

+ 7 - 6
src/anki/renderer/Drawer.cpp

@@ -128,7 +128,7 @@ public:
 	Array<Mat4, MAX_INSTANCES> m_cachedTrfs;
 	U m_cachedTrfCount = 0;
 
-	TransientMemoryToken m_uboToken;
+	StagingGpuMemoryToken m_uboToken;
 
 	U m_nodeProcessedCount = 0;
 
@@ -297,8 +297,8 @@ void RenderableDrawer::setupUniforms(DrawContext& ctx, CompleteRenderingBuildInf
 	const MaterialVariant& variant = mtl.getVariant(build.m_in.m_key);
 
 	// Get some memory for uniforms
-	U8* uniforms = static_cast<U8*>(m_r->getGrManager().allocateFrameTransientMemory(
-		variant.getDefaultBlockSize(), BufferUsageBit::UNIFORM_ALL, ctx.m_uboToken));
+	U8* uniforms = static_cast<U8*>(m_r->getStagingGpuMemoryManager().allocatePerFrame(
+		variant.getDefaultBlockSize(), StagingGpuMemoryType::UNIFORM, ctx.m_uboToken));
 
 	// Call the visitor
 	SetupRenderableVariableVisitor visitor;
@@ -363,7 +363,7 @@ Error RenderableDrawer::flushDrawcall(DrawContext& ctx, CompleteRenderingBuildIn
 	// Finaly, touch the command buffer
 	CommandBufferPtr& cmdb = ctx.m_cmdb;
 
-	cmdb->bindUniformBuffer(0, 0, ctx.m_uboToken);
+	cmdb->bindUniformBuffer(0, 0, ctx.m_uboToken.m_buffer, ctx.m_uboToken.m_offset, ctx.m_uboToken.m_range);
 	cmdb->bindShaderProgram(build.m_out.m_program);
 
 	for(U i = 0; i < build.m_out.m_vertexBufferBindingCount; ++i)
@@ -376,7 +376,7 @@ Error RenderableDrawer::flushDrawcall(DrawContext& ctx, CompleteRenderingBuildIn
 		else
 		{
 			ANKI_ASSERT(!!(binding.m_token));
-			cmdb->bindVertexBuffer(i, binding.m_token, binding.m_stride);
+			cmdb->bindVertexBuffer(i, binding.m_token.m_buffer, binding.m_token.m_offset, binding.m_stride);
 		}
 	}
 
@@ -398,7 +398,8 @@ Error RenderableDrawer::flushDrawcall(DrawContext& ctx, CompleteRenderingBuildIn
 		else
 		{
 			ANKI_ASSERT(!!(build.m_out.m_indexBufferToken));
-			cmdb->bindIndexBuffer(build.m_out.m_indexBufferToken, IndexType::U16);
+			cmdb->bindIndexBuffer(
+				build.m_out.m_indexBufferToken.m_buffer, build.m_out.m_indexBufferToken.m_offset, IndexType::U16);
 		}
 
 		cmdb->drawElements(build.m_out.m_topology,

+ 6 - 10
src/anki/renderer/Fs.cpp

@@ -89,17 +89,13 @@ void Fs::drawVolumetric(RenderingContext& ctx, CommandBufferPtr cmdb)
 	cmdb->setDepthWrite(false);
 	cmdb->setDepthCompareOperation(CompareOperation::ALWAYS);
 
-	TransientMemoryToken token;
-	Vec4* unis = static_cast<Vec4*>(
-		getGrManager().allocateFrameTransientMemory(sizeof(Vec4), BufferUsageBit::UNIFORM_ALL, token));
+	Vec4* unis = allocateAndBindUniforms<Vec4*>(sizeof(Vec4), cmdb, 0, 0);
 	computeLinearizeDepthOptimal(fr.getNear(), fr.getFar(), unis->x(), unis->y());
 
 	cmdb->bindTextureAndSampler(0, 0, m_r->getDepthDownscale().m_hd.m_depthRt, m_vol.m_nearestSampler);
 	cmdb->bindTextureAndSampler(0, 1, m_r->getDepthDownscale().m_qd.m_depthRt, m_vol.m_nearestSampler);
 	cmdb->bindTexture(0, 2, m_r->getVolumetric().m_rt);
 
-	cmdb->bindUniformBuffer(0, 0, token);
-
 	m_r->drawQuad(cmdb);
 
 	// Restore state
@@ -133,11 +129,11 @@ Error Fs::buildCommandBuffers(RenderingContext& ctx, U threadId, U threadCount)
 	cmdb->bindTexture(1, 0, m_r->getDepthDownscale().m_hd.m_depthRt);
 	cmdb->bindTexture(1, 1, m_r->getSm().m_spotTexArray);
 	cmdb->bindTexture(1, 2, m_r->getSm().m_omniTexArray);
-	cmdb->bindUniformBuffer(1, 0, ctx.m_is.m_commonToken);
-	cmdb->bindUniformBuffer(1, 1, ctx.m_is.m_pointLightsToken);
-	cmdb->bindUniformBuffer(1, 2, ctx.m_is.m_spotLightsToken);
-	cmdb->bindStorageBuffer(1, 0, ctx.m_is.m_clustersToken);
-	cmdb->bindStorageBuffer(1, 1, ctx.m_is.m_lightIndicesToken);
+	bindUniforms(cmdb, 1, 0, ctx.m_is.m_commonToken);
+	bindUniforms(cmdb, 1, 1, ctx.m_is.m_pointLightsToken);
+	bindUniforms(cmdb, 1, 2, ctx.m_is.m_spotLightsToken);
+	bindStorage(cmdb, 1, 0, ctx.m_is.m_clustersToken);
+	bindStorage(cmdb, 1, 1, ctx.m_is.m_lightIndicesToken);
 
 	cmdb->setViewport(0, 0, m_width, m_height);
 	cmdb->setBlendFactors(

+ 1 - 5
src/anki/renderer/FsUpscale.cpp

@@ -67,14 +67,10 @@ void FsUpscale::run(RenderingContext& ctx)
 {
 	CommandBufferPtr cmdb = ctx.m_commandBuffer;
 
-	TransientMemoryToken token;
-
-	Vec4* linearDepth = static_cast<Vec4*>(
-		getGrManager().allocateFrameTransientMemory(sizeof(Vec4), BufferUsageBit::UNIFORM_ALL, token));
+	Vec4* linearDepth = allocateAndBindUniforms<Vec4*>(sizeof(Vec4), cmdb, 0, 0);
 	const Frustum& fr = ctx.m_frustumComponent->getFrustum();
 	computeLinearizeDepthOptimal(fr.getNear(), fr.getFar(), linearDepth->x(), linearDepth->y());
 
-	cmdb->bindUniformBuffer(0, 0, token);
 	cmdb->bindTexture(0, 0, m_r->getMs().m_depthRt);
 	cmdb->bindTextureAndSampler(0, 1, m_r->getDepthDownscale().m_hd.m_depthRt, m_nearestSampler);
 	cmdb->bindTexture(0, 2, m_r->getFs().getRt());

+ 11 - 31
src/anki/renderer/Ir.cpp

@@ -123,9 +123,9 @@ Error Ir::loadMesh(CString fname, BufferPtr& vert, BufferPtr& idx, U32& idxCount
 	init.m_flags = CommandBufferFlag::SMALL_BATCH;
 	CommandBufferPtr cmdb = getGrManager().newInstance<CommandBuffer>(init);
 
-	TransientMemoryToken token;
+	StagingGpuMemoryToken token;
 	Vec3* verts = static_cast<Vec3*>(
-		getGrManager().allocateFrameTransientMemory(vertBuffSize, BufferUsageBit::BUFFER_UPLOAD_SOURCE, token));
+		m_r->getStagingGpuMemoryManager().allocatePerFrame(vertBuffSize, StagingGpuMemoryType::TRANSFER, token));
 
 	const U8* ptr = loader.getVertexData();
 	for(U i = 0; i < loader.getHeader().m_totalVerticesCount; ++i)
@@ -135,14 +135,14 @@ Error Ir::loadMesh(CString fname, BufferPtr& vert, BufferPtr& idx, U32& idxCount
 		ptr += loader.getVertexSize();
 	}
 
-	cmdb->uploadBuffer(vert, 0, token);
+	cmdb->copyBufferToBuffer(token.m_buffer, token.m_offset, vert, 0, token.m_range);
 
-	void* cpuIds = getGrManager().allocateFrameTransientMemory(
-		loader.getIndexDataSize(), BufferUsageBit::BUFFER_UPLOAD_SOURCE, token);
+	void* cpuIds = m_r->getStagingGpuMemoryManager().allocatePerFrame(
+		loader.getIndexDataSize(), StagingGpuMemoryType::TRANSFER, token);
 
 	memcpy(cpuIds, loader.getIndexData(), loader.getIndexDataSize());
 
-	cmdb->uploadBuffer(idx, 0, token);
+	cmdb->copyBufferToBuffer(token.m_buffer, token.m_offset, idx, 0, token.m_range);
 	idxCount = loader.getHeader().m_totalIndicesCount;
 
 	cmdb->flush();
@@ -456,11 +456,8 @@ void Ir::runIs(RenderingContext& rctx, FrustumComponent& frc, U layer, U faceIdx
 		const LightComponent& lightc = it->m_node->getComponent<LightComponent>();
 		const MoveComponent& movec = it->m_node->getComponent<MoveComponent>();
 
-		TransientMemoryToken uniVertToken, uniFragToken;
-
 		// Update uniforms
-		IrVertex* vert = static_cast<IrVertex*>(
-			getGrManager().allocateFrameTransientMemory(sizeof(IrVertex), BufferUsageBit::UNIFORM_ALL, uniVertToken));
+		IrVertex* vert = allocateAndBindUniforms<IrVertex*>(sizeof(IrVertex), cmdb, 0, 0);
 
 		Mat4 modelM(movec.getWorldTransform().getOrigin().xyz1(),
 			movec.getWorldTransform().getRotation().getRotationPart(),
@@ -468,8 +465,7 @@ void Ir::runIs(RenderingContext& rctx, FrustumComponent& frc, U layer, U faceIdx
 
 		vert->m_mvp = vpMat * modelM;
 
-		IrPointLight* light = static_cast<IrPointLight*>(getGrManager().allocateFrameTransientMemory(
-			sizeof(IrPointLight), BufferUsageBit::UNIFORM_ALL, uniFragToken));
+		IrPointLight* light = allocateAndBindUniforms<IrPointLight*>(sizeof(IrPointLight), cmdb, 0, 1);
 
 		Vec4 pos = vMat * movec.getWorldTransform().getOrigin().xyz1();
 
@@ -478,10 +474,6 @@ void Ir::runIs(RenderingContext& rctx, FrustumComponent& frc, U layer, U faceIdx
 		light->m_diffuseColorPad1 = lightc.getDiffuseColor();
 		light->m_specularColorPad1 = lightc.getSpecularColor();
 
-		// Bind stuff
-		cmdb->bindUniformBuffer(0, 0, uniVertToken);
-		cmdb->bindUniformBuffer(0, 1, uniFragToken);
-
 		// Draw
 		cmdb->drawElements(PrimitiveTopology::TRIANGLES, m_is.m_plightIdxCount);
 
@@ -513,17 +505,12 @@ void Ir::runIs(RenderingContext& rctx, FrustumComponent& frc, U layer, U faceIdx
 
 		modelM = modelM * scaleM;
 
-		TransientMemoryToken uniVertToken, uniFragToken;
-
 		// Update vertex uniforms
-		IrVertex* vert = static_cast<IrVertex*>(
-			getGrManager().allocateFrameTransientMemory(sizeof(IrVertex), BufferUsageBit::UNIFORM_ALL, uniVertToken));
-
+		IrVertex* vert = allocateAndBindUniforms<IrVertex*>(sizeof(IrVertex), cmdb, 0, 0);
 		vert->m_mvp = vpMat * modelM;
 
 		// Update fragment uniforms
-		IrSpotLight* light = static_cast<IrSpotLight*>(getGrManager().allocateFrameTransientMemory(
-			sizeof(IrSpotLight), BufferUsageBit::UNIFORM_ALL, uniFragToken));
+		IrSpotLight* light = allocateAndBindUniforms<IrSpotLight*>(sizeof(IrSpotLight), cmdb, 0, 1);
 
 		light->m_projectionParams = frc.getProjectionParameters();
 
@@ -538,10 +525,6 @@ void Ir::runIs(RenderingContext& rctx, FrustumComponent& frc, U layer, U faceIdx
 		lightDir = vMat.getRotationPart() * lightDir;
 		light->m_lightDirPad1 = lightDir.xyz0();
 
-		// Bind stuff
-		cmdb->bindUniformBuffer(0, 0, uniVertToken);
-		cmdb->bindUniformBuffer(0, 1, uniFragToken);
-
 		// Draw
 		cmdb->drawElements(PrimitiveTopology::TRIANGLES, m_is.m_slightIdxCount);
 
@@ -584,13 +567,10 @@ void Ir::computeIrradiance(RenderingContext& rctx, U layer, U faceIdx)
 	// Set state and draw
 	cmdb->setViewport(0, 0, IRRADIANCE_TEX_SIZE, IRRADIANCE_TEX_SIZE);
 
-	TransientMemoryToken token;
-	UVec4* faceIdxArrayIdx = static_cast<UVec4*>(
-		getGrManager().allocateFrameTransientMemory(sizeof(UVec4), BufferUsageBit::UNIFORM_ALL, token));
+	UVec4* faceIdxArrayIdx = allocateAndBindUniforms<UVec4*>(sizeof(UVec4), cmdb, 0, 0);
 	faceIdxArrayIdx->x() = faceIdx;
 	faceIdxArrayIdx->y() = layer;
 
-	cmdb->bindUniformBuffer(0, 0, token);
 	cmdb->bindTexture(0, 0, m_is.m_lightRt);
 	cmdb->bindShaderProgram(m_irradiance.m_prog);
 	cmdb->beginRenderPass(face.m_irradianceFb);

+ 10 - 10
src/anki/renderer/Is.cpp

@@ -89,7 +89,7 @@ Error Is::initInternal(const ConfigSet& config)
 		m_clusterCounts[1],
 		m_clusterCounts[2],
 		&m_r->getThreadPool(),
-		&getGrManager());
+		&m_r->getStagingGpuMemoryManager());
 
 	//
 	// Load shaders and programs
@@ -188,14 +188,14 @@ void Is::run(RenderingContext& ctx)
 	cmdb->bindTexture(1, 0, (ctx.m_is.m_diffDecalTex) ? ctx.m_is.m_diffDecalTex : m_dummyTex);
 	cmdb->bindTexture(1, 1, (ctx.m_is.m_normRoughnessDecalTex) ? ctx.m_is.m_normRoughnessDecalTex : m_dummyTex);
 
-	cmdb->bindUniformBuffer(0, 0, ctx.m_is.m_commonToken);
-	cmdb->bindUniformBuffer(0, 1, ctx.m_is.m_pointLightsToken);
-	cmdb->bindUniformBuffer(0, 2, ctx.m_is.m_spotLightsToken);
-	cmdb->bindUniformBuffer(0, 3, ctx.m_is.m_probesToken);
-	cmdb->bindUniformBuffer(0, 4, ctx.m_is.m_decalsToken);
+	bindUniforms(cmdb, 0, 0, ctx.m_is.m_commonToken);
+	bindUniforms(cmdb, 0, 1, ctx.m_is.m_pointLightsToken);
+	bindUniforms(cmdb, 0, 2, ctx.m_is.m_spotLightsToken);
+	bindUniforms(cmdb, 0, 3, ctx.m_is.m_probesToken);
+	bindUniforms(cmdb, 0, 4, ctx.m_is.m_decalsToken);
 
-	cmdb->bindStorageBuffer(0, 0, ctx.m_is.m_clustersToken);
-	cmdb->bindStorageBuffer(0, 1, ctx.m_is.m_lightIndicesToken);
+	bindStorage(cmdb, 0, 0, ctx.m_is.m_clustersToken);
+	bindStorage(cmdb, 0, 1, ctx.m_is.m_lightIndicesToken);
 
 	cmdb->drawArrays(PrimitiveTopology::TRIANGLE_STRIP, 4, m_clusterCount);
 	cmdb->endRenderPass();
@@ -204,8 +204,8 @@ void Is::run(RenderingContext& ctx)
 void Is::updateCommonBlock(RenderingContext& ctx)
 {
 	const FrustumComponent& fr = *ctx.m_frustumComponent;
-	ShaderCommonUniforms* blk = static_cast<ShaderCommonUniforms*>(getGrManager().allocateFrameTransientMemory(
-		sizeof(ShaderCommonUniforms), BufferUsageBit::UNIFORM_ALL, ctx.m_is.m_commonToken));
+	ShaderCommonUniforms* blk =
+		allocateUniforms<ShaderCommonUniforms*>(sizeof(ShaderCommonUniforms), ctx.m_is.m_commonToken);
 
 	// Start writing
 	blk->m_projectionParams = fr.getProjectionParameters();

+ 9 - 14
src/anki/renderer/Lf.cpp

@@ -139,22 +139,20 @@ void Lf::runOcclusionTests(RenderingContext& ctx, CommandBufferPtr cmdb)
 	const Vec3* initialPositions;
 	if(count)
 	{
-		TransientMemoryToken uniToken, vertToken;
-
 		// Setup MVP UBO
-		Mat4* mvp = static_cast<Mat4*>(
-			getGrManager().allocateFrameTransientMemory(sizeof(Mat4), BufferUsageBit::UNIFORM_ALL, uniToken));
+		Mat4* mvp = allocateAndBindUniforms<Mat4*>(sizeof(Mat4), cmdb, 0, 0);
 		*mvp = camFr.getViewProjectionMatrix();
 
 		// Alloc dyn mem
-		positions = static_cast<Vec3*>(
-			getGrManager().allocateFrameTransientMemory(sizeof(Vec3) * count, BufferUsageBit::VERTEX, vertToken));
+		StagingGpuMemoryToken vertToken;
+		positions = static_cast<Vec3*>(m_r->getStagingGpuMemoryManager().allocatePerFrame(
+			sizeof(Vec3) * count, StagingGpuMemoryType::VERTEX, vertToken));
 		initialPositions = positions;
 
+		cmdb->bindVertexBuffer(0, vertToken.m_buffer, vertToken.m_offset, sizeof(Vec3));
+
 		// Setup state
 		cmdb->bindShaderProgram(m_occlusionProg);
-		cmdb->bindUniformBuffer(0, 0, uniToken);
-		cmdb->bindVertexBuffer(0, vertToken, sizeof(Vec3));
 		cmdb->setVertexAttribute(0, 0, PixelFormat(ComponentFormat::R32G32B32, TransformFormat::FLOAT), 0);
 		cmdb->setColorChannelWriteMask(0, ColorBit::NONE);
 		cmdb->setColorChannelWriteMask(1, ColorBit::NONE);
@@ -215,8 +213,8 @@ void Lf::updateIndirectInfo(RenderingContext& ctx, CommandBufferPtr cmdb)
 
 	// Update the indirect info
 	cmdb->bindShaderProgram(m_updateIndirectBuffProg);
-	cmdb->bindStorageBuffer(0, 0, m_queryResultBuff, 0);
-	cmdb->bindStorageBuffer(0, 1, m_indirectBuff, 0);
+	cmdb->bindStorageBuffer(0, 0, m_queryResultBuff, 0, MAX_PTR_SIZE);
+	cmdb->bindStorageBuffer(0, 1, m_indirectBuff, 0, MAX_PTR_SIZE);
 	cmdb->dispatchCompute(count, 1, 1);
 
 	// Set barrier
@@ -266,9 +264,7 @@ void Lf::run(RenderingContext& ctx, CommandBufferPtr cmdb)
 		U spritesCount = max<U>(1, m_maxSpritesPerFlare);
 
 		// Get uniform memory
-		TransientMemoryToken token;
-		Sprite* tmpSprites = static_cast<Sprite*>(getGrManager().allocateFrameTransientMemory(
-			spritesCount * sizeof(Sprite), BufferUsageBit::UNIFORM_ALL, token));
+		Sprite* tmpSprites = allocateAndBindUniforms<Sprite*>(spritesCount * sizeof(Sprite), cmdb, 0, 0);
 		WeakArray<Sprite> sprites(tmpSprites, spritesCount);
 
 		// misc
@@ -285,7 +281,6 @@ void Lf::run(RenderingContext& ctx, CommandBufferPtr cmdb)
 
 		// Render
 		cmdb->bindTexture(0, 0, lf.getTexture());
-		cmdb->bindUniformBuffer(0, 0, token);
 
 		cmdb->drawArraysIndirect(
 			PrimitiveTopology::TRIANGLE_STRIP, 1, i * sizeof(DrawArraysIndirectInfo), m_indirectBuff);

+ 20 - 20
src/anki/renderer/LightBin.cpp

@@ -343,11 +343,11 @@ LightBin::LightBin(const GenericMemoryPoolAllocator<U8>& alloc,
 	U clusterCountY,
 	U clusterCountZ,
 	ThreadPool* threadPool,
-	GrManager* gr)
+	StagingGpuMemoryManager* stagingMem)
 	: m_alloc(alloc)
 	, m_clusterCount(clusterCountX * clusterCountY * clusterCountZ)
 	, m_threadPool(threadPool)
-	, m_gr(gr)
+	, m_stagingMem(stagingMem)
 	, m_barrier(threadPool->getThreadsCount())
 {
 	m_clusterer.init(alloc, clusterCountX, clusterCountY, clusterCountZ);
@@ -361,12 +361,12 @@ Error LightBin::bin(FrustumComponent& frc,
 	StackAllocator<U8> frameAlloc,
 	U maxLightIndices,
 	Bool shadowsEnabled,
-	TransientMemoryToken& pointLightsToken,
-	TransientMemoryToken& spotLightsToken,
-	TransientMemoryToken* probesToken,
-	TransientMemoryToken& decalsToken,
-	TransientMemoryToken& clustersToken,
-	TransientMemoryToken& lightIndicesToken,
+	StagingGpuMemoryToken& pointLightsToken,
+	StagingGpuMemoryToken& spotLightsToken,
+	StagingGpuMemoryToken* probesToken,
+	StagingGpuMemoryToken& decalsToken,
+	StagingGpuMemoryToken& clustersToken,
+	StagingGpuMemoryToken& lightIndicesToken,
 	TexturePtr& diffuseDecalTexAtlas,
 	TexturePtr& normalRoughnessDecalTexAtlas)
 {
@@ -403,8 +403,8 @@ Error LightBin::bin(FrustumComponent& frc,
 
 	if(visiblePointLightsCount)
 	{
-		ShaderPointLight* data = static_cast<ShaderPointLight*>(m_gr->allocateFrameTransientMemory(
-			sizeof(ShaderPointLight) * visiblePointLightsCount, BufferUsageBit::UNIFORM_ALL, pointLightsToken));
+		ShaderPointLight* data = static_cast<ShaderPointLight*>(m_stagingMem->allocatePerFrame(
+			sizeof(ShaderPointLight) * visiblePointLightsCount, StagingGpuMemoryType::UNIFORM, pointLightsToken));
 
 		ctx.m_pointLights = WeakArray<ShaderPointLight>(data, visiblePointLightsCount);
 
@@ -418,8 +418,8 @@ Error LightBin::bin(FrustumComponent& frc,
 
 	if(visibleSpotLightsCount)
 	{
-		ShaderSpotLight* data = static_cast<ShaderSpotLight*>(m_gr->allocateFrameTransientMemory(
-			sizeof(ShaderSpotLight) * visibleSpotLightsCount, BufferUsageBit::UNIFORM_ALL, spotLightsToken));
+		ShaderSpotLight* data = static_cast<ShaderSpotLight*>(m_stagingMem->allocatePerFrame(
+			sizeof(ShaderSpotLight) * visibleSpotLightsCount, StagingGpuMemoryType::UNIFORM, spotLightsToken));
 
 		ctx.m_spotLights = WeakArray<ShaderSpotLight>(data, visibleSpotLightsCount);
 
@@ -435,8 +435,8 @@ Error LightBin::bin(FrustumComponent& frc,
 	{
 		if(visibleProbeCount)
 		{
-			ShaderProbe* data = static_cast<ShaderProbe*>(m_gr->allocateFrameTransientMemory(
-				sizeof(ShaderProbe) * visibleProbeCount, BufferUsageBit::UNIFORM_ALL, *probesToken));
+			ShaderProbe* data = static_cast<ShaderProbe*>(m_stagingMem->allocatePerFrame(
+				sizeof(ShaderProbe) * visibleProbeCount, StagingGpuMemoryType::UNIFORM, *probesToken));
 
 			ctx.m_probes = WeakArray<ShaderProbe>(data, visibleProbeCount);
 
@@ -451,8 +451,8 @@ Error LightBin::bin(FrustumComponent& frc,
 
 	if(visibleDecalCount)
 	{
-		ShaderDecal* data = static_cast<ShaderDecal*>(m_gr->allocateFrameTransientMemory(
-			sizeof(ShaderDecal) * visibleDecalCount, BufferUsageBit::UNIFORM_ALL, decalsToken));
+		ShaderDecal* data = static_cast<ShaderDecal*>(m_stagingMem->allocatePerFrame(
+			sizeof(ShaderDecal) * visibleDecalCount, StagingGpuMemoryType::UNIFORM, decalsToken));
 
 		ctx.m_decals = WeakArray<ShaderDecal>(data, visibleDecalCount);
 
@@ -466,14 +466,14 @@ Error LightBin::bin(FrustumComponent& frc,
 	ctx.m_bin = this;
 
 	// Get mem for clusters
-	ShaderCluster* data = static_cast<ShaderCluster*>(m_gr->allocateFrameTransientMemory(
-		sizeof(ShaderCluster) * m_clusterCount, BufferUsageBit::STORAGE_ALL, clustersToken));
+	ShaderCluster* data = static_cast<ShaderCluster*>(m_stagingMem->allocatePerFrame(
+		sizeof(ShaderCluster) * m_clusterCount, StagingGpuMemoryType::STORAGE, clustersToken));
 
 	ctx.m_clusters = WeakArray<ShaderCluster>(data, m_clusterCount);
 
 	// Allocate light IDs
-	U32* data2 = static_cast<U32*>(m_gr->allocateFrameTransientMemory(
-		maxLightIndices * sizeof(U32), BufferUsageBit::STORAGE_ALL, lightIndicesToken));
+	U32* data2 = static_cast<U32*>(m_stagingMem->allocatePerFrame(
+		maxLightIndices * sizeof(U32), StagingGpuMemoryType::STORAGE, lightIndicesToken));
 
 	ctx.m_lightIds = WeakArray<U32>(data2, maxLightIndices);
 

+ 8 - 8
src/anki/renderer/LightBin.h

@@ -30,7 +30,7 @@ public:
 		U clusterCountY,
 		U clusterCountZ,
 		ThreadPool* threadPool,
-		GrManager* gr);
+		StagingGpuMemoryManager* stagingMem);
 
 	~LightBin();
 
@@ -38,12 +38,12 @@ public:
 		StackAllocator<U8> frameAlloc,
 		U maxLightIndices,
 		Bool shadowsEnabled,
-		TransientMemoryToken& pointLightsToken,
-		TransientMemoryToken& spotLightsToken,
-		TransientMemoryToken* probesToken,
-		TransientMemoryToken& decalsToken,
-		TransientMemoryToken& clustersToken,
-		TransientMemoryToken& lightIndicesToken,
+		StagingGpuMemoryToken& pointLightsToken,
+		StagingGpuMemoryToken& spotLightsToken,
+		StagingGpuMemoryToken* probesToken,
+		StagingGpuMemoryToken& decalsToken,
+		StagingGpuMemoryToken& clustersToken,
+		StagingGpuMemoryToken& lightIndicesToken,
 		TexturePtr& diffuseDecalTexAtlas,
 		TexturePtr& normalRoughnessDecalTexAtlas);
 
@@ -57,7 +57,7 @@ private:
 	Clusterer m_clusterer;
 	U32 m_clusterCount = 0;
 	ThreadPool* m_threadPool = nullptr;
-	GrManager* m_gr = nullptr;
+	StagingGpuMemoryManager* m_stagingMem = nullptr;
 	Barrier m_barrier;
 
 	void binLights(U32 threadId, PtrSize threadsCount, LightBinContext& ctx);

+ 3 - 1
src/anki/renderer/MainRenderer.cpp

@@ -35,6 +35,7 @@ MainRenderer::~MainRenderer()
 Error MainRenderer::create(ThreadPool* threadpool,
 	ResourceManager* resources,
 	GrManager* gr,
+	StagingGpuMemoryManager* stagingMem,
 	AllocAlignedCallback allocCb,
 	void* allocCbUserData,
 	const ConfigSet& config,
@@ -64,7 +65,8 @@ Error MainRenderer::create(ThreadPool* threadpool,
 	m_rDrawToDefaultFb = m_renderingQuality == 1.0;
 
 	m_r.reset(m_alloc.newInstance<Renderer>());
-	ANKI_CHECK(m_r->init(threadpool, resources, gr, m_alloc, m_frameAlloc, config2, globTimestamp, m_rDrawToDefaultFb));
+	ANKI_CHECK(m_r->init(
+		threadpool, resources, gr, stagingMem, m_alloc, m_frameAlloc, config2, globTimestamp, m_rDrawToDefaultFb));
 
 	// Set the default preprocessor string
 	m_materialShaderSource.sprintf(m_alloc,

+ 2 - 0
src/anki/renderer/MainRenderer.h

@@ -18,6 +18,7 @@ class ConfigSet;
 class SceneGraph;
 class SceneNode;
 class ThreadPool;
+class StagingGpuMemoryManager;
 
 /// @addtogroup renderer
 /// @{
@@ -33,6 +34,7 @@ public:
 	ANKI_USE_RESULT Error create(ThreadPool* threadpool,
 		ResourceManager* resources,
 		GrManager* gl,
+		StagingGpuMemoryManager* stagingMem,
 		AllocAlignedCallback allocCb,
 		void* allocCbUserData,
 		const ConfigSet& config,

+ 1 - 1
src/anki/renderer/Pps.cpp

@@ -151,7 +151,7 @@ Error Pps::run(RenderingContext& ctx)
 		cmdb->bindTexture(0, 4, m_r->getDbg().getRt());
 	}
 
-	cmdb->bindStorageBuffer(0, 0, m_r->getTm().m_luminanceBuff, 0);
+	cmdb->bindStorageBuffer(0, 0, m_r->getTm().m_luminanceBuff, 0, MAX_PTR_SIZE);
 
 	// Get or create FB
 	FramebufferPtr* fb = nullptr;

+ 2 - 0
src/anki/renderer/Renderer.cpp

@@ -64,6 +64,7 @@ Renderer::~Renderer()
 Error Renderer::init(ThreadPool* threadpool,
 	ResourceManager* resources,
 	GrManager* gl,
+	StagingGpuMemoryManager* stagingMem,
 	HeapAllocator<U8> alloc,
 	StackAllocator<U8> frameAlloc,
 	const ConfigSet& config,
@@ -74,6 +75,7 @@ Error Renderer::init(ThreadPool* threadpool,
 	m_threadpool = threadpool;
 	m_resources = resources;
 	m_gr = gl;
+	m_stagingMem = stagingMem;
 	m_alloc = alloc;
 	m_frameAlloc = frameAlloc;
 	m_willDrawToDefaultFbo = willDrawToDefaultFbo;

+ 19 - 10
src/anki/renderer/Renderer.h

@@ -13,6 +13,7 @@
 #include <anki/resource/Forward.h>
 #include <anki/resource/ShaderResource.h>
 #include <anki/core/Timestamp.h>
+#include <anki/core/StagingGpuMemoryManager.h>
 #include <anki/util/ThreadPool.h>
 #include <anki/collision/Forward.h>
 
@@ -22,6 +23,7 @@ namespace anki
 // Forward
 class ConfigSet;
 class ResourceManager;
+class StagingGpuMemoryManager;
 
 /// @addtogroup renderer
 /// @{
@@ -66,13 +68,13 @@ public:
 	class Is
 	{
 	public:
-		TransientMemoryToken m_commonToken;
-		TransientMemoryToken m_pointLightsToken;
-		TransientMemoryToken m_spotLightsToken;
-		TransientMemoryToken m_probesToken;
-		TransientMemoryToken m_decalsToken;
-		TransientMemoryToken m_clustersToken;
-		TransientMemoryToken m_lightIndicesToken;
+		StagingGpuMemoryToken m_commonToken;
+		StagingGpuMemoryToken m_pointLightsToken;
+		StagingGpuMemoryToken m_spotLightsToken;
+		StagingGpuMemoryToken m_probesToken;
+		StagingGpuMemoryToken m_decalsToken;
+		StagingGpuMemoryToken m_clustersToken;
+		StagingGpuMemoryToken m_lightIndicesToken;
 
 		TexturePtr m_diffDecalTex;
 		TexturePtr m_normRoughnessDecalTex;
@@ -227,6 +229,7 @@ public:
 	ANKI_USE_RESULT Error init(ThreadPool* threadpool,
 		ResourceManager* resources,
 		GrManager* gr,
+		StagingGpuMemoryManager* stagingMem,
 		HeapAllocator<U8> alloc,
 		StackAllocator<U8> frameAlloc,
 		const ConfigSet& config,
@@ -310,6 +313,11 @@ anki_internal:
 		return *m_gr;
 	}
 
+	StagingGpuMemoryManager& getStagingGpuMemoryManager()
+	{
+		return *m_stagingMem;
+	}
+
 	HeapAllocator<U8> getAllocator() const
 	{
 		return m_alloc;
@@ -352,9 +360,10 @@ anki_internal:
 	}
 
 private:
-	ThreadPool* m_threadpool;
-	ResourceManager* m_resources;
-	GrManager* m_gr;
+	ThreadPool* m_threadpool = nullptr;
+	ResourceManager* m_resources = nullptr;
+	GrManager* m_gr = nullptr;
+	StagingGpuMemoryManager* m_stagingMem = nullptr;
 	Timestamp* m_globTimestamp;
 	HeapAllocator<U8> m_alloc;
 	StackAllocator<U8> m_frameAlloc;

+ 6 - 0
src/anki/renderer/RenderingPass.cpp

@@ -35,4 +35,10 @@ ResourceManager& RenderingPass::getResourceManager()
 	return m_r->getResourceManager();
 }
 
+void* RenderingPass::allocatePerFrameStagingMemory(
+	PtrSize size, StagingGpuMemoryType usage, StagingGpuMemoryToken& token)
+{
+	return m_r->getStagingGpuMemoryManager().allocatePerFrame(size, usage, token);
+}
+
 } // end namespace anki

+ 40 - 0
src/anki/renderer/RenderingPass.h

@@ -10,6 +10,7 @@
 #include <anki/Gr.h>
 #include <anki/resource/ResourceManager.h>
 #include <anki/resource/ShaderResource.h>
+#include <anki/core/StagingGpuMemoryManager.h>
 
 namespace anki
 {
@@ -39,6 +40,43 @@ anki_internal:
 
 	StackAllocator<U8> getFrameAllocator() const;
 
+	template<typename TPtr>
+	TPtr allocateUniforms(PtrSize size, StagingGpuMemoryToken& token)
+	{
+		return static_cast<TPtr>(allocatePerFrameStagingMemory(size, StagingGpuMemoryType::UNIFORM, token));
+	}
+
+	static void bindUniforms(CommandBufferPtr& cmdb, U set, U binding, const StagingGpuMemoryToken& token)
+	{
+		if(token && !token.isUnused())
+		{
+			cmdb->bindUniformBuffer(set, binding, token.m_buffer, token.m_offset, token.m_range);
+		}
+	}
+
+	template<typename TPtr>
+	TPtr allocateAndBindUniforms(PtrSize size, CommandBufferPtr& cmdb, U set, U binding)
+	{
+		StagingGpuMemoryToken token;
+		TPtr ptr = allocateUniforms<TPtr>(size, token);
+		bindUniforms(cmdb, set, binding, token);
+		return ptr;
+	}
+
+	template<typename TPtr>
+	TPtr allocateStorage(PtrSize size, StagingGpuMemoryToken& token)
+	{
+		return static_cast<TPtr>(allocatePerFrameStagingMemory(size, StagingGpuMemoryType::STORAGE, token));
+	}
+
+	static void bindStorage(CommandBufferPtr& cmdb, U set, U binding, const StagingGpuMemoryToken& token)
+	{
+		if(token && !token.isUnused())
+		{
+			cmdb->bindStorageBuffer(set, binding, token.m_buffer, token.m_offset, token.m_range);
+		}
+	}
+
 protected:
 	Renderer* m_r; ///< Know your father
 
@@ -46,6 +84,8 @@ protected:
 	const GrManager& getGrManager() const;
 
 	ResourceManager& getResourceManager();
+
+	void* allocatePerFrameStagingMemory(PtrSize size, StagingGpuMemoryType usage, StagingGpuMemoryToken& token);
 };
 /// @}
 

+ 12 - 2
src/anki/renderer/Smaa.cpp

@@ -166,9 +166,14 @@ Error SmaaWeights::init(const ConfigSet& initializer)
 		texinit.m_sampling.m_repeat = false;
 		m_areaTex = gr.newInstance<Texture>(texinit);
 
+		StagingGpuMemoryToken token;
+		void* stagingMem = m_r->getStagingGpuMemoryManager().allocatePerFrame(
+			sizeof(areaTexBytes), StagingGpuMemoryType::TRANSFER, token);
+		memcpy(stagingMem, &areaTexBytes[0], sizeof(areaTexBytes));
+
 		const TextureSurfaceInfo surf(0, 0, 0, 0);
 		cmdb->setTextureSurfaceBarrier(m_areaTex, TextureUsageBit::NONE, TextureUsageBit::UPLOAD, surf);
-		cmdb->uploadTextureSurfaceCopyData(m_areaTex, surf, &areaTexBytes[0], sizeof(areaTexBytes));
+		cmdb->copyBufferToTextureSurface(token.m_buffer, token.m_offset, token.m_range, m_areaTex, surf);
 		cmdb->setTextureSurfaceBarrier(m_areaTex, TextureUsageBit::UPLOAD, TextureUsageBit::SAMPLED_FRAGMENT, surf);
 	}
 
@@ -183,9 +188,14 @@ Error SmaaWeights::init(const ConfigSet& initializer)
 		texinit.m_sampling.m_repeat = false;
 		m_searchTex = gr.newInstance<Texture>(texinit);
 
+		StagingGpuMemoryToken token;
+		void* stagingMem = m_r->getStagingGpuMemoryManager().allocatePerFrame(
+			sizeof(searchTexBytes), StagingGpuMemoryType::TRANSFER, token);
+		memcpy(stagingMem, &searchTexBytes[0], sizeof(searchTexBytes));
+
 		const TextureSurfaceInfo surf(0, 0, 0, 0);
 		cmdb->setTextureSurfaceBarrier(m_searchTex, TextureUsageBit::NONE, TextureUsageBit::UPLOAD, surf);
-		cmdb->uploadTextureSurfaceCopyData(m_searchTex, surf, &searchTexBytes[0], sizeof(searchTexBytes));
+		cmdb->copyBufferToTextureSurface(token.m_buffer, token.m_offset, token.m_range, m_searchTex, surf);
 		cmdb->setTextureSurfaceBarrier(m_searchTex, TextureUsageBit::UPLOAD, TextureUsageBit::SAMPLED_FRAGMENT, surf);
 	}
 	cmdb->flush();

+ 8 - 10
src/anki/renderer/Ssao.cpp

@@ -114,18 +114,21 @@ Error Ssao::initInternal(const ConfigSet& config)
 
 	m_noiseTex = gr.newInstance<Texture>(tinit);
 
-	Array<Array<I8, 4>, NOISE_TEX_SIZE * NOISE_TEX_SIZE> noise;
-	genNoise(&noise[0], &noise[0] + noise.getSize());
+	StagingGpuMemoryToken token;
+	const U noiseSize = NOISE_TEX_SIZE * NOISE_TEX_SIZE * sizeof(Array<I8, 4>);
+	Array<I8, 4>* noise = static_cast<Array<I8, 4>*>(
+		m_r->getStagingGpuMemoryManager().allocatePerFrame(noiseSize, StagingGpuMemoryType::TRANSFER, token));
+
+	genNoise(&noise[0], &noise[0] + noiseSize);
 
 	CommandBufferInitInfo cmdbInit;
 	cmdbInit.m_flags = CommandBufferFlag::SMALL_BATCH | CommandBufferFlag::TRANSFER_WORK;
-
 	CommandBufferPtr cmdb = gr.newInstance<CommandBuffer>(cmdbInit);
 
 	TextureSurfaceInfo surf(0, 0, 0, 0);
 
 	cmdb->setTextureSurfaceBarrier(m_noiseTex, TextureUsageBit::NONE, TextureUsageBit::UPLOAD, surf);
-	cmdb->uploadTextureSurfaceCopyData(m_noiseTex, surf, &noise[0], sizeof(noise));
+	cmdb->copyBufferToTextureSurface(token.m_buffer, token.m_offset, token.m_range, m_noiseTex, surf);
 	cmdb->setTextureSurfaceBarrier(m_noiseTex, TextureUsageBit::UPLOAD, TextureUsageBit::SAMPLED_FRAGMENT, surf);
 
 	cmdb->flush();
@@ -241,18 +244,13 @@ void Ssao::run(RenderingContext& ctx)
 	cmdb->bindTexture(0, 1, m_r->getMs().m_rt2);
 	cmdb->bindTexture(0, 2, m_noiseTex);
 
-	TransientMemoryToken token;
-	Vec4* unis = static_cast<Vec4*>(
-		getGrManager().allocateFrameTransientMemory(sizeof(Vec4) * 2, BufferUsageBit::UNIFORM_ALL, token));
-
+	Vec4* unis = allocateAndBindUniforms<Vec4*>(sizeof(Vec4) * 2, cmdb, 0, 0);
 	const FrustumComponent& frc = *ctx.m_frustumComponent;
 	const Mat4& pmat = frc.getProjectionMatrix();
 	*unis = frc.getProjectionParameters();
 	++unis;
 	*unis = Vec4(pmat(0, 0), pmat(1, 1), pmat(2, 2), pmat(2, 3));
 
-	cmdb->bindUniformBuffer(0, 0, token);
-
 	// Draw
 	m_r->drawQuad(cmdb);
 	cmdb->endRenderPass();

+ 6 - 4
src/anki/renderer/Tm.cpp

@@ -47,10 +47,12 @@ Error Tm::initInternal(const ConfigSet& initializer)
 	CommandBufferInitInfo cmdbinit;
 	cmdbinit.m_flags = CommandBufferFlag::SMALL_BATCH | CommandBufferFlag::TRANSFER_WORK;
 	CommandBufferPtr cmdb = getGrManager().newInstance<CommandBuffer>(cmdbinit);
-	TransientMemoryToken token;
-	void* data = getGrManager().allocateFrameTransientMemory(sizeof(Vec4), BufferUsageBit::BUFFER_UPLOAD_SOURCE, token);
+
+	StagingGpuMemoryToken token;
+	void* data =
+		m_r->getStagingGpuMemoryManager().allocatePerFrame(sizeof(Vec4), StagingGpuMemoryType::TRANSFER, token);
 	*static_cast<Vec4*>(data) = Vec4(0.5);
-	cmdb->uploadBuffer(m_luminanceBuff, 0, token);
+	cmdb->copyBufferToBuffer(token.m_buffer, token.m_offset, m_luminanceBuff, 0, token.m_range);
 	cmdb->flush();
 
 	return ErrorCode::NONE;
@@ -60,7 +62,7 @@ void Tm::run(RenderingContext& ctx)
 {
 	CommandBufferPtr& cmdb = ctx.m_commandBuffer;
 	cmdb->bindShaderProgram(m_prog);
-	cmdb->bindStorageBuffer(0, 0, m_luminanceBuff, 0);
+	cmdb->bindStorageBuffer(0, 0, m_luminanceBuff, 0, MAX_PTR_SIZE);
 	cmdb->bindTexture(0, 0, m_r->getIs().getRt());
 
 	cmdb->dispatchCompute(1, 1, 1);

+ 9 - 14
src/anki/renderer/Volumetric.cpp

@@ -92,14 +92,6 @@ void Volumetric::run(RenderingContext& ctx)
 	CommandBufferPtr& cmdb = ctx.m_commandBuffer;
 	const Frustum& frc = ctx.m_frustumComponent->getFrustum();
 
-	// Update uniforms
-	TransientMemoryToken token;
-	Vec4* uniforms = static_cast<Vec4*>(
-		getGrManager().allocateFrameTransientMemory(sizeof(Vec4) * 2, BufferUsageBit::UNIFORM_ALL, token));
-	computeLinearizeDepthOptimal(frc.getNear(), frc.getFar(), uniforms[0].x(), uniforms[0].y());
-
-	uniforms[1] = Vec4(m_fogColor, m_fogFactor);
-
 	// pass
 	cmdb->setViewport(0, 0, m_r->getWidth() / VOLUMETRIC_FRACTION, m_r->getHeight() / VOLUMETRIC_FRACTION);
 	cmdb->setBlendFactors(0, BlendFactor::SRC_ALPHA, BlendFactor::ONE_MINUS_SRC_ALPHA);
@@ -108,13 +100,16 @@ void Volumetric::run(RenderingContext& ctx)
 	cmdb->bindTexture(0, 1, m_r->getSm().m_spotTexArray);
 	cmdb->bindTexture(0, 2, m_r->getSm().m_omniTexArray);
 
-	cmdb->bindUniformBuffer(0, 0, ctx.m_is.m_commonToken);
-	cmdb->bindUniformBuffer(0, 1, ctx.m_is.m_pointLightsToken);
-	cmdb->bindUniformBuffer(0, 2, ctx.m_is.m_spotLightsToken);
-	cmdb->bindUniformBuffer(0, 3, token);
+	bindUniforms(cmdb, 0, 0, ctx.m_is.m_commonToken);
+	bindUniforms(cmdb, 0, 1, ctx.m_is.m_pointLightsToken);
+	bindUniforms(cmdb, 0, 2, ctx.m_is.m_spotLightsToken);
+
+	Vec4* uniforms = allocateAndBindUniforms<Vec4*>(sizeof(Vec4) * 2, cmdb, 0, 3);
+	computeLinearizeDepthOptimal(frc.getNear(), frc.getFar(), uniforms[0].x(), uniforms[0].y());
+	uniforms[1] = Vec4(m_fogColor, m_fogFactor);
 
-	cmdb->bindStorageBuffer(0, 0, ctx.m_is.m_clustersToken);
-	cmdb->bindStorageBuffer(0, 1, ctx.m_is.m_lightIndicesToken);
+	bindStorage(cmdb, 0, 0, ctx.m_is.m_clustersToken);
+	bindStorage(cmdb, 0, 1, ctx.m_is.m_lightIndicesToken);
 
 	cmdb->bindShaderProgram(m_prog);
 

+ 9 - 8
src/anki/resource/Mesh.cpp

@@ -9,6 +9,7 @@
 #include <anki/resource/AsyncLoader.h>
 #include <anki/util/Functions.h>
 #include <anki/misc/Xml.h>
+#include <anki/core/StagingGpuMemoryManager.h>
 
 namespace anki
 {
@@ -34,14 +35,15 @@ public:
 Error MeshLoadTask::operator()(AsyncLoaderTaskContext& ctx)
 {
 	GrManager& gr = m_manager->getGrManager();
+	StagingGpuMemoryManager& stagingMem = m_manager->getStagingGpuMemoryManager();
 	CommandBufferPtr cmdb;
 
 	// Write vert buff
 	if(m_vertBuff)
 	{
-		TransientMemoryToken token;
-		void* data = gr.tryAllocateFrameTransientMemory(
-			m_loader.getVertexDataSize(), BufferUsageBit::BUFFER_UPLOAD_SOURCE, token);
+		StagingGpuMemoryToken token;
+		void* data =
+			stagingMem.tryAllocatePerFrame(m_loader.getVertexDataSize(), StagingGpuMemoryType::TRANSFER, token);
 
 		if(data)
 		{
@@ -51,7 +53,7 @@ Error MeshLoadTask::operator()(AsyncLoaderTaskContext& ctx)
 			cmdb->setBufferBarrier(
 				m_vertBuff, BufferUsageBit::VERTEX, BufferUsageBit::BUFFER_UPLOAD_DESTINATION, 0, MAX_PTR_SIZE);
 
-			cmdb->uploadBuffer(m_vertBuff, 0, token);
+			cmdb->copyBufferToBuffer(token.m_buffer, token.m_offset, m_vertBuff, 0, token.m_range);
 
 			cmdb->setBufferBarrier(
 				m_vertBuff, BufferUsageBit::BUFFER_UPLOAD_DESTINATION, BufferUsageBit::VERTEX, 0, MAX_PTR_SIZE);
@@ -68,9 +70,8 @@ Error MeshLoadTask::operator()(AsyncLoaderTaskContext& ctx)
 
 	// Create index buffer
 	{
-		TransientMemoryToken token;
-		void* data = gr.tryAllocateFrameTransientMemory(
-			m_loader.getIndexDataSize(), BufferUsageBit::BUFFER_UPLOAD_SOURCE, token);
+		StagingGpuMemoryToken token;
+		void* data = stagingMem.tryAllocatePerFrame(m_loader.getIndexDataSize(), StagingGpuMemoryType::TRANSFER, token);
 
 		if(data)
 		{
@@ -84,7 +85,7 @@ Error MeshLoadTask::operator()(AsyncLoaderTaskContext& ctx)
 			cmdb->setBufferBarrier(
 				m_indicesBuff, BufferUsageBit::INDEX, BufferUsageBit::BUFFER_UPLOAD_DESTINATION, 0, MAX_PTR_SIZE);
 
-			cmdb->uploadBuffer(m_indicesBuff, 0, token);
+			cmdb->copyBufferToBuffer(token.m_buffer, token.m_offset, m_indicesBuff, 0, token.m_range);
 
 			cmdb->setBufferBarrier(
 				m_indicesBuff, BufferUsageBit::BUFFER_UPLOAD_DESTINATION, BufferUsageBit::INDEX, 0, MAX_PTR_SIZE);

+ 1 - 0
src/anki/resource/ResourceManager.cpp

@@ -36,6 +36,7 @@ ResourceManager::~ResourceManager()
 Error ResourceManager::create(ResourceManagerInitInfo& init)
 {
 	m_gr = init.m_gr;
+	m_stagingMem = init.m_stagingMem;
 	m_physics = init.m_physics;
 	m_fs = init.m_resourceFs;
 	m_alloc = ResourceAllocator<U8>(init.m_allocCallback, init.m_allocCallbackData);

+ 9 - 0
src/anki/resource/ResourceManager.h

@@ -21,6 +21,7 @@ class ResourceManager;
 class AsyncLoader;
 class ResourceManagerModel;
 class Renderer;
+class StagingGpuMemoryManager;
 
 /// @addtogroup resource
 /// @{
@@ -92,6 +93,7 @@ class ResourceManagerInitInfo
 {
 public:
 	GrManager* m_gr = nullptr;
+	StagingGpuMemoryManager* m_stagingMem = nullptr;
 	PhysicsWorld* m_physics = nullptr;
 	ResourceFilesystem* m_resourceFs = nullptr;
 	const ConfigSet* m_config = nullptr;
@@ -160,6 +162,12 @@ anki_internal:
 		return *m_gr;
 	}
 
+	StagingGpuMemoryManager& getStagingGpuMemoryManager()
+	{
+		ANKI_ASSERT(m_stagingMem);
+		return *m_stagingMem;
+	}
+
 	PhysicsWorld& getPhysicsWorld()
 	{
 		ANKI_ASSERT(m_physics);
@@ -222,6 +230,7 @@ anki_internal:
 
 private:
 	GrManager* m_gr = nullptr;
+	StagingGpuMemoryManager* m_stagingMem = nullptr;
 	PhysicsWorld* m_physics = nullptr;
 	ResourceFilesystem* m_fs = nullptr;
 	ResourceAllocator<U8> m_alloc;

+ 7 - 5
src/anki/resource/TextureResource.cpp

@@ -7,6 +7,7 @@
 #include <anki/resource/ImageLoader.h>
 #include <anki/resource/ResourceManager.h>
 #include <anki/resource/AsyncLoader.h>
+#include <anki/core/StagingGpuMemoryManager.h>
 
 namespace anki
 {
@@ -18,6 +19,7 @@ public:
 	ImageLoader m_loader;
 	TexturePtr m_tex;
 	GrManager* m_gr ANKI_DBG_NULLIFY_PTR;
+	StagingGpuMemoryManager* m_stagingMem ANKI_DBG_NULLIFY_PTR;
 	U m_layers = 0;
 	U m_faces = 0;
 	TextureType m_texType;
@@ -52,7 +54,6 @@ Error TexUploadTask::operator()(AsyncLoaderTaskContext& ctx)
 				PtrSize surfOrVolSize;
 				const void* surfOrVolData;
 				PtrSize allocationSize;
-				const BufferUsageBit uploadBuffUsage = BufferUsageBit::TEXTURE_UPLOAD_SOURCE;
 
 				if(m_texType == TextureType::_3D)
 				{
@@ -73,8 +74,8 @@ Error TexUploadTask::operator()(AsyncLoaderTaskContext& ctx)
 
 				ANKI_ASSERT(allocationSize >= surfOrVolSize);
 
-				TransientMemoryToken token;
-				void* data = m_gr->tryAllocateFrameTransientMemory(allocationSize, uploadBuffUsage, token);
+				StagingGpuMemoryToken token;
+				void* data = m_stagingMem->tryAllocatePerFrame(allocationSize, StagingGpuMemoryType::TRANSFER, token);
 
 				if(data)
 				{
@@ -96,7 +97,7 @@ Error TexUploadTask::operator()(AsyncLoaderTaskContext& ctx)
 
 						cmdb->setTextureVolumeBarrier(m_tex, TextureUsageBit::NONE, TextureUsageBit::UPLOAD, vol);
 
-						cmdb->uploadTextureVolume(m_tex, vol, token);
+						cmdb->copyBufferToTextureVolume(token.m_buffer, token.m_offset, token.m_range, m_tex, vol);
 
 						cmdb->setTextureVolumeBarrier(m_tex,
 							TextureUsageBit::UPLOAD,
@@ -109,7 +110,7 @@ Error TexUploadTask::operator()(AsyncLoaderTaskContext& ctx)
 
 						cmdb->setTextureSurfaceBarrier(m_tex, TextureUsageBit::NONE, TextureUsageBit::UPLOAD, surf);
 
-						cmdb->uploadTextureSurface(m_tex, surf, token);
+						cmdb->copyBufferToTextureSurface(token.m_buffer, token.m_offset, token.m_range, m_tex, surf);
 
 						cmdb->setTextureSurfaceBarrier(m_tex,
 							TextureUsageBit::UPLOAD,
@@ -271,6 +272,7 @@ Error TextureResource::load(const ResourceFilename& filename)
 	task->m_layers = init.m_layerCount;
 	task->m_faces = faces;
 	task->m_gr = &getManager().getGrManager();
+	task->m_stagingMem = &getManager().getStagingGpuMemoryManager();
 	task->m_tex = m_tex;
 	task->m_texType = init.m_type;
 

+ 2 - 2
src/anki/scene/ParticleEmitter.cpp

@@ -375,8 +375,8 @@ Error ParticleEmitter::frameUpdate(F32 prevUpdateTime, F32 crntTime)
 	Vec4 aabbmax(MIN_F32, MIN_F32, MIN_F32, 0.0);
 	m_aliveParticlesCount = 0;
 
-	F32* verts = static_cast<F32*>(getResourceManager().getGrManager().allocateFrameTransientMemory(
-		m_vertBuffSize, BufferUsageBit::VERTEX, m_vertBuffToken));
+	F32* verts = static_cast<F32*>(getResourceManager().getStagingGpuMemoryManager().allocatePerFrame(
+		m_vertBuffSize, StagingGpuMemoryType::VERTEX, m_vertBuffToken));
 
 	const F32* verts_base = verts;
 	(void)verts_base;

+ 1 - 1
src/anki/scene/ParticleEmitter.h

@@ -190,7 +190,7 @@ private:
 	/// @name Graphics
 	/// @{
 	U32 m_vertBuffSize = 0;
-	TransientMemoryToken m_vertBuffToken;
+	StagingGpuMemoryToken m_vertBuffToken;
 	/// @}
 
 	SimulationType m_simulationType = SimulationType::UNDEFINED;

+ 3 - 2
src/anki/scene/RenderComponent.h

@@ -10,6 +10,7 @@
 #include <anki/resource/Material.h>
 #include <anki/resource/Model.h>
 #include <anki/util/HashMap.h>
+#include <anki/core/StagingGpuMemoryManager.h>
 
 namespace anki
 {
@@ -115,7 +116,7 @@ public:
 class RenderingVertexBufferBinding : public VertexBufferBinding
 {
 public:
-	TransientMemoryToken m_token;
+	StagingGpuMemoryToken m_token;
 
 	Bool operator==(const RenderingVertexBufferBinding& b) const
 	{
@@ -152,7 +153,7 @@ public:
 	U32 m_vertexAttributeCount;
 
 	BufferPtr m_indexBuffer;
-	TransientMemoryToken m_indexBufferToken;
+	StagingGpuMemoryToken m_indexBufferToken;
 
 	union A
 	{

+ 0 - 1
src/anki/scene/SceneGraph.cpp

@@ -11,7 +11,6 @@
 #include <anki/physics/PhysicsWorld.h>
 #include <anki/resource/ResourceManager.h>
 #include <anki/renderer/MainRenderer.h>
-#include <anki/renderer/Renderer.h>
 #include <anki/misc/ConfigSet.h>
 #include <anki/util/ThreadPool.h>
 

+ 0 - 1
src/anki/scene/Sector.cpp

@@ -12,7 +12,6 @@
 #include <anki/util/Logger.h>
 #include <anki/resource/ResourceManager.h>
 #include <anki/resource/MeshLoader.h>
-#include <anki/renderer/Renderer.h>
 
 namespace anki
 {

+ 2 - 0
src/anki/ui/UiInterfaceImpl.cpp

@@ -167,6 +167,7 @@ Error UiInterfaceImpl::loadImage(const CString& filename, IntrusivePtr<UiImage>&
 
 Error UiInterfaceImpl::createR8Image(const WeakArray<U8>& data, const UVec2& size, IntrusivePtr<UiImage>& img)
 {
+#if 0
 	ANKI_ASSERT(data.getSize() == size.x() * size.y());
 
 	// Calc mip count
@@ -204,6 +205,7 @@ Error UiInterfaceImpl::createR8Image(const WeakArray<U8>& data, const UVec2& siz
 	UiImageImpl* impl = getAllocator().newInstance<UiImageImpl>(this);
 	impl->m_texture = tex;
 	img.reset(impl);
+#endif
 
 	return ErrorCode::NONE;
 }