Browse Source

Some refactoring

Panagiotis Christopoulos Charitos 9 years ago
parent
commit
8df65f2bf2

+ 1 - 1
sandbox/Main.cpp

@@ -10,7 +10,7 @@
 
 
 using namespace anki;
 using namespace anki;
 
 
-#define PLAYER 1
+#define PLAYER 0
 #define MOUSE 1
 #define MOUSE 1
 
 
 class MyApp : public App
 class MyApp : public App

+ 1 - 1
shaders/Pps.frag.glsl

@@ -144,7 +144,7 @@ void main()
 	out_color += bloom;
 	out_color += bloom;
 #endif
 #endif
 
 
-// out_color = colorGrading(out_color);
+	out_color = colorGrading(out_color);
 
 
 #if 0
 #if 0
 	{
 	{

+ 5 - 5
src/anki/gr/common/GpuFrameRingAllocator.cpp → src/anki/gr/common/FrameGpuAllocator.cpp

@@ -3,12 +3,12 @@
 // Code licensed under the BSD License.
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 // http://www.anki3d.org/LICENSE
 
 
-#include <anki/gr/common/GpuFrameRingAllocator.h>
+#include <anki/gr/common/FrameGpuAllocator.h>
 
 
 namespace anki
 namespace anki
 {
 {
 
 
-void GpuFrameRingAllocator::init(PtrSize size, U32 alignment, PtrSize maxAllocationSize)
+void FrameGpuAllocator::init(PtrSize size, U32 alignment, PtrSize maxAllocationSize)
 {
 {
 	ANKI_ASSERT(!isCreated());
 	ANKI_ASSERT(!isCreated());
 	ANKI_ASSERT(size > 0 && alignment > 0 && maxAllocationSize > 0);
 	ANKI_ASSERT(size > 0 && alignment > 0 && maxAllocationSize > 0);
@@ -21,7 +21,7 @@ void GpuFrameRingAllocator::init(PtrSize size, U32 alignment, PtrSize maxAllocat
 	m_maxAllocationSize = maxAllocationSize;
 	m_maxAllocationSize = maxAllocationSize;
 }
 }
 
 
-PtrSize GpuFrameRingAllocator::endFrame()
+PtrSize FrameGpuAllocator::endFrame()
 {
 {
 	ANKI_ASSERT(isCreated());
 	ANKI_ASSERT(isCreated());
 
 
@@ -41,7 +41,7 @@ PtrSize GpuFrameRingAllocator::endFrame()
 	return bytesNotUsed;
 	return bytesNotUsed;
 }
 }
 
 
-Error GpuFrameRingAllocator::allocate(PtrSize originalSize, PtrSize& outOffset)
+Error FrameGpuAllocator::allocate(PtrSize originalSize, PtrSize& outOffset)
 {
 {
 	ANKI_ASSERT(isCreated());
 	ANKI_ASSERT(isCreated());
 	ANKI_ASSERT(originalSize > 0);
 	ANKI_ASSERT(originalSize > 0);
@@ -79,7 +79,7 @@ Error GpuFrameRingAllocator::allocate(PtrSize originalSize, PtrSize& outOffset)
 }
 }
 
 
 #if ANKI_ENABLE_TRACE
 #if ANKI_ENABLE_TRACE
-PtrSize GpuFrameRingAllocator::getUnallocatedMemorySize() const
+PtrSize FrameGpuAllocator::getUnallocatedMemorySize() const
 {
 {
 	PtrSize perFrameSize = m_size / MAX_FRAMES_IN_FLIGHT;
 	PtrSize perFrameSize = m_size / MAX_FRAMES_IN_FLIGHT;
 	PtrSize crntFrameStartOffset = perFrameSize * (m_frame % MAX_FRAMES_IN_FLIGHT);
 	PtrSize crntFrameStartOffset = perFrameSize * (m_frame % MAX_FRAMES_IN_FLIGHT);

+ 3 - 3
src/anki/gr/common/GpuFrameRingAllocator.h → src/anki/gr/common/FrameGpuAllocator.h

@@ -14,16 +14,16 @@ namespace anki
 /// @{
 /// @{
 
 
 /// Manages pre-allocated GPU memory for per frame usage.
 /// Manages pre-allocated GPU memory for per frame usage.
-class GpuFrameRingAllocator : public NonCopyable
+class FrameGpuAllocator : public NonCopyable
 {
 {
 	friend class DynamicMemorySerializeCommand;
 	friend class DynamicMemorySerializeCommand;
 
 
 public:
 public:
-	GpuFrameRingAllocator()
+	FrameGpuAllocator()
 	{
 	{
 	}
 	}
 
 
-	~GpuFrameRingAllocator()
+	~FrameGpuAllocator()
 	{
 	{
 	}
 	}
 
 

+ 7 - 11
src/anki/gr/common/StackGpuAllocator.h

@@ -54,23 +54,13 @@ public:
 	{
 	{
 		return m_memory != nullptr;
 		return m_memory != nullptr;
 	}
 	}
-
-private:
-	StackGpuAllocatorChunk* m_chunk = nullptr;
-
-	Bool valid() const
-	{
-		return (m_memory && m_chunk) || (m_memory == nullptr && m_chunk == nullptr);
-	}
 };
 };
 
 
 /// Linear based allocator.
 /// Linear based allocator.
 class StackGpuAllocator : public NonCopyable
 class StackGpuAllocator : public NonCopyable
 {
 {
 public:
 public:
-	StackGpuAllocator()
-	{
-	}
+	StackGpuAllocator() = default;
 
 
 	~StackGpuAllocator();
 	~StackGpuAllocator();
 
 
@@ -82,6 +72,12 @@ public:
 	/// Reset all the memory chunks. Not thread safe.
 	/// Reset all the memory chunks. Not thread safe.
 	void reset();
 	void reset();
 
 
+	StackGpuAllocatorInterface* getInterface() const
+	{
+		ANKI_ASSERT(m_iface);
+		return m_iface;
+	}
+
 private:
 private:
 	using Chunk = StackGpuAllocatorChunk;
 	using Chunk = StackGpuAllocatorChunk;
 
 

+ 3 - 3
src/anki/gr/gl/BufferImpl.h

@@ -46,12 +46,12 @@ public:
 		glBindBufferRange(target, binding, m_glName, offset, size);
 		glBindBufferRange(target, binding, m_glName, offset, size);
 	}
 	}
 
 
-	void write(const void* buff, U32 offset, U32 size) const
+	void write(GLuint pbo, U32 pboOffset, U32 offset, U32 size) const
 	{
 	{
 		ANKI_ASSERT(isCreated());
 		ANKI_ASSERT(isCreated());
 		ANKI_ASSERT(offset + size <= m_size);
 		ANKI_ASSERT(offset + size <= m_size);
-		glBindBuffer(m_target, m_glName);
-		glBufferSubData(m_target, offset, size, buff);
+
+		glCopyNamedBufferSubData(pbo, m_glName, pboOffset, offset, size);
 	}
 	}
 
 
 	void fill(PtrSize offset, PtrSize size, U32 value)
 	void fill(PtrSize offset, PtrSize size, U32 value)

+ 6 - 12
src/anki/gr/gl/CommandBuffer.cpp

@@ -318,10 +318,8 @@ void CommandBuffer::uploadTextureSurface(
 
 
 		Error operator()(GlState& state)
 		Error operator()(GlState& state)
 		{
 		{
-			void* data = state.m_manager->getImplementation().getTransientMemoryManager().getBaseAddress(m_token);
-			data = static_cast<void*>(static_cast<U8*>(data) + m_token.m_offset);
-
-			m_handle->m_impl->writeSurface(m_surf, data, m_token.m_range);
+			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)
 			if(m_token.m_lifetime == TransientMemoryTokenLifetime::PERSISTENT)
 			{
 			{
@@ -357,10 +355,8 @@ void CommandBuffer::uploadTextureVolume(TexturePtr tex, const TextureVolumeInfo&
 
 
 		Error operator()(GlState& state)
 		Error operator()(GlState& state)
 		{
 		{
-			void* data = state.m_manager->getImplementation().getTransientMemoryManager().getBaseAddress(m_token);
-			data = static_cast<void*>(static_cast<U8*>(data) + m_token.m_offset);
-
-			m_handle->m_impl->writeVolume(m_vol, data, m_token.m_range);
+			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)
 			if(m_token.m_lifetime == TransientMemoryTokenLifetime::PERSISTENT)
 			{
 			{
@@ -396,10 +392,8 @@ void CommandBuffer::uploadBuffer(BufferPtr buff, PtrSize offset, const Transient
 
 
 		Error operator()(GlState& state)
 		Error operator()(GlState& state)
 		{
 		{
-			void* data = state.m_manager->getImplementation().getTransientMemoryManager().getBaseAddress(m_token);
-			data = static_cast<void*>(static_cast<U8*>(data) + m_token.m_offset);
-
-			m_handle->m_impl->write(data, m_offset, m_token.m_range);
+			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)
 			if(m_token.m_lifetime == TransientMemoryTokenLifetime::PERSISTENT)
 			{
 			{

+ 16 - 12
src/anki/gr/gl/TextureImpl.cpp

@@ -462,10 +462,9 @@ void TextureImpl::init(const TextureInitInfo& init)
 	ANKI_CHECK_GL_ERROR();
 	ANKI_CHECK_GL_ERROR();
 }
 }
 
 
-void TextureImpl::writeSurface(const TextureSurfaceInfo& surf, void* data, PtrSize dataSize)
+void TextureImpl::writeSurface(const TextureSurfaceInfo& surf, GLuint pbo, PtrSize offset, PtrSize dataSize)
 {
 {
 	checkSurface(surf);
 	checkSurface(surf);
-	ANKI_ASSERT(data);
 	ANKI_ASSERT(dataSize > 0);
 	ANKI_ASSERT(dataSize > 0);
 
 
 	U mipmap = surf.m_level;
 	U mipmap = surf.m_level;
@@ -476,52 +475,54 @@ void TextureImpl::writeSurface(const TextureSurfaceInfo& surf, void* data, PtrSi
 	ANKI_ASSERT(h > 0);
 	ANKI_ASSERT(h > 0);
 
 
 	bind();
 	bind();
+	glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
+	const void* ptrOffset = numberToPtr<const void*>(offset);
 
 
 	switch(m_target)
 	switch(m_target)
 	{
 	{
 	case GL_TEXTURE_2D:
 	case GL_TEXTURE_2D:
 		if(!m_compressed)
 		if(!m_compressed)
 		{
 		{
-			glTexSubImage2D(m_target, mipmap, 0, 0, w, h, m_format, m_type, data);
+			glTexSubImage2D(m_target, mipmap, 0, 0, w, h, m_format, m_type, ptrOffset);
 		}
 		}
 		else
 		else
 		{
 		{
-			glCompressedTexSubImage2D(m_target, mipmap, 0, 0, w, h, m_format, dataSize, data);
+			glCompressedTexSubImage2D(m_target, mipmap, 0, 0, w, h, m_format, dataSize, ptrOffset);
 		}
 		}
 		break;
 		break;
 	case GL_TEXTURE_CUBE_MAP:
 	case GL_TEXTURE_CUBE_MAP:
 		if(!m_compressed)
 		if(!m_compressed)
 		{
 		{
-			glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + surfIdx, mipmap, 0, 0, w, h, m_format, m_type, data);
+			glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + surfIdx, mipmap, 0, 0, w, h, m_format, m_type, ptrOffset);
 		}
 		}
 		else
 		else
 		{
 		{
 			glCompressedTexSubImage2D(
 			glCompressedTexSubImage2D(
-				GL_TEXTURE_CUBE_MAP_POSITIVE_X + surfIdx, mipmap, 0, 0, w, h, m_format, dataSize, data);
+				GL_TEXTURE_CUBE_MAP_POSITIVE_X + surfIdx, mipmap, 0, 0, w, h, m_format, dataSize, ptrOffset);
 		}
 		}
 		break;
 		break;
 	case GL_TEXTURE_2D_ARRAY:
 	case GL_TEXTURE_2D_ARRAY:
 	case GL_TEXTURE_3D:
 	case GL_TEXTURE_3D:
 		if(!m_compressed)
 		if(!m_compressed)
 		{
 		{
-			glTexSubImage3D(m_target, mipmap, 0, 0, surfIdx, w, h, 1, m_format, m_type, data);
+			glTexSubImage3D(m_target, mipmap, 0, 0, surfIdx, w, h, 1, m_format, m_type, ptrOffset);
 		}
 		}
 		else
 		else
 		{
 		{
-			glCompressedTexSubImage3D(m_target, mipmap, 0, 0, surfIdx, w, h, 1, m_format, dataSize, data);
+			glCompressedTexSubImage3D(m_target, mipmap, 0, 0, surfIdx, w, h, 1, m_format, dataSize, ptrOffset);
 		}
 		}
 		break;
 		break;
 	default:
 	default:
 		ANKI_ASSERT(0);
 		ANKI_ASSERT(0);
 	}
 	}
 
 
+	glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
 	ANKI_CHECK_GL_ERROR();
 	ANKI_CHECK_GL_ERROR();
 }
 }
 
 
-void TextureImpl::writeVolume(const TextureVolumeInfo& vol, void* data, PtrSize dataSize)
+void TextureImpl::writeVolume(const TextureVolumeInfo& vol, GLuint pbo, PtrSize offset, PtrSize dataSize)
 {
 {
 	checkVolume(vol);
 	checkVolume(vol);
-	ANKI_ASSERT(data);
 	ANKI_ASSERT(dataSize > 0);
 	ANKI_ASSERT(dataSize > 0);
 	ANKI_ASSERT(m_texType == TextureType::_3D);
 	ANKI_ASSERT(m_texType == TextureType::_3D);
 
 
@@ -534,16 +535,19 @@ void TextureImpl::writeVolume(const TextureVolumeInfo& vol, void* data, PtrSize
 	ANKI_ASSERT(d > 0);
 	ANKI_ASSERT(d > 0);
 
 
 	bind();
 	bind();
+	glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
+	const void* ptrOffset = numberToPtr<const void*>(offset);
 
 
 	if(!m_compressed)
 	if(!m_compressed)
 	{
 	{
-		glTexSubImage3D(m_target, mipmap, 0, 0, 0, w, h, d, m_format, m_type, data);
+		glTexSubImage3D(m_target, mipmap, 0, 0, 0, w, h, d, m_format, m_type, ptrOffset);
 	}
 	}
 	else
 	else
 	{
 	{
-		glCompressedTexSubImage3D(m_target, mipmap, 0, 0, 0, w, h, d, m_format, dataSize, data);
+		glCompressedTexSubImage3D(m_target, mipmap, 0, 0, 0, w, h, d, m_format, dataSize, ptrOffset);
 	}
 	}
 
 
+	glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
 	ANKI_CHECK_GL_ERROR();
 	ANKI_CHECK_GL_ERROR();
 }
 }
 
 

+ 2 - 2
src/anki/gr/gl/TextureImpl.h

@@ -61,10 +61,10 @@ public:
 	void init(const TextureInitInfo& init);
 	void init(const TextureInitInfo& init);
 
 
 	/// Write texture data.
 	/// Write texture data.
-	void writeSurface(const TextureSurfaceInfo& surf, void* data, PtrSize dataSize);
+	void writeSurface(const TextureSurfaceInfo& surf, GLuint pbo, PtrSize offset, PtrSize dataSize);
 
 
 	/// Write texture data.
 	/// Write texture data.
-	void writeVolume(const TextureVolumeInfo& vol, void* data, PtrSize dataSize);
+	void writeVolume(const TextureVolumeInfo& vol, GLuint pbo, PtrSize offset, PtrSize dataSize);
 
 
 	/// Generate mipmaps.
 	/// Generate mipmaps.
 	void generateMipmaps2d(U face, U layer);
 	void generateMipmaps2d(U face, U layer);

+ 23 - 55
src/anki/gr/gl/TransientMemoryManager.cpp

@@ -29,8 +29,6 @@ void TransientMemoryManager::destroyRenderThread()
 			glDeleteBuffers(1, &buff.m_name);
 			glDeleteBuffers(1, &buff.m_name);
 			buff.m_name = 0;
 			buff.m_name = 0;
 		}
 		}
-
-		buff.m_cpuBuff.destroy(m_alloc);
 	}
 	}
 }
 }
 
 
@@ -39,82 +37,52 @@ void TransientMemoryManager::initMainThread(GenericMemoryPoolAllocator<U8> alloc
 	m_alloc = alloc;
 	m_alloc = alloc;
 
 
 	m_perFrameBuffers[TransientBufferType::UNIFORM].m_size = cfg.getNumber("gr.uniformPerFrameMemorySize");
 	m_perFrameBuffers[TransientBufferType::UNIFORM].m_size = cfg.getNumber("gr.uniformPerFrameMemorySize");
-
 	m_perFrameBuffers[TransientBufferType::STORAGE].m_size = cfg.getNumber("gr.storagePerFrameMemorySize");
 	m_perFrameBuffers[TransientBufferType::STORAGE].m_size = cfg.getNumber("gr.storagePerFrameMemorySize");
-
 	m_perFrameBuffers[TransientBufferType::VERTEX].m_size = cfg.getNumber("gr.vertexPerFrameMemorySize");
 	m_perFrameBuffers[TransientBufferType::VERTEX].m_size = cfg.getNumber("gr.vertexPerFrameMemorySize");
-
 	m_perFrameBuffers[TransientBufferType::TRANSFER].m_size = cfg.getNumber("gr.transferPerFrameMemorySize");
 	m_perFrameBuffers[TransientBufferType::TRANSFER].m_size = cfg.getNumber("gr.transferPerFrameMemorySize");
 }
 }
 
 
-void TransientMemoryManager::initRenderThread()
+void TransientMemoryManager::initBuffer(TransientBufferType type, U32 alignment, PtrSize maxAllocSize, GLenum target)
 {
 {
 	const U BUFF_FLAGS = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT;
 	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
 	// Uniform
 	{
 	{
-		// Create buffer
-		PerFrameBuffer& buff = m_perFrameBuffers[TransientBufferType::UNIFORM];
-		PtrSize size = buff.m_size;
-		glGenBuffers(1, &buff.m_name);
-		glBindBuffer(GL_UNIFORM_BUFFER, buff.m_name);
-
-		// Map it
-		glBufferStorage(GL_UNIFORM_BUFFER, size, nullptr, BUFF_FLAGS);
-		buff.m_mappedMem = static_cast<U8*>(glMapBufferRange(GL_UNIFORM_BUFFER, 0, size, BUFF_FLAGS));
-		ANKI_ASSERT(buff.m_mappedMem);
-
-		// Create the allocator
 		GLint64 blockAlignment;
 		GLint64 blockAlignment;
 		glGetInteger64v(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &blockAlignment);
 		glGetInteger64v(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &blockAlignment);
-		buff.m_alloc.init(size, blockAlignment, MAX_UNIFORM_BLOCK_SIZE);
+		initBuffer(TransientBufferType::UNIFORM, blockAlignment, MAX_UNIFORM_BLOCK_SIZE, GL_UNIFORM_BUFFER);
 	}
 	}
 
 
 	// Storage
 	// Storage
 	{
 	{
-		// Create buffer
-		PerFrameBuffer& buff = m_perFrameBuffers[TransientBufferType::STORAGE];
-		PtrSize size = buff.m_size;
-		glGenBuffers(1, &buff.m_name);
-		glBindBuffer(GL_SHADER_STORAGE_BUFFER, buff.m_name);
-
-		// Map it
-		glBufferStorage(GL_SHADER_STORAGE_BUFFER, size, nullptr, BUFF_FLAGS);
-		buff.m_mappedMem = static_cast<U8*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, size, BUFF_FLAGS));
-		ANKI_ASSERT(buff.m_mappedMem);
-
-		// Create the allocator
 		GLint64 blockAlignment;
 		GLint64 blockAlignment;
 		glGetInteger64v(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, &blockAlignment);
 		glGetInteger64v(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, &blockAlignment);
-		buff.m_alloc.init(size, blockAlignment, MAX_STORAGE_BLOCK_SIZE);
+		initBuffer(TransientBufferType::STORAGE, blockAlignment, MAX_STORAGE_BLOCK_SIZE, GL_SHADER_STORAGE_BUFFER);
 	}
 	}
 
 
 	// Vertex
 	// Vertex
-	{
-		// Create buffer
-		PerFrameBuffer& buff = m_perFrameBuffers[TransientBufferType::VERTEX];
-		PtrSize size = buff.m_size;
-		glGenBuffers(1, &buff.m_name);
-		glBindBuffer(GL_ARRAY_BUFFER, buff.m_name);
-
-		// Map it
-		glBufferStorage(GL_ARRAY_BUFFER, size, nullptr, BUFF_FLAGS);
-		buff.m_mappedMem = static_cast<U8*>(glMapBufferRange(GL_ARRAY_BUFFER, 0, size, BUFF_FLAGS));
-		ANKI_ASSERT(buff.m_mappedMem);
-
-		// Create the allocator
-		buff.m_alloc.init(size, 16, MAX_U32);
-	}
+	initBuffer(TransientBufferType::VERTEX, 16, MAX_U32, GL_ARRAY_BUFFER);
 
 
 	// Transfer
 	// Transfer
-	{
-		PerFrameBuffer& buff = m_perFrameBuffers[TransientBufferType::TRANSFER];
-		PtrSize size = buff.m_size;
-		buff.m_cpuBuff.create(m_alloc, size);
-
-		buff.m_mappedMem = reinterpret_cast<U8*>(&buff.m_cpuBuff[0]);
-		buff.m_alloc.init(size, 16, MAX_U32);
-	}
+	initBuffer(TransientBufferType::TRANSFER, 16, MAX_U32, GL_PIXEL_UNPACK_BUFFER);
 }
 }
 
 
 void TransientMemoryManager::allocate(PtrSize size,
 void TransientMemoryManager::allocate(PtrSize size,

+ 5 - 24
src/anki/gr/gl/TransientMemoryManager.h

@@ -6,7 +6,7 @@
 #pragma once
 #pragma once
 
 
 #include <anki/gr/gl/Common.h>
 #include <anki/gr/gl/Common.h>
-#include <anki/gr/common/GpuFrameRingAllocator.h>
+#include <anki/gr/common/FrameGpuAllocator.h>
 #include <anki/gr/common/GpuBlockAllocator.h>
 #include <anki/gr/common/GpuBlockAllocator.h>
 #include <anki/gr/common/Misc.h>
 #include <anki/gr/common/Misc.h>
 
 
@@ -49,21 +49,6 @@ public:
 		ANKI_ASSERT(token.m_lifetime == TransientMemoryTokenLifetime::PERSISTENT);
 		ANKI_ASSERT(token.m_lifetime == TransientMemoryTokenLifetime::PERSISTENT);
 	}
 	}
 
 
-	void* getBaseAddress(const TransientMemoryToken& token) const
-	{
-		void* addr;
-		if(token.m_lifetime == TransientMemoryTokenLifetime::PER_FRAME)
-		{
-			addr = m_perFrameBuffers[bufferUsageToTransient(token.m_usage)].m_mappedMem;
-		}
-		else
-		{
-			addr = nullptr;
-		}
-		ANKI_ASSERT(addr);
-		return addr;
-	}
-
 	GLuint getGlName(const TransientMemoryToken& token) const
 	GLuint getGlName(const TransientMemoryToken& token) const
 	{
 	{
 		GLuint name;
 		GLuint name;
@@ -80,24 +65,20 @@ public:
 	}
 	}
 
 
 private:
 private:
-	class alignas(16) Aligned16Type
-	{
-		U8 _m_val[16];
-	};
-
-	// CPU or GPU buffer.
+	// GPU buffer.
 	class PerFrameBuffer
 	class PerFrameBuffer
 	{
 	{
 	public:
 	public:
 		PtrSize m_size = 0;
 		PtrSize m_size = 0;
 		GLuint m_name = 0;
 		GLuint m_name = 0;
-		DynamicArray<Aligned16Type> m_cpuBuff;
 		U8* m_mappedMem = nullptr;
 		U8* m_mappedMem = nullptr;
-		GpuFrameRingAllocator m_alloc;
+		FrameGpuAllocator m_alloc;
 	};
 	};
 
 
 	GenericMemoryPoolAllocator<U8> m_alloc;
 	GenericMemoryPoolAllocator<U8> m_alloc;
 	Array<PerFrameBuffer, U(TransientBufferType::COUNT)> m_perFrameBuffers;
 	Array<PerFrameBuffer, U(TransientBufferType::COUNT)> m_perFrameBuffers;
+
+	void initBuffer(TransientBufferType type, U32 alignment, PtrSize maxAllocSize, GLenum target);
 };
 };
 /// @}
 /// @}
 
 

+ 2 - 2
src/anki/gr/vulkan/TransientMemoryManager.h

@@ -6,7 +6,7 @@
 #pragma once
 #pragma once
 
 
 #include <anki/gr/vulkan/Common.h>
 #include <anki/gr/vulkan/Common.h>
-#include <anki/gr/common/GpuFrameRingAllocator.h>
+#include <anki/gr/common/FrameGpuAllocator.h>
 #include <anki/gr/common/Misc.h>
 #include <anki/gr/common/Misc.h>
 
 
 namespace anki
 namespace anki
@@ -65,7 +65,7 @@ private:
 		BufferImpl* m_buff = nullptr;
 		BufferImpl* m_buff = nullptr;
 		U8* m_mappedMem = nullptr;
 		U8* m_mappedMem = nullptr;
 		VkBuffer m_bufferHandle = VK_NULL_HANDLE; ///< Cache it.
 		VkBuffer m_bufferHandle = VK_NULL_HANDLE; ///< Cache it.
-		GpuFrameRingAllocator m_alloc;
+		FrameGpuAllocator m_alloc;
 	};
 	};
 
 
 	GrManager* m_manager = nullptr;
 	GrManager* m_manager = nullptr;

+ 1 - 2
src/anki/renderer/Clusterer.cpp

@@ -102,8 +102,7 @@ void Clusterer::init(const GenericMemoryPoolAllocator<U8>& alloc, U clusterCount
 	m_counts[1] = clusterCountY;
 	m_counts[1] = clusterCountY;
 	m_counts[2] = clusterCountZ;
 	m_counts[2] = clusterCountZ;
 
 
-	// Init planes. One plane for each direction, plus near/far plus the world
-	// space of those
+	// Init planes. One plane for each direction, plus near/far plus the world space of those
 	U planesCount = (m_counts[0] - 1) * 2 // planes J
 	U planesCount = (m_counts[0] - 1) * 2 // planes J
 		+ (m_counts[1] - 1) * 2 // planes I
 		+ (m_counts[1] - 1) * 2 // planes I
 		+ 2; // Near and far planes
 		+ 2; // Near and far planes

+ 1 - 2
src/anki/renderer/Clusterer.h

@@ -128,8 +128,7 @@ private:
 	Plane* m_nearPlane; ///< In world space
 	Plane* m_nearPlane; ///< In world space
 	Plane* m_farPlane; ///< In world space
 	Plane* m_farPlane; ///< In world space
 
 
-	/// Used to check if the frustum is changed and we need to update the
-	/// planes.
+	/// Used to check if the frustum is changed and we need to update the planes.
 	const SceneNode* m_node = nullptr;
 	const SceneNode* m_node = nullptr;
 
 
 	const FrustumComponent* m_frc = nullptr; ///< Cache it.
 	const FrustumComponent* m_frc = nullptr; ///< Cache it.

+ 77 - 1
src/anki/renderer/Is.cpp

@@ -17,8 +17,9 @@
 namespace anki
 namespace anki
 {
 {
 
 
-struct ShaderCommonUniforms
+class ShaderCommonUniforms
 {
 {
+public:
 	Vec4 m_projectionParams;
 	Vec4 m_projectionParams;
 	Vec4 m_rendererSizeTimePad1;
 	Vec4 m_rendererSizeTimePad1;
 	Vec4 m_nearFarClustererMagicPad1;
 	Vec4 m_nearFarClustererMagicPad1;
@@ -27,6 +28,17 @@ struct ShaderCommonUniforms
 	UVec4 m_tileCount;
 	UVec4 m_tileCount;
 };
 };
 
 
+enum class ShaderVariantBit : U8
+{
+	P_LIGHTS = 1 << 0,
+	S_LIGHTS = 1 << 1,
+	DECALS = 1 << 2,
+	INDIRECT = 1 << 3,
+	P_LIGHTS_SHADOWS = 1 << 4,
+	S_LIGHTS_SHADOWS = 1 << 5
+};
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(ShaderVariantBit, inline)
+
 Is::Is(Renderer* r)
 Is::Is(Renderer* r)
 	: RenderingPass(r)
 	: RenderingPass(r)
 {
 {
@@ -66,6 +78,7 @@ Error Is::initInternal(const ConfigSet& config)
 	ANKI_ASSERT(m_rtMipCount);
 	ANKI_ASSERT(m_rtMipCount);
 
 
 	U clusterCount = m_r->getTileCountXY().x() * m_r->getTileCountXY().y() * config.getNumber("clusterSizeZ");
 	U clusterCount = m_r->getTileCountXY().x() * m_r->getTileCountXY().y() * config.getNumber("clusterSizeZ");
+	m_clusterCount = clusterCount;
 	m_maxLightIds *= clusterCount;
 	m_maxLightIds *= clusterCount;
 
 
 	m_lightBin = getAllocator().newInstance<LightBin>(getAllocator(),
 	m_lightBin = getAllocator().newInstance<LightBin>(getAllocator(),
@@ -273,4 +286,67 @@ void Is::setPreRunBarriers(RenderingContext& ctx)
 		TextureSurfaceInfo(0, 0, 0, 0));
 		TextureSurfaceInfo(0, 0, 0, 0));
 }
 }
 
 
+Error Is::getOrCreatePipeline(ShaderVariantBit variantMask, RenderingContext& ctx, PipelinePtr& ppline)
+{
+	auto it = m_shaderVariantMap.find(variantMask);
+	if(it != m_shaderVariantMap.getEnd())
+	{
+		ppline = it->m_lightPpline;
+	}
+	else
+	{
+		StringAuto pps(ctx.m_tempAllocator);
+
+		pps.sprintf("#define TILE_COUNT_X %u\n"
+					"#define TILE_COUNT_Y %u\n"
+					"#define CLUSTER_COUNT %u\n"
+					"#define RENDERER_WIDTH %u\n"
+					"#define RENDERER_HEIGHT %u\n"
+					"#define MAX_LIGHT_INDICES %u\n"
+					"#define POISSON %u\n"
+					"#define INDIRECT_ENABLED %u\n"
+					"#define IR_MIPMAP_COUNT %u\n"
+					"#define POINT_LIGHTS_ENABLED %u\n"
+					"#define SPOT_LIGHTS_ENABLED %u\n"
+					"#define DECALS_ENABLED %u\n"
+					"#define POINT_LIGHTS_SHADOWS_ENABLED %u\n"
+					"#define SPOT_LIGHTS_SHADOWS_ENABLED %u\n",
+			m_r->getTileCountXY().x(),
+			m_r->getTileCountXY().y(),
+			m_clusterCount,
+			m_r->getWidth(),
+			m_r->getHeight(),
+			m_maxLightIds,
+			m_r->getSm().getPoissonEnabled(),
+			!!(variantMask & ShaderVariantBit::INDIRECT),
+			m_r->getIr().getReflectionTextureMipmapCount(),
+			!!(variantMask & ShaderVariantBit::P_LIGHTS),
+			!!(variantMask & ShaderVariantBit::S_LIGHTS),
+			!!(variantMask & ShaderVariantBit::DECALS),
+			!!(variantMask & ShaderVariantBit::P_LIGHTS_SHADOWS),
+			!!(variantMask & ShaderVariantBit::S_LIGHTS_SHADOWS));
+
+		ShaderVariant variant;
+		ANKI_CHECK(getResourceManager().loadResourceToCache(
+			variant.m_lightFrag, "shaders/Is.frag.glsl", pps.toCString(), "r_"));
+
+		PipelineInitInfo init;
+
+		init.m_inputAssembler.m_topology = PrimitiveTopology::TRIANGLE_STRIP;
+		init.m_depthStencil.m_depthWriteEnabled = false;
+		init.m_depthStencil.m_depthCompareFunction = CompareOperation::ALWAYS;
+		init.m_color.m_attachmentCount = 1;
+		init.m_color.m_attachments[0].m_format = IS_COLOR_ATTACHMENT_PIXEL_FORMAT;
+		init.m_shaders[U(ShaderType::VERTEX)] = m_lightVert->getGrShader();
+		init.m_shaders[U(ShaderType::FRAGMENT)] = m_lightFrag->getGrShader();
+		variant.m_lightPpline = getGrManager().newInstance<Pipeline>(init);
+
+		ppline = variant.m_lightPpline;
+
+		m_shaderVariantMap.pushBack(getAllocator(), variantMask, variant);
+	}
+
+	return ErrorCode::NONE;
+}
+
 } // end namespace anki
 } // end namespace anki

+ 25 - 0
src/anki/renderer/Is.h

@@ -15,6 +15,7 @@ namespace anki
 // Forward
 // Forward
 class FrustumComponent;
 class FrustumComponent;
 class LightBin;
 class LightBin;
+enum class ShaderVariantBit : U8;
 
 
 /// @addtogroup renderer
 /// @addtogroup renderer
 /// @{
 /// @{
@@ -58,6 +59,7 @@ private:
 	/// The IS render target
 	/// The IS render target
 	TexturePtr m_rt;
 	TexturePtr m_rt;
 	U8 m_rtMipCount = 0;
 	U8 m_rtMipCount = 0;
+	U32 m_clusterCount = 0;
 
 
 	/// The IS FBO
 	/// The IS FBO
 	FramebufferPtr m_fb;
 	FramebufferPtr m_fb;
@@ -73,6 +75,27 @@ private:
 	ShaderResourcePtr m_lightFrag;
 	ShaderResourcePtr m_lightFrag;
 	PipelinePtr m_lightPpline;
 	PipelinePtr m_lightPpline;
 
 
+	class ShaderVariant
+	{
+	public:
+		ShaderResourcePtr m_lightFrag;
+		PipelinePtr m_lightPpline;
+	};
+
+	using Key = ShaderVariantBit;
+
+	/// Hash the hash.
+	class Hasher
+	{
+	public:
+		U64 operator()(const Key& b) const
+		{
+			return U64(b);
+		}
+	};
+
+	HashMap<Key, ShaderVariant, Hasher> m_shaderVariantMap;
+
 	LightBin* m_lightBin = nullptr;
 	LightBin* m_lightBin = nullptr;
 
 
 	/// @name Limits
 	/// @name Limits
@@ -84,6 +107,8 @@ private:
 	ANKI_USE_RESULT Error initInternal(const ConfigSet& initializer);
 	ANKI_USE_RESULT Error initInternal(const ConfigSet& initializer);
 
 
 	void updateCommonBlock(RenderingContext& ctx);
 	void updateCommonBlock(RenderingContext& ctx);
+
+	ANKI_USE_RESULT Error getOrCreatePipeline(ShaderVariantBit variantMask, RenderingContext& ctx, PipelinePtr& ppline);
 };
 };
 /// @}
 /// @}
 
 

+ 22 - 4
src/anki/script/Scene.cpp

@@ -1149,9 +1149,18 @@ static inline int pwrapDecalComponentsetDiffuseDecal(lua_State* l)
 	}
 	}
 
 
 	// Call the method
 	// Call the method
-	self->setDiffuseDecal(arg0, arg1, arg2);
+	Error ret = self->setDiffuseDecal(arg0, arg1, arg2);
 
 
-	return 0;
+	// Push return value
+	if(ANKI_UNLIKELY(ret))
+	{
+		lua_pushstring(l, "Glue code returned an error");
+		return -1;
+	}
+
+	lua_pushnumber(l, ret);
+
+	return 1;
 }
 }
 
 
 /// Wrap method DecalComponent::setDiffuseDecal.
 /// Wrap method DecalComponent::setDiffuseDecal.
@@ -1207,9 +1216,18 @@ static inline int pwrapDecalComponentsetNormalRoughnessDecal(lua_State* l)
 	}
 	}
 
 
 	// Call the method
 	// Call the method
-	self->setNormalRoughnessDecal(arg0, arg1, arg2);
+	Error ret = self->setNormalRoughnessDecal(arg0, arg1, arg2);
 
 
-	return 0;
+	// Push return value
+	if(ANKI_UNLIKELY(ret))
+	{
+		lua_pushstring(l, "Glue code returned an error");
+		return -1;
+	}
+
+	lua_pushnumber(l, ret);
+
+	return 1;
 }
 }
 
 
 /// Wrap method DecalComponent::setNormalRoughnessDecal.
 /// Wrap method DecalComponent::setNormalRoughnessDecal.

+ 2 - 0
src/anki/script/Scene.xml

@@ -145,6 +145,7 @@ static SceneGraph* getSceneGraph(lua_State* l)
 						<arg>CString</arg>
 						<arg>CString</arg>
 						<arg>F32</arg>
 						<arg>F32</arg>
 					</args>
 					</args>
+					<return>Error</return>
 				</method>
 				</method>
 				<method name="setNormalRoughnessDecal">
 				<method name="setNormalRoughnessDecal">
 					<args>
 					<args>
@@ -152,6 +153,7 @@ static SceneGraph* getSceneGraph(lua_State* l)
 						<arg>CString</arg>
 						<arg>CString</arg>
 						<arg>F32</arg>
 						<arg>F32</arg>
 					</args>
 					</args>
+					<return>Error</return>
 				</method>
 				</method>
 				<method name="updateShape">
 				<method name="updateShape">
 					<args>
 					<args>

+ 12 - 1
src/anki/util/HashMap.h

@@ -280,8 +280,19 @@ protected:
 
 
 } // end namespace detail
 } // end namespace detail
 
 
+/// Default hash key compare.
+template<typename TKey>
+class DefaultHashKeyCompare
+{
+public:
+	Bool operator()(const TKey& a, const TKey& b) const
+	{
+		return a == b;
+	}
+};
+
 /// Hash map template.
 /// Hash map template.
-template<typename TKey, typename TValue, typename THasher, typename TCompare>
+template<typename TKey, typename TValue, typename THasher, typename TCompare = DefaultHashKeyCompare<TKey>>
 class HashMap : public detail::HashMapBase<TKey, TValue, THasher, TCompare, detail::HashMapNode<TValue>>
 class HashMap : public detail::HashMapBase<TKey, TValue, THasher, TCompare, detail::HashMapNode<TValue>>
 {
 {
 private:
 private:

+ 61 - 24
tests/gr/StackGpuAllocator.cpp

@@ -6,6 +6,7 @@
 #include <anki/gr/common/StackGpuAllocator.h>
 #include <anki/gr/common/StackGpuAllocator.h>
 #include <anki/util/ThreadHive.h>
 #include <anki/util/ThreadHive.h>
 #include <tests/framework/Framework.h>
 #include <tests/framework/Framework.h>
+#include <algorithm>
 
 
 using namespace anki;
 using namespace anki;
 
 
@@ -14,8 +15,9 @@ namespace
 
 
 const U ALLOCATION_COUNT = 1024;
 const U ALLOCATION_COUNT = 1024;
 const U THREAD_COUNT = 4;
 const U THREAD_COUNT = 4;
-const U32 MIN_ALLOCATION_SIZE = 1024;
+const U32 MIN_ALLOCATION_SIZE = 256;
 const U32 MAX_ALLOCATION_SIZE = 1024 * 10;
 const U32 MAX_ALLOCATION_SIZE = 1024 * 10;
+const U32 ALIGNMENT = 256;
 
 
 class Mem : public StackGpuAllocatorMemory
 class Mem : public StackGpuAllocatorMemory
 {
 {
@@ -27,13 +29,11 @@ public:
 class Interface final : public StackGpuAllocatorInterface
 class Interface final : public StackGpuAllocatorInterface
 {
 {
 public:
 public:
-	U32 m_alignment = 256;
-
 	ANKI_USE_RESULT Error allocate(PtrSize size, StackGpuAllocatorMemory*& mem)
 	ANKI_USE_RESULT Error allocate(PtrSize size, StackGpuAllocatorMemory*& mem)
 	{
 	{
 		Mem* m = new Mem();
 		Mem* m = new Mem();
 
 
-		m->m_mem = mallocAligned(size, m_alignment);
+		m->m_mem = mallocAligned(size, ALIGNMENT);
 		m->m_size = size;
 		m->m_size = size;
 		mem = m;
 		mem = m;
 
 
@@ -51,21 +51,27 @@ public:
 	{
 	{
 		scale = 2.0;
 		scale = 2.0;
 		bias = 0;
 		bias = 0;
-		initialSize = m_alignment * 1024;
+		initialSize = ALIGNMENT * 1024;
 	}
 	}
 
 
 	U32 getMaxAlignment()
 	U32 getMaxAlignment()
 	{
 	{
-		return m_alignment;
+		return ALIGNMENT;
 	}
 	}
 };
 };
 
 
+class Allocation
+{
+public:
+	StackGpuAllocatorHandle m_handle;
+	PtrSize m_size;
+};
+
 class TestContext
 class TestContext
 {
 {
 public:
 public:
 	StackGpuAllocator* m_salloc;
 	StackGpuAllocator* m_salloc;
-	Array<StackGpuAllocatorHandle, ALLOCATION_COUNT> m_allocs;
-	Array<U32, ALLOCATION_COUNT> m_allocSize;
+	Array<Allocation, ALLOCATION_COUNT> m_allocs;
 	Atomic<U32> m_allocCount;
 	Atomic<U32> m_allocCount;
 };
 };
 
 
@@ -74,8 +80,9 @@ static void doAllocation(void* arg, U32 threadId, ThreadHive& hive)
 	TestContext* ctx = static_cast<TestContext*>(arg);
 	TestContext* ctx = static_cast<TestContext*>(arg);
 
 
 	U allocCount = ctx->m_allocCount.fetchAdd(1);
 	U allocCount = ctx->m_allocCount.fetchAdd(1);
-	ctx->m_allocSize[allocCount] = randRange(MIN_ALLOCATION_SIZE, MAX_ALLOCATION_SIZE);
-	ctx->m_salloc->allocate(ctx->m_allocSize[allocCount], ctx->m_allocs[allocCount]);
+	PtrSize allocSize = randRange(MIN_ALLOCATION_SIZE, MAX_ALLOCATION_SIZE);
+	ctx->m_allocs[allocCount].m_size = allocSize;
+	ANKI_TEST_EXPECT_NO_ERR(ctx->m_salloc->allocate(allocSize, ctx->m_allocs[allocCount].m_handle));
 }
 }
 
 
 } // end anonymous namespace
 } // end anonymous namespace
@@ -88,22 +95,52 @@ ANKI_TEST(Gr, StackGpuAllocator)
 	StackGpuAllocator salloc;
 	StackGpuAllocator salloc;
 	salloc.init(alloc, &iface);
 	salloc.init(alloc, &iface);
 
 
-	TestContext ctx;
-	memset(&ctx, 0, sizeof(ctx));
-	ctx.m_salloc = &salloc;
-
-	ThreadHiveTask task;
-	task.m_callback = doAllocation;
-	task.m_argument = &ctx;
 	ThreadHive hive(THREAD_COUNT, alloc);
 	ThreadHive hive(THREAD_COUNT, alloc);
 
 
-	for(U i = 0; i < ALLOCATION_COUNT; ++i)
+	for(U i = 0; i < 1024; ++i)
 	{
 	{
-		hive.submitTasks(&task, 1);
+		TestContext ctx;
+		memset(&ctx, 0, sizeof(ctx));
+		ctx.m_salloc = &salloc;
+
+		ThreadHiveTask task;
+		task.m_callback = doAllocation;
+		task.m_argument = &ctx;
+
+		for(U i = 0; i < ALLOCATION_COUNT; ++i)
+		{
+			hive.submitTasks(&task, 1);
+		}
+
+		hive.waitAllTasks();
+
+		// Make sure memory doesn't overlap
+		std::sort(ctx.m_allocs.getBegin(), ctx.m_allocs.getEnd(), [](const Allocation& a, const Allocation& b) {
+			if(a.m_handle.m_memory != b.m_handle.m_memory)
+			{
+				return a.m_handle.m_memory < b.m_handle.m_memory;
+			}
+
+			if(a.m_handle.m_offset != b.m_handle.m_offset)
+			{
+				return a.m_handle.m_offset <= b.m_handle.m_offset;
+			}
+
+			ANKI_TEST_EXPECT_EQ(1, 0);
+			return true;
+		});
+
+		for(U i = 1; i < ALLOCATION_COUNT; ++i)
+		{
+			const Allocation& a = ctx.m_allocs[i - 1];
+			const Allocation& b = ctx.m_allocs[i];
+
+			if(a.m_handle.m_memory == b.m_handle.m_memory)
+			{
+				ANKI_TEST_EXPECT_LEQ(a.m_handle.m_offset + a.m_size, b.m_handle.m_offset);
+			}
+		}
+
+		salloc.reset();
 	}
 	}
-
-	hive.waitAllTasks();
-
-	// Make sure memory doesn't overlap
-	// TODO
 }
 }