浏览代码

Vulkan: Bug fixes and some refactoring

Panagiotis Christopoulos Charitos 9 年之前
父节点
当前提交
9e94f948dd

+ 12 - 0
shaders/LfOcclusion.frag.glsl

@@ -7,6 +7,18 @@
 
 #include "shaders/Common.glsl"
 
+// WORKAROUND: For some reason validation layer complains
+#ifdef ANKI_VK
+layout(location = 0) out vec4 out_msRt0;
+layout(location = 1) out vec4 out_msRt1;
+layout(location = 2) out vec4 out_msRt2;
+#endif
+
 void main()
 {
+#ifdef ANKI_VK
+	out_msRt0 = vec4(0.0);
+	out_msRt1 = vec4(0.0);
+	out_msRt2 = vec4(0.0);
+#endif
 }

+ 1 - 1
shaders/LfSpritePass.vert.glsl

@@ -16,7 +16,7 @@ struct Sprite
 };
 
 // The block contains data for all flares
-layout(std140) uniform _blk
+layout(std140, ANKI_UBO_BINDING(0, 0)) uniform _blk
 {
 	Sprite u_sprites[MAX_SPRITES];
 };

+ 27 - 20
src/anki/gr/vulkan/BufferImpl.cpp

@@ -19,9 +19,9 @@ BufferImpl::~BufferImpl()
 		vkDestroyBuffer(getDevice(), m_handle, nullptr);
 	}
 
-	if(!m_memHandle.isEmpty())
+	if(m_memHandle)
 	{
-		getGrManagerImpl().freeMemory(m_memIdx, m_memHandle);
+		getGrManagerImpl().getGpuMemoryAllocator().freeMemory(m_memHandle);
 	}
 }
 
@@ -47,30 +47,33 @@ Error BufferImpl::init(
 	// Get mem requirements
 	VkMemoryRequirements req;
 	vkGetBufferMemoryRequirements(getDevice(), m_handle, &req);
+	U memIdx = MAX_U32;
 
 	if(access == BufferMapAccessBit::WRITE)
 	{
 		// Only write
 
 		// Device & host but not coherent
-		m_memIdx = getGrManagerImpl().findMemoryType(req.memoryTypeBits,
+		memIdx = getGrManagerImpl().getGpuMemoryAllocator().findMemoryType(
+			req.memoryTypeBits,
 			VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
 				| VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
 			VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
 
 		// Fallback: host and not coherent
-		if(m_memIdx == MAX_U32)
+		if(memIdx == MAX_U32)
 		{
-			m_memIdx = getGrManagerImpl().findMemoryType(req.memoryTypeBits,
+			memIdx = getGrManagerImpl().getGpuMemoryAllocator().findMemoryType(
+				req.memoryTypeBits,
 				VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
 				VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
 		}
 
 		// Fallback: any host
-		if(m_memIdx == MAX_U32)
+		if(memIdx == MAX_U32)
 		{
 			ANKI_LOGW("Vulkan: Using a fallback mode for write-only buffer");
-			m_memIdx = getGrManagerImpl().findMemoryType(
+			memIdx = getGrManagerImpl().getGpuMemoryAllocator().findMemoryType(
 				req.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, 0);
 		}
 	}
@@ -79,26 +82,28 @@ Error BufferImpl::init(
 		// Read or read/write
 
 		// Cached & coherent
-		m_memIdx = getGrManagerImpl().findMemoryType(req.memoryTypeBits,
+		memIdx = getGrManagerImpl().getGpuMemoryAllocator().findMemoryType(
+			req.memoryTypeBits,
 			VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
 				| VK_MEMORY_PROPERTY_HOST_CACHED_BIT
 				| VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
 			0);
 
 		// Fallback: Just cached
-		if(m_memIdx == MAX_U32)
+		if(memIdx == MAX_U32)
 		{
-			m_memIdx = getGrManagerImpl().findMemoryType(req.memoryTypeBits,
+			memIdx = getGrManagerImpl().getGpuMemoryAllocator().findMemoryType(
+				req.memoryTypeBits,
 				VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
 					| VK_MEMORY_PROPERTY_HOST_CACHED_BIT,
 				0);
 		}
 
 		// Fallback: Just host
-		if(m_memIdx == MAX_U32)
+		if(memIdx == MAX_U32)
 		{
 			ANKI_LOGW("Vulkan: Using a fallback mode for read/write buffer");
-			m_memIdx = getGrManagerImpl().findMemoryType(
+			memIdx = getGrManagerImpl().getGpuMemoryAllocator().findMemoryType(
 				req.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, 0);
 		}
 	}
@@ -109,27 +114,28 @@ Error BufferImpl::init(
 		ANKI_ASSERT(access == BufferMapAccessBit::NONE);
 
 		// Device only
-		m_memIdx = getGrManagerImpl().findMemoryType(req.memoryTypeBits,
+		memIdx = getGrManagerImpl().getGpuMemoryAllocator().findMemoryType(
+			req.memoryTypeBits,
 			VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
 			VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
 
 		// Fallback: Device with anything else
-		if(m_memIdx == MAX_U32)
+		if(memIdx == MAX_U32)
 		{
-			m_memIdx = getGrManagerImpl().findMemoryType(
+			memIdx = getGrManagerImpl().getGpuMemoryAllocator().findMemoryType(
 				req.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0);
 		}
 	}
 
-	ANKI_ASSERT(m_memIdx != MAX_U32);
+	ANKI_ASSERT(memIdx != MAX_U32);
 
 	const VkPhysicalDeviceMemoryProperties& props =
 		getGrManagerImpl().getMemoryProperties();
-	m_memoryFlags = props.memoryTypes[m_memIdx].propertyFlags;
+	m_memoryFlags = props.memoryTypes[memIdx].propertyFlags;
 
 	// Allocate
-	getGrManagerImpl().allocateMemory(
-		m_memIdx, req.size, req.alignment, m_memHandle);
+	getGrManagerImpl().getGpuMemoryAllocator().allocateMemory(
+		memIdx, req.size, req.alignment, true, m_memHandle);
 
 	// Bind mem to buffer
 	ANKI_VK_CHECK(vkBindBufferMemory(
@@ -150,7 +156,8 @@ void* BufferImpl::map(PtrSize offset, PtrSize range, BufferMapAccessBit access)
 	ANKI_ASSERT(!m_mapped);
 	ANKI_ASSERT(offset + range <= m_size);
 
-	void* ptr = getGrManagerImpl().getMappedAddress(m_memIdx, m_memHandle);
+	void* ptr = getGrManagerImpl().getGpuMemoryAllocator().getMappedAddress(
+		m_memHandle);
 	ANKI_ASSERT(ptr);
 
 #if ANKI_ASSERTIONS

+ 0 - 1
src/anki/gr/vulkan/BufferImpl.h

@@ -62,7 +62,6 @@ public:
 private:
 	VkBuffer m_handle = VK_NULL_HANDLE;
 	GpuMemoryAllocationHandle m_memHandle;
-	U32 m_memIdx = 0;
 	BufferMapAccessBit m_access = BufferMapAccessBit::NONE;
 	U32 m_size = 0;
 	VkMemoryPropertyFlags m_memoryFlags = 0;

+ 12 - 2
src/anki/gr/vulkan/FramebufferImpl.cpp

@@ -212,6 +212,12 @@ Error FramebufferImpl::initFramebuffer(const FramebufferInitInfo& init)
 			attachments[count] =
 				tex.getOrCreateSingleSurfaceView(att.m_surface);
 
+			if(m_width == 0)
+			{
+				m_width = tex.m_width >> att.m_surface.m_level;
+				m_height = tex.m_height >> att.m_surface.m_level;
+			}
+
 			m_refs[count++] = att.m_texture;
 		}
 
@@ -224,11 +230,15 @@ Error FramebufferImpl::initFramebuffer(const FramebufferInitInfo& init)
 			attachments[count] =
 				tex.getOrCreateSingleSurfaceView(att.m_surface);
 
+			if(m_width == 0)
+			{
+				m_width = tex.m_width >> att.m_surface.m_level;
+				m_height = tex.m_height >> att.m_surface.m_level;
+			}
+
 			m_refs[count++] = att.m_texture;
 		}
 
-		m_width = m_refs[0]->getImplementation().m_width;
-		m_height = m_refs[0]->getImplementation().m_height;
 		ci.width = m_width;
 		ci.height = m_height;
 

+ 115 - 16
src/anki/gr/vulkan/GpuMemoryAllocator.cpp

@@ -50,6 +50,9 @@ public:
 	/// Protect the m_mappedAddress. It's a SpinLock because we don't want a
 	/// whole mutex for every GpuMemoryAllocatorChunk.
 	SpinLock m_mtx;
+
+	/// If true it contains linear resources.
+	Bool8 m_linearResources = false;
 };
 
 //==============================================================================
@@ -77,11 +80,11 @@ public:
 };
 
 //==============================================================================
-// GpuMemoryAllocator                                                          =
+// GpuMemoryAllocatorMemType                                                   =
 //==============================================================================
 
 //==============================================================================
-GpuMemoryAllocator::~GpuMemoryAllocator()
+GpuMemoryAllocatorMemType::~GpuMemoryAllocatorMemType()
 {
 	for(Class& cl : m_classes)
 	{
@@ -125,7 +128,7 @@ GpuMemoryAllocator::~GpuMemoryAllocator()
 }
 
 //==============================================================================
-void GpuMemoryAllocator::init(
+void GpuMemoryAllocatorMemType::init(
 	GenericMemoryPoolAllocator<U8> alloc, VkDevice dev, U memoryTypeIdx)
 {
 	m_alloc = alloc;
@@ -137,12 +140,25 @@ void GpuMemoryAllocator::init(
 	//
 	const U CLASS_COUNT = 6;
 	m_classes.create(m_alloc, CLASS_COUNT);
+	static const CString MESSAGE =
+		"VK: Creating memory class. "
+		"Chunk size: %u, maxSlotSize: %u, allocsPerChunk: %u";
+
+#define ANKI_PRINT_MSG()                                                       \
+	if(memoryTypeIdx == 0)                                                     \
+	{                                                                          \
+		ANKI_LOGI(&MESSAGE[0],                                                 \
+			c.m_chunkPages* PAGE_SIZE,                                         \
+			c.m_maxSlotSize,                                                   \
+			c.m_chunkPages* PAGE_SIZE / c.m_maxSlotSize)                       \
+	}
 
 	// 1st class. From (0, 256] bytes
 	{
 		Class& c = m_classes[0];
 		c.m_chunkPages = 2;
 		c.m_maxSlotSize = 256;
+		ANKI_PRINT_MSG();
 	}
 
 	// 2st class. From (256, 4K] bytes
@@ -150,6 +166,7 @@ void GpuMemoryAllocator::init(
 		Class& c = m_classes[1];
 		c.m_chunkPages = 32;
 		c.m_maxSlotSize = 4 * 1024;
+		ANKI_PRINT_MSG();
 	}
 
 	// 3rd class. From (4K, 128K] bytes
@@ -157,6 +174,7 @@ void GpuMemoryAllocator::init(
 		Class& c = m_classes[2];
 		c.m_chunkPages = 1024;
 		c.m_maxSlotSize = 128 * 1024;
+		ANKI_PRINT_MSG();
 	}
 
 	// 4rth class. From (128K, 1M] bytes
@@ -164,6 +182,7 @@ void GpuMemoryAllocator::init(
 		Class& c = m_classes[3];
 		c.m_chunkPages = 4 * 1024;
 		c.m_maxSlotSize = 1 * 1024 * 1024;
+		ANKI_PRINT_MSG();
 	}
 
 	// 5th class. From (1M, 10M] bytes
@@ -171,6 +190,7 @@ void GpuMemoryAllocator::init(
 		Class& c = m_classes[4];
 		c.m_chunkPages = 10 * 1024;
 		c.m_maxSlotSize = 10 * 1024 * 1024;
+		ANKI_PRINT_MSG();
 	}
 
 	// 6th class. From (10M, 80M] bytes
@@ -178,6 +198,7 @@ void GpuMemoryAllocator::init(
 		Class& c = m_classes[5];
 		c.m_chunkPages = 20 * 1024;
 		c.m_maxSlotSize = 80 * 1024 * 1024;
+		ANKI_PRINT_MSG();
 	}
 
 	for(Class& c : m_classes)
@@ -189,7 +210,7 @@ void GpuMemoryAllocator::init(
 }
 
 //==============================================================================
-GpuMemoryAllocator::Class* GpuMemoryAllocator::findClass(
+GpuMemoryAllocatorMemType::Class* GpuMemoryAllocatorMemType::findClass(
 	PtrSize size, U32 alignment)
 {
 	ANKI_ASSERT(size > 0 && alignment > 0);
@@ -233,14 +254,16 @@ GpuMemoryAllocator::Class* GpuMemoryAllocator::findClass(
 }
 
 //==============================================================================
-GpuMemoryAllocator::Chunk* GpuMemoryAllocator::findChunkWithUnusedSlot(
-	Class& cl)
+GpuMemoryAllocatorMemType::Chunk*
+GpuMemoryAllocatorMemType::findChunkWithUnusedSlot(
+	Class& cl, Bool linearResource)
 {
 	auto it = cl.m_inUseChunks.getBegin();
 	const auto end = cl.m_inUseChunks.getEnd();
 	while(it != end)
 	{
-		if(it->m_inUseSlotCount < cl.m_slotsPerChunkCount)
+		if(it->m_inUseSlotCount < cl.m_slotsPerChunkCount
+			&& it->m_linearResources == linearResource)
 		{
 			return &(*it);
 		}
@@ -252,7 +275,8 @@ GpuMemoryAllocator::Chunk* GpuMemoryAllocator::findChunkWithUnusedSlot(
 }
 
 //==============================================================================
-GpuMemoryAllocator::Chunk& GpuMemoryAllocator::createChunk(Class& cl)
+GpuMemoryAllocatorMemType::Chunk& GpuMemoryAllocatorMemType::createChunk(
+	Class& cl, Bool linearResources)
 {
 	Chunk* chunk = nullptr;
 
@@ -277,6 +301,7 @@ GpuMemoryAllocator::Chunk& GpuMemoryAllocator::createChunk(Class& cl)
 		cl.m_unusedChunks.popFront();
 	}
 
+	chunk->m_linearResources = linearResources;
 	cl.m_inUseChunks.pushBack(chunk);
 
 	ANKI_ASSERT(chunk->m_mem && chunk->m_class == &cl
@@ -287,8 +312,10 @@ GpuMemoryAllocator::Chunk& GpuMemoryAllocator::createChunk(Class& cl)
 }
 
 //==============================================================================
-void GpuMemoryAllocator::allocate(
-	PtrSize size, U alignment, GpuMemoryAllocationHandle& handle)
+void GpuMemoryAllocatorMemType::allocate(PtrSize size,
+	U alignment,
+	Bool linearResource,
+	GpuMemoryAllocationHandle& handle)
 {
 	handle.m_memory = VK_NULL_HANDLE;
 
@@ -297,12 +324,12 @@ void GpuMemoryAllocator::allocate(
 	ANKI_ASSERT(cl && "Didn't found a suitable class");
 
 	LockGuard<Mutex> lock(cl->m_mtx);
-	Chunk* chunk = findChunkWithUnusedSlot(*cl);
+	Chunk* chunk = findChunkWithUnusedSlot(*cl, linearResource);
 
 	// Create a new chunk if needed
 	if(chunk == nullptr)
 	{
-		chunk = &createChunk(*cl);
+		chunk = &createChunk(*cl, linearResource);
 	}
 
 	// Allocate from chunk
@@ -328,7 +355,7 @@ void GpuMemoryAllocator::allocate(
 }
 
 //==============================================================================
-void GpuMemoryAllocator::destroyChunk(Class& cl, Chunk& chunk)
+void GpuMemoryAllocatorMemType::destroyChunk(Class& cl, Chunk& chunk)
 {
 	// Push the chunk to unused area
 	cl.m_inUseChunks.erase(&chunk);
@@ -343,7 +370,7 @@ void GpuMemoryAllocator::destroyChunk(Class& cl, Chunk& chunk)
 }
 
 //==============================================================================
-void GpuMemoryAllocator::free(GpuMemoryAllocationHandle& handle)
+void GpuMemoryAllocatorMemType::free(GpuMemoryAllocationHandle& handle)
 {
 	ANKI_CHECK_HANDLE(handle);
 
@@ -367,7 +394,8 @@ void GpuMemoryAllocator::free(GpuMemoryAllocationHandle& handle)
 }
 
 //==============================================================================
-void* GpuMemoryAllocator::getMappedAddress(GpuMemoryAllocationHandle& handle)
+void* GpuMemoryAllocatorMemType::getMappedAddress(
+	GpuMemoryAllocationHandle& handle)
 {
 	ANKI_CHECK_HANDLE(handle);
 
@@ -397,4 +425,75 @@ void* GpuMemoryAllocator::getMappedAddress(GpuMemoryAllocationHandle& handle)
 	return static_cast<void*>(out + handle.m_offset);
 }
 
-} // end namespace anki
+//==============================================================================
+// GpuMemoryAllocator                                                          =
+//==============================================================================
+
+//==============================================================================
+GpuMemoryAllocator::~GpuMemoryAllocator()
+{
+}
+
+//==============================================================================
+void GpuMemoryAllocator::init(
+	VkPhysicalDevice pdev, VkDevice dev, GrAllocator<U8> alloc)
+{
+	vkGetPhysicalDeviceMemoryProperties(pdev, &m_memoryProperties);
+
+	// Create the high level allocators
+	m_gpuAllocs.create(alloc, m_memoryProperties.memoryTypeCount);
+	U idx = 0;
+	for(GpuMemoryAllocatorMemType& a : m_gpuAllocs)
+	{
+		a.init(alloc, dev, idx++);
+	}
+
+	m_dev = dev;
+	m_alloc = alloc;
+}
+
+//==============================================================================
+void GpuMemoryAllocator::destroy()
+{
+	m_gpuAllocs.destroy(m_alloc);
+}
+
+//==============================================================================
+U GpuMemoryAllocator::findMemoryType(U resourceMemTypeBits,
+	VkMemoryPropertyFlags preferFlags,
+	VkMemoryPropertyFlags avoidFlags) const
+{
+	U preferedHigh = MAX_U32;
+	U preferedMed = MAX_U32;
+
+	// Iterate all mem types
+	for(U i = 0; i < m_memoryProperties.memoryTypeCount; i++)
+	{
+		if(resourceMemTypeBits & (1u << i))
+		{
+			VkMemoryPropertyFlags flags =
+				m_memoryProperties.memoryTypes[i].propertyFlags;
+
+			if((flags & preferFlags) == preferFlags)
+			{
+				preferedMed = i;
+
+				if((flags & avoidFlags) != avoidFlags)
+				{
+					preferedHigh = i;
+				}
+			}
+		}
+	}
+
+	if(preferedHigh < MAX_U32)
+	{
+		return preferedHigh;
+	}
+	else
+	{
+		return preferedMed;
+	}
+}
+
+} // end namespace anki

+ 64 - 9
src/anki/gr/vulkan/GpuMemoryAllocator.h

@@ -21,11 +21,12 @@ class GpuMemoryAllocatorClass;
 /// The handle that is returned from GpuMemoryAllocator's allocations.
 class GpuMemoryAllocationHandle
 {
-	friend class GpuMemoryAllocator;
+	friend class GpuMemoryAllocatorMemType;
 
 public:
 	VkDeviceMemory m_memory = VK_NULL_HANDLE;
 	PtrSize m_offset = MAX_PTR_SIZE;
+	U32 m_memoryTypeIndex = MAX_U32;
 
 	Bool isEmpty() const
 	{
@@ -41,21 +42,24 @@ private:
 	GpuMemoryAllocatorChunk* m_chunk = nullptr;
 };
 
-/// Dynamic GPU memory allocator.
-class GpuMemoryAllocator
+/// Dynamic GPU memory allocator for a specific type.
+class GpuMemoryAllocatorMemType
 {
 public:
-	GpuMemoryAllocator()
+	GpuMemoryAllocatorMemType()
 	{
 	}
 
-	~GpuMemoryAllocator();
+	~GpuMemoryAllocatorMemType();
 
 	void init(
 		GenericMemoryPoolAllocator<U8> alloc, VkDevice dev, U memoryTypeIdx);
 
 	/// Allocate GPU memory.
-	void allocate(PtrSize size, U alignment, GpuMemoryAllocationHandle& handle);
+	void allocate(PtrSize size,
+		U alignment,
+		Bool linearResource,
+		GpuMemoryAllocationHandle& handle);
 
 	/// Free allocated memory.
 	void free(GpuMemoryAllocationHandle& handle);
@@ -77,14 +81,65 @@ private:
 
 	Class* findClass(PtrSize size, U32 alignment);
 
-	Chunk* findChunkWithUnusedSlot(Class& cl);
+	Chunk* findChunkWithUnusedSlot(Class& cl, Bool linearResource);
 
 	/// Create or recycle chunk.
-	Chunk& createChunk(Class& cl);
+	Chunk& createChunk(Class& cl, Bool linearResources);
 
 	/// Park the chunk.
 	void destroyChunk(Class& cl, Chunk& chunk);
 };
+
+/// Dynamic GPU memory allocator for all types.
+class GpuMemoryAllocator
+{
+public:
+	GpuMemoryAllocator()
+	{
+	}
+
+	~GpuMemoryAllocator();
+
+	void init(VkPhysicalDevice pdev, VkDevice dev, GrAllocator<U8> alloc);
+
+	void destroy();
+
+	/// Allocate memory.
+	void allocateMemory(U memTypeIdx,
+		PtrSize size,
+		U alignment,
+		Bool linearResource,
+		GpuMemoryAllocationHandle& handle)
+	{
+		m_gpuAllocs[memTypeIdx].allocate(
+			size, alignment, linearResource, handle);
+		handle.m_memoryTypeIndex = memTypeIdx;
+	}
+
+	/// Free memory.
+	void freeMemory(GpuMemoryAllocationHandle& handle)
+	{
+		m_gpuAllocs[handle.m_memoryTypeIndex].free(handle);
+	}
+
+	/// Map memory.
+	ANKI_USE_RESULT void* getMappedAddress(GpuMemoryAllocationHandle& handle)
+	{
+		return m_gpuAllocs[handle.m_memoryTypeIndex].getMappedAddress(handle);
+	}
+
+	/// Find a suitable memory type.
+	U findMemoryType(U resourceMemTypeBits,
+		VkMemoryPropertyFlags preferFlags,
+		VkMemoryPropertyFlags avoidFlags) const;
+
+private:
+	/// One for each mem type.
+	DynamicArray<GpuMemoryAllocatorMemType> m_gpuAllocs;
+	VkPhysicalDeviceMemoryProperties m_memoryProperties;
+	VkDevice m_dev;
+	GrAllocator<U8> m_alloc;
+};
 /// @}
 
-} // end namespace anki
+} // end namespace anki

+ 2 - 46
src/anki/gr/vulkan/GrManagerImpl.cpp

@@ -145,7 +145,7 @@ GrManagerImpl::~GrManagerImpl()
 	}
 
 	m_transientMem.destroy();
-	m_gpuMemAllocs.destroy(getAllocator());
+	m_gpuAlloc.destroy();
 
 	m_semaphores.destroy(); // Destroy before fences
 	m_fences.destroy();
@@ -716,13 +716,7 @@ Error GrManagerImpl::initMemory(const ConfigSet& cfg)
 {
 	vkGetPhysicalDeviceMemoryProperties(m_physicalDevice, &m_memoryProperties);
 
-	// Create the high level allocators
-	m_gpuMemAllocs.create(getAllocator(), m_memoryProperties.memoryTypeCount);
-	U idx = 0;
-	for(GpuMemoryAllocator& alloc : m_gpuMemAllocs)
-	{
-		alloc.init(getAllocator(), m_device, idx++);
-	}
+	m_gpuAlloc.init(m_physicalDevice, m_device, getAllocator());
 
 	// Transient mem
 	ANKI_CHECK(m_transientMem.init(cfg));
@@ -730,44 +724,6 @@ Error GrManagerImpl::initMemory(const ConfigSet& cfg)
 	return ErrorCode::NONE;
 }
 
-//==============================================================================
-U GrManagerImpl::findMemoryType(U resourceMemTypeBits,
-	VkMemoryPropertyFlags preferFlags,
-	VkMemoryPropertyFlags avoidFlags) const
-{
-	U preferedHigh = MAX_U32;
-	U preferedMed = MAX_U32;
-
-	// Iterate all mem types
-	for(U i = 0; i < m_memoryProperties.memoryTypeCount; i++)
-	{
-		if(resourceMemTypeBits & (1u << i))
-		{
-			VkMemoryPropertyFlags flags =
-				m_memoryProperties.memoryTypes[i].propertyFlags;
-
-			if((flags & preferFlags) == preferFlags)
-			{
-				preferedMed = i;
-
-				if((flags & avoidFlags) != avoidFlags)
-				{
-					preferedHigh = i;
-				}
-			}
-		}
-	}
-
-	if(preferedHigh < MAX_U32)
-	{
-		return preferedHigh;
-	}
-	else
-	{
-		return preferedMed;
-	}
-}
-
 //==============================================================================
 void* GrManagerImpl::allocateCallback(void* userData,
 	size_t size,

+ 4 - 23
src/anki/gr/vulkan/GrManagerImpl.h

@@ -162,30 +162,11 @@ public:
 
 	/// @name Memory
 	/// @{
-	void allocateMemory(U memTypeIdx,
-		PtrSize size,
-		U alignment,
-		GpuMemoryAllocationHandle& handle)
+	GpuMemoryAllocator& getGpuMemoryAllocator()
 	{
-		m_gpuMemAllocs[memTypeIdx].allocate(size, alignment, handle);
+		return m_gpuAlloc;
 	}
 
-	void freeMemory(U memTypeIdx, GpuMemoryAllocationHandle& handle)
-	{
-		m_gpuMemAllocs[memTypeIdx].free(handle);
-	}
-
-	ANKI_USE_RESULT void* getMappedAddress(
-		U memTypeIdx, GpuMemoryAllocationHandle& handle)
-	{
-		return m_gpuMemAllocs[memTypeIdx].getMappedAddress(handle);
-	}
-
-	/// Find a suitable memory type.
-	U findMemoryType(U resourceMemTypeBits,
-		VkMemoryPropertyFlags preferFlags,
-		VkMemoryPropertyFlags avoidFlags) const;
-
 	TransientMemoryManager& getTransientMemoryManager()
 	{
 		return m_transientMem;
@@ -263,8 +244,8 @@ private:
 	/// @{
 	VkPhysicalDeviceMemoryProperties m_memoryProperties;
 
-	/// One for each mem type.
-	DynamicArray<GpuMemoryAllocator> m_gpuMemAllocs;
+	/// The main allocator.
+	GpuMemoryAllocator m_gpuAlloc;
 
 	TransientMemoryManager m_transientMem;
 	/// @}

+ 1 - 1
src/anki/gr/vulkan/ResourceGroupImpl.cpp

@@ -233,7 +233,7 @@ Error ResourceGroupImpl::init(const ResourceGroupInitInfo& init)
 				init.m_textures[i].m_texture->getImplementation();
 
 			VkDescriptorImageInfo& inf = texes[i];
-			inf.imageView = teximpl.m_viewHandle;
+			inf.imageView = teximpl.getOrCreateResourceGroupView();
 
 			m_refs[refCount++] = init.m_textures[i].m_texture;
 

+ 66 - 151
src/anki/gr/vulkan/TextureImpl.cpp

@@ -14,21 +14,6 @@
 namespace anki
 {
 
-//==============================================================================
-// TextureImpl::CreateContext                                                  =
-//==============================================================================
-
-class TextureImpl::CreateContext
-{
-public:
-	TextureInitInfo m_init;
-	VkImageCreateInfo m_imgCi = {};
-};
-
-//==============================================================================
-// TextureImpl                                                                 =
-//==============================================================================
-
 //==============================================================================
 TextureImpl::TextureImpl(GrManager* manager)
 	: VulkanObject(manager)
@@ -38,20 +23,15 @@ TextureImpl::TextureImpl(GrManager* manager)
 //==============================================================================
 TextureImpl::~TextureImpl()
 {
-	if(m_viewHandle)
-	{
-		vkDestroyImageView(getDevice(), m_viewHandle, nullptr);
-	}
-
-	for(VkImageView view : m_singleSurfaceViews)
+	for(auto it : m_viewsMap)
 	{
-		if(view)
+		if(it != VK_NULL_HANDLE)
 		{
-			vkDestroyImageView(getDevice(), view, nullptr);
+			vkDestroyImageView(getDevice(), it, nullptr);
 		}
 	}
 
-	m_singleSurfaceViews.destroy(getAllocator());
+	m_viewsMap.destroy(getAllocator());
 
 	if(m_imageHandle)
 	{
@@ -60,7 +40,7 @@ TextureImpl::~TextureImpl()
 
 	if(m_memHandle)
 	{
-		getGrManagerImpl().freeMemory(m_memIdx, m_memHandle);
+		getGrManagerImpl().getGpuMemoryAllocator().freeMemory(m_memHandle);
 	}
 }
 
@@ -170,10 +150,25 @@ Error TextureImpl::init(const TextureInitInfo& init_, Texture* tex)
 	m_aspect = convertImageAspect(m_format);
 	m_usage = init.m_usage;
 
-	CreateContext ctx;
-	ctx.m_init = init;
-	ANKI_CHECK(initImage(ctx));
-	ANKI_CHECK(initView(ctx));
+	ANKI_CHECK(initImage(init));
+
+	// Init the template
+	m_viewCreateInfoTemplate = {};
+	m_viewCreateInfoTemplate.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+	m_viewCreateInfoTemplate.image = m_imageHandle;
+	m_viewCreateInfoTemplate.viewType = convertTextureViewType(init.m_type);
+	m_viewCreateInfoTemplate.format = m_vkFormat;
+	m_viewCreateInfoTemplate.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
+	m_viewCreateInfoTemplate.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
+	m_viewCreateInfoTemplate.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
+	m_viewCreateInfoTemplate.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
+	m_viewCreateInfoTemplate.subresourceRange.aspectMask = m_aspect;
+	m_viewCreateInfoTemplate.subresourceRange.baseArrayLayer = 0;
+	m_viewCreateInfoTemplate.subresourceRange.baseMipLevel = 0;
+	m_viewCreateInfoTemplate.subresourceRange.layerCount =
+		VK_REMAINING_ARRAY_LAYERS;
+	m_viewCreateInfoTemplate.subresourceRange.levelCount =
+		VK_REMAINING_MIP_LEVELS;
 
 	// Transition the image layout from undefined to something relevant
 	if(!!init.m_initialUsage)
@@ -215,9 +210,9 @@ Error TextureImpl::init(const TextureInitInfo& init_, Texture* tex)
 }
 
 //==============================================================================
-Error TextureImpl::initImage(CreateContext& ctx)
+Error TextureImpl::initImage(const TextureInitInfo& init_)
 {
-	TextureInitInfo& init = ctx.m_init;
+	TextureInitInfo init = init_;
 
 	// Check if format is supported
 	Bool supported;
@@ -247,17 +242,15 @@ Error TextureImpl::initImage(CreateContext& ctx)
 	}
 
 	// Contunue with the creation
-	m_type = init.m_type;
-
-	VkImageCreateInfo& ci = ctx.m_imgCi;
+	VkImageCreateInfo ci = {};
 	ci.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
 	ci.flags = calcCreateFlags(init);
-	ci.imageType = convertTextureType(init.m_type);
+	ci.imageType = convertTextureType(m_type);
 	ci.format = m_vkFormat;
 	ci.extent.width = init.m_width;
 	ci.extent.height = init.m_height;
 
-	switch(init.m_type)
+	switch(m_type)
 	{
 	case TextureType::_1D:
 	case TextureType::_2D:
@@ -302,22 +295,23 @@ Error TextureImpl::initImage(CreateContext& ctx)
 	VkMemoryRequirements req = {};
 	vkGetImageMemoryRequirements(getDevice(), m_imageHandle, &req);
 
-	m_memIdx = getGrManagerImpl().findMemoryType(req.memoryTypeBits,
+	U memIdx = getGrManagerImpl().getGpuMemoryAllocator().findMemoryType(
+		req.memoryTypeBits,
 		VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
 		VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
 
 	// Fallback
-	if(m_memIdx == MAX_U32)
+	if(memIdx == MAX_U32)
 	{
-		m_memIdx = getGrManagerImpl().findMemoryType(
+		memIdx = getGrManagerImpl().getGpuMemoryAllocator().findMemoryType(
 			req.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0);
 	}
 
-	ANKI_ASSERT(m_memIdx != MAX_U32);
+	ANKI_ASSERT(memIdx != MAX_U32);
 
 	// Allocate
-	getGrManagerImpl().allocateMemory(
-		m_memIdx, req.size, req.alignment, m_memHandle);
+	getGrManagerImpl().getGpuMemoryAllocator().allocateMemory(
+		memIdx, req.size, req.alignment, false, m_memHandle);
 
 	// Bind mem to image
 	ANKI_VK_CHECK(vkBindImageMemory(getDevice(),
@@ -328,31 +322,6 @@ Error TextureImpl::initImage(CreateContext& ctx)
 	return ErrorCode::NONE;
 }
 
-//==============================================================================
-Error TextureImpl::initView(CreateContext& ctx)
-{
-	const TextureInitInfo& init = ctx.m_init;
-
-	VkImageViewCreateInfo ci = {};
-	ci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
-	ci.image = m_imageHandle;
-	ci.viewType = convertTextureViewType(init.m_type);
-	ci.format = ctx.m_imgCi.format;
-	ci.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
-	ci.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
-	ci.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
-	ci.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
-	ci.subresourceRange.aspectMask = m_aspect;
-	ci.subresourceRange.baseArrayLayer = 0;
-	ci.subresourceRange.baseMipLevel = 0;
-	ci.subresourceRange.layerCount = ctx.m_imgCi.arrayLayers;
-	ci.subresourceRange.levelCount = ctx.m_imgCi.mipLevels;
-
-	ANKI_VK_CHECK(vkCreateImageView(getDevice(), &ci, nullptr, &m_viewHandle));
-
-	return ErrorCode::NONE;
-}
-
 //==============================================================================
 void TextureImpl::computeBarrierInfo(TextureUsageBit before,
 	TextureUsageBit after,
@@ -655,106 +624,52 @@ VkImageView TextureImpl::getOrCreateSingleSurfaceView(
 {
 	checkSurface(surf);
 
-	// If it's single surface return the single view
-	if(m_mipCount == 1 && m_depth == 1 && m_layerCount == 1
-		&& m_type != TextureType::CUBE
-		&& m_type != TextureType::CUBE_ARRAY)
-	{
-		return m_viewHandle;
-	}
-
-	Bool isCube =
-		m_type == TextureType::CUBE || m_type == TextureType::CUBE_ARRAY;
-	U faceCount = (isCube) ? 6 : 1;
-
-	LockGuard<Mutex> lock(m_singleSurfaceViewsMtx);
-
-	// Create the array
-	if(m_singleSurfaceViews.isEmpty())
-	{
-		U surfCount = m_mipCount * m_depth * faceCount * m_layerCount;
-
-		m_singleSurfaceViews.create(getAllocator(), surfCount);
-		memset(&m_singleSurfaceViews[0],
-			0,
-			sizeof(m_singleSurfaceViews[0]) * surfCount);
-	}
+	VkImageViewCreateInfo ci = m_viewCreateInfoTemplate;
+	ci.viewType = VK_IMAGE_VIEW_TYPE_2D;
+	computeSubResourceRange(surf, ci.subresourceRange);
 
-	// [level][depth][face][layer]
-	U surfIdx = surf.m_level * m_depth * faceCount * m_layerCount
-		+ surf.m_depth * faceCount * m_layerCount + surf.m_face * m_layerCount
-		+ surf.m_layer;
-
-	VkImageView& view = m_singleSurfaceViews[surfIdx];
-	if(ANKI_UNLIKELY(view == VK_NULL_HANDLE))
-	{
-		VkImageViewCreateInfo ci = {};
-		ci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
-		ci.image = m_imageHandle;
-		ci.viewType = VK_IMAGE_VIEW_TYPE_2D;
-		ci.format = m_vkFormat;
-		ci.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
-		ci.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
-		ci.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
-		ci.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
+	return getOrCreateView(ci);
+}
 
-		computeSubResourceRange(surf, ci.subresourceRange);
+//==============================================================================
+VkImageView TextureImpl::getOrCreateSingleLevelView(U level)
+{
+	ANKI_ASSERT(level < m_mipCount);
 
-		ANKI_VK_CHECKF(vkCreateImageView(getDevice(), &ci, nullptr, &view));
-	}
+	VkImageViewCreateInfo ci = m_viewCreateInfoTemplate;
+	ci.subresourceRange.baseMipLevel = level;
+	ci.subresourceRange.levelCount = 1;
 
-	ANKI_ASSERT(view);
-	return view;
+	return getOrCreateView(ci);
 }
 
 //==============================================================================
-VkImageView TextureImpl::getOrCreateSingleLevelView(U level)
+VkImageView TextureImpl::getOrCreateResourceGroupView()
 {
-	ANKI_ASSERT(level < m_mipCount);
+	VkImageViewCreateInfo ci = m_viewCreateInfoTemplate;
+	ci.subresourceRange.aspectMask = m_aspect & (~VK_IMAGE_ASPECT_STENCIL_BIT);
 
-	// If it's single level return the single view
-	if(m_mipCount == 1)
-	{
-		return m_viewHandle;
-	}
+	return getOrCreateView(ci);
+}
 
-	LockGuard<Mutex> lock(m_singleLevelViewsMtx);
+//==============================================================================
+VkImageView TextureImpl::getOrCreateView(const VkImageViewCreateInfo& ci)
+{
+	LockGuard<Mutex> lock(m_viewsMapMtx);
+	auto it = m_viewsMap.find(ci);
 
-	// Create the array
-	if(m_singleLevelViews.isEmpty())
+	if(it != m_viewsMap.getEnd())
 	{
-		m_singleLevelViews.create(getAllocator(), m_mipCount);
-		memset(&m_singleLevelViews[0],
-			0,
-			sizeof(m_singleLevelViews[0]) * m_mipCount);
+		return *it;
 	}
-
-	VkImageView& view = m_singleLevelViews[level];
-	if(ANKI_UNLIKELY(view == VK_NULL_HANDLE))
+	else
 	{
-		VkImageSubresourceRange range;
-		range.aspectMask = m_aspect;
-		range.baseMipLevel = level;
-		range.levelCount = 1;
-		range.baseArrayLayer = 0;
-		range.layerCount = VK_REMAINING_ARRAY_LAYERS;
-
-		VkImageViewCreateInfo ci = {};
-		ci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
-		ci.image = m_imageHandle;
-		ci.viewType = convertTextureViewType(m_type);
-		ci.format = m_vkFormat;
-		ci.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
-		ci.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
-		ci.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
-		ci.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
-		ci.subresourceRange = range;
-
+		VkImageView view = VK_NULL_HANDLE;
 		ANKI_VK_CHECKF(vkCreateImageView(getDevice(), &ci, nullptr, &view));
-	}
+		m_viewsMap.pushBack(getAllocator(), ci, view);
 
-	ANKI_ASSERT(view);
-	return view;
+		return view;
+	}
 }
 
 } // end namespace anki

+ 30 - 13
src/anki/gr/vulkan/TextureImpl.h

@@ -9,6 +9,7 @@
 #include <anki/gr/vulkan/GpuMemoryAllocator.h>
 #include <anki/gr/vulkan/Semaphore.h>
 #include <anki/gr/common/Misc.h>
+#include <anki/util/HashMap.h>
 
 namespace anki
 {
@@ -30,9 +31,7 @@ public:
 	SamplerPtr m_sampler;
 
 	VkImage m_imageHandle = VK_NULL_HANDLE;
-	VkImageView m_viewHandle = VK_NULL_HANDLE;
 
-	U32 m_memIdx = MAX_U32;
 	GpuMemoryAllocationHandle m_memHandle;
 
 	U32 m_width = 0;
@@ -89,6 +88,9 @@ public:
 
 	VkImageView getOrCreateSingleLevelView(U level);
 
+	/// That view will be used in descriptor sets.
+	VkImageView getOrCreateResourceGroupView();
+
 	/// By knowing the previous and new texture usage calculate the relavant
 	/// info for a ppline barrier.
 	void computeBarrierInfo(TextureUsageBit before,
@@ -103,15 +105,29 @@ public:
 	VkImageLayout computeLayout(TextureUsageBit usage, U level) const;
 
 private:
-	class CreateContext;
-
-	/// A number of views, one for each surface. Used in image load/store.
-	DynamicArray<VkImageView> m_singleSurfaceViews;
-	Mutex m_singleSurfaceViewsMtx;
-
-	/// A number of views, one for each level. Used in image load/store.
-	DynamicArray<VkImageView> m_singleLevelViews;
-	Mutex m_singleLevelViewsMtx;
+	class ViewHasher
+	{
+	public:
+		U64 operator()(const VkImageViewCreateInfo& b) const
+		{
+			return computeHash(&b, sizeof(b));
+		}
+	};
+
+	class ViewCompare
+	{
+	public:
+		Bool operator()(const VkImageViewCreateInfo& a,
+			const VkImageViewCreateInfo& b) const
+		{
+			return memcmp(&a, &b, sizeof(a)) == 0;
+		}
+	};
+
+	HashMap<VkImageViewCreateInfo, VkImageView, ViewHasher, ViewCompare>
+		m_viewsMap;
+	Mutex m_viewsMapMtx;
+	VkImageViewCreateInfo m_viewCreateInfoTemplate;
 
 	ANKI_USE_RESULT static VkFormatFeatureFlags calcFeatures(
 		const TextureInitInfo& init);
@@ -121,8 +137,9 @@ private:
 
 	ANKI_USE_RESULT Bool imageSupported(const TextureInitInfo& init);
 
-	ANKI_USE_RESULT Error initImage(CreateContext& ctx);
-	ANKI_USE_RESULT Error initView(CreateContext& ctx);
+	ANKI_USE_RESULT Error initImage(const TextureInitInfo& init);
+
+	VkImageView getOrCreateView(const VkImageViewCreateInfo& ci);
 };
 
 //==============================================================================

+ 17 - 3
src/anki/renderer/Ssao.cpp

@@ -130,10 +130,24 @@ Error Ssao::initInternal(const ConfigSet& config)
 	Array<Vec3, NOISE_TEX_SIZE * NOISE_TEX_SIZE> noise;
 	genNoise(&noise[0], &noise[0] + noise.getSize());
 
-	CommandBufferPtr cmdb =
-		gr.newInstance<CommandBuffer>(CommandBufferInitInfo());
+	CommandBufferInitInfo cmdbInit;
+	cmdbInit.m_flags = CommandBufferFlag::SMALL_BATCH;
+
+	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, TextureSurfaceInfo(0, 0, 0, 0), &noise[0], sizeof(noise));
+		m_noiseTex, surf, &noise[0], sizeof(noise));
+
+	cmdb->setTextureSurfaceBarrier(m_noiseTex,
+		TextureUsageBit::UPLOAD,
+		TextureUsageBit::SAMPLED_FRAGMENT,
+		surf);
+
 	cmdb->flush();
 
 	//