Browse Source

Vulkan: Adding storage & image load/store support

Panagiotis Christopoulos Charitos 9 years ago
parent
commit
3389ead88c

+ 3 - 3
include/anki/gr/Enums.h

@@ -170,12 +170,12 @@ enum class TextureUsageBit : U16
 	GEOMETRY_SHADER_SAMPLED = 1 << 3,
 	FRAGMENT_SHADER_SAMPLED = 1 << 4,
 	COMPUTE_SHADER_SAMPLED = 1 << 5,
-	ANY_SHADER_SAMPLED = VERTEX_SHADER_SAMPLED
+	ANY_GRAPHICS_SHADER_SAMPLED = VERTEX_SHADER_SAMPLED
 		| TESSELLATION_CONTROL_SHADER_SAMPLED
 		| TESSELLATION_EVALUATION_SHADER_SAMPLED
 		| GEOMETRY_SHADER_SAMPLED
-		| FRAGMENT_SHADER_SAMPLED
-		| COMPUTE_SHADER_SAMPLED,
+		| FRAGMENT_SHADER_SAMPLED,
+	ANY_SHADER_SAMPLED = ANY_GRAPHICS_SHADER_SAMPLED | COMPUTE_SHADER_SAMPLED,
 	/// @}
 
 	/// @name Image_load_store

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

@@ -22,6 +22,7 @@ class TextureBinding
 public:
 	TexturePtr m_texture;
 	SamplerPtr m_sampler; ///< Use it to override texture's sampler.
+	TextureUsageBit m_usage = TextureUsageBit::FRAGMENT_SHADER_SAMPLED;
 };
 
 /// Buffer binding info.
@@ -40,6 +41,7 @@ class ImageBinding
 public:
 	TexturePtr m_texture;
 	U8 m_level = 0;
+	TextureUsageBit m_usage = TextureUsageBit::COMPUTE_SHADER_IMAGE_READ_WRITE;
 };
 
 /// Resource group initializer.

+ 3 - 8
include/anki/gr/vulkan/CommandBufferImpl.inl.h

@@ -112,7 +112,6 @@ inline void CommandBufferImpl::setImageBarrier(TexturePtr tex,
 	ANKI_ASSERT(impl.usageValid(nextUsage));
 
 	impl.checkSurface(surf);
-	Bool isDepthStencil = formatIsDepthStencil(impl.m_format);
 
 	VkPipelineStageFlags srcStage;
 	VkAccessFlags srcAccess;
@@ -120,19 +119,15 @@ inline void CommandBufferImpl::setImageBarrier(TexturePtr tex,
 	VkPipelineStageFlags dstStage;
 	VkAccessFlags dstAccess;
 	VkImageLayout newLayout;
-	computeBarrierInfo(prevUsage,
+	impl.computeBarrierInfo(prevUsage,
 		nextUsage,
-		isDepthStencil,
 		surf.m_level,
-		impl.m_mipCount,
 		srcStage,
 		srcAccess,
 		dstStage,
 		dstAccess);
-	oldLayout =
-		computeLayout(prevUsage, isDepthStencil, surf.m_level, impl.m_mipCount);
-	newLayout =
-		computeLayout(nextUsage, isDepthStencil, surf.m_level, impl.m_mipCount);
+	oldLayout = impl.computeLayout(prevUsage, surf.m_level);
+	newLayout = impl.computeLayout(nextUsage, surf.m_level);
 
 	VkImageSubresourceRange range;
 	impl.computeSubResourceRange(surf, range);

+ 0 - 16
include/anki/gr/vulkan/Common.h

@@ -58,22 +58,6 @@ ANKI_USE_RESULT inline Bool formatIsDepthStencil(PixelFormat fmt)
 	}
 }
 
-/// By knowing the previous and new texture usage calculate the relavant info
-/// for a ppline barrier.
-void computeBarrierInfo(TextureUsageBit before,
-	TextureUsageBit after,
-	Bool isDepthStencil,
-	U level,
-	U levelCount,
-	VkPipelineStageFlags& srcStages,
-	VkAccessFlags& srcAccesses,
-	VkPipelineStageFlags& dstStages,
-	VkAccessFlags& dstAccesses);
-
-/// Predict the image layout.
-ANKI_USE_RESULT VkImageLayout computeLayout(
-	TextureUsageBit usage, Bool isDepthStencil, U level, U levelCount);
-
 /// Convert compare op.
 ANKI_USE_RESULT VkCompareOp convertCompareOp(CompareOperation ak);
 

+ 2 - 3
include/anki/gr/vulkan/FramebufferImpl.h

@@ -76,9 +76,8 @@ private:
 
 	ANKI_USE_RESULT Error initRenderPass(const FramebufferInitInfo& init);
 
-	void setupAttachmentDescriptor(const FramebufferAttachmentInfo& in,
-		VkAttachmentDescription& out,
-		Bool depthStencil);
+	void setupAttachmentDescriptor(
+		const FramebufferAttachmentInfo& in, VkAttachmentDescription& out);
 
 	ANKI_USE_RESULT Error initFramebuffer(const FramebufferInitInfo& init);
 };

+ 3 - 1
include/anki/gr/vulkan/ResourceGroupImpl.h

@@ -74,6 +74,7 @@ private:
 
 	// For dynamic binding
 	U8 m_uniBindingCount = 0;
+	U8 m_storageBindingCount = 0;
 	BitSet<MAX_UNIFORM_BUFFER_BINDINGS + MAX_STORAGE_BUFFER_BINDINGS>
 		m_dynamicBuffersMask = {false};
 
@@ -86,7 +87,8 @@ private:
 	/// gracefully
 	DynamicArray<GrObjectPtr<GrObject>> m_refs;
 
-	static U calcRefCount(const ResourceGroupInitInfo& init, Bool& hasUploaded);
+	static U calcRefCount(
+		const ResourceGroupInitInfo& init, Bool& hasUploaded, Bool& needsDSet);
 };
 /// @}
 

+ 21 - 1
include/anki/gr/vulkan/TextureImpl.h

@@ -20,9 +20,14 @@ namespace anki
 class TextureImpl : public VulkanObject
 {
 public:
+	SamplerPtr m_sampler;
+
 	VkImage m_imageHandle = VK_NULL_HANDLE;
 	VkImageView m_viewHandle = VK_NULL_HANDLE;
-	SamplerPtr m_sampler;
+
+	/// A number of views, one for each level. Used in image load/store.
+	DynamicArray<VkImageView> m_viewsEveryLevel;
+
 	U32 m_memIdx = MAX_U32;
 	GpuMemoryAllocationHandle m_memHandle;
 
@@ -36,6 +41,8 @@ public:
 	TextureUsageBit m_usage = TextureUsageBit::NONE;
 	PixelFormat m_format;
 
+	Bool m_depthStencil = false;
+
 	TextureImpl(GrManager* manager);
 
 	~TextureImpl();
@@ -55,6 +62,19 @@ public:
 		return (usage & m_usage) == usage;
 	}
 
+	/// By knowing the previous and new texture usage calculate the relavant
+	/// info for a ppline barrier.
+	void computeBarrierInfo(TextureUsageBit before,
+		TextureUsageBit after,
+		U level,
+		VkPipelineStageFlags& srcStages,
+		VkAccessFlags& srcAccesses,
+		VkPipelineStageFlags& dstStages,
+		VkAccessFlags& dstAccesses) const;
+
+	/// Predict the image layout.
+	VkImageLayout computeLayout(TextureUsageBit usage, U level) const;
+
 private:
 	class CreateContext;
 

+ 0 - 258
src/gr/vulkan/Common.cpp

@@ -8,264 +8,6 @@
 namespace anki
 {
 
-//==============================================================================
-void computeBarrierInfo(TextureUsageBit before,
-	TextureUsageBit after,
-	Bool isDepthStencil,
-	U level,
-	U levelCount,
-	VkPipelineStageFlags& srcStages,
-	VkAccessFlags& srcAccesses,
-	VkPipelineStageFlags& dstStages,
-	VkAccessFlags& dstAccesses)
-{
-	ANKI_ASSERT(level < levelCount && levelCount > 0);
-	srcStages = 0;
-	srcAccesses = 0;
-	dstStages = 0;
-	dstAccesses = 0;
-	Bool lastLevel = level == levelCount - 1;
-
-	//
-	// Before
-	//
-	if((before & TextureUsageBit::FRAGMENT_SHADER_SAMPLED)
-		!= TextureUsageBit::NONE)
-	{
-		srcStages |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
-		srcAccesses |= VK_ACCESS_SHADER_READ_BIT;
-	}
-
-	if((before & TextureUsageBit::COMPUTE_SHADER_SAMPLED)
-		!= TextureUsageBit::NONE)
-	{
-		srcStages |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
-		srcAccesses |= VK_ACCESS_SHADER_READ_BIT;
-	}
-
-	if((before & TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ)
-		!= TextureUsageBit::NONE)
-	{
-		if(isDepthStencil)
-		{
-			srcStages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
-				| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
-			srcAccesses |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
-		}
-		else
-		{
-			srcStages |= VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
-			srcAccesses |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
-		}
-	}
-
-	if((before & TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE)
-		!= TextureUsageBit::NONE)
-	{
-		srcStages |= VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
-
-		if(isDepthStencil)
-		{
-			srcAccesses |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
-		}
-		else
-		{
-			srcAccesses |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
-		}
-	}
-
-	if((before & TextureUsageBit::GENERATE_MIPMAPS) != TextureUsageBit::NONE)
-	{
-		srcStages |= VK_PIPELINE_STAGE_TRANSFER_BIT;
-
-		if(!lastLevel)
-		{
-			srcAccesses |= VK_ACCESS_TRANSFER_READ_BIT;
-		}
-		else
-		{
-			srcAccesses |= VK_ACCESS_TRANSFER_WRITE_BIT;
-		}
-	}
-
-	if((before & TextureUsageBit::UPLOAD) != TextureUsageBit::NONE)
-	{
-		srcStages |= VK_PIPELINE_STAGE_TRANSFER_BIT;
-		srcAccesses |= VK_ACCESS_TRANSFER_WRITE_BIT;
-	}
-
-	if((before & TextureUsageBit::CLEAR) != TextureUsageBit::NONE)
-	{
-		srcStages |= VK_PIPELINE_STAGE_TRANSFER_BIT;
-		srcAccesses |= VK_ACCESS_TRANSFER_WRITE_BIT;
-	}
-
-	if(srcStages == 0)
-	{
-		srcStages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
-	}
-
-	//
-	// After
-	//
-	if((after & TextureUsageBit::FRAGMENT_SHADER_SAMPLED)
-		!= TextureUsageBit::NONE)
-	{
-		dstStages |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
-		dstAccesses |= VK_ACCESS_SHADER_READ_BIT;
-	}
-
-	if((after & TextureUsageBit::COMPUTE_SHADER_SAMPLED)
-		!= TextureUsageBit::NONE)
-	{
-		dstStages |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
-		dstAccesses |= VK_ACCESS_SHADER_READ_BIT;
-	}
-
-	if((after & TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ)
-		!= TextureUsageBit::NONE)
-	{
-		if(isDepthStencil)
-		{
-			dstStages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
-				| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
-			dstAccesses |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
-		}
-		else
-		{
-			dstStages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
-			dstAccesses |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
-		}
-	}
-
-	if((after & TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE)
-		!= TextureUsageBit::NONE)
-	{
-		if(isDepthStencil)
-		{
-			dstStages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
-				| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
-			dstAccesses |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
-		}
-		else
-		{
-			dstStages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
-			dstAccesses |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
-		}
-	}
-
-	if((after & TextureUsageBit::GENERATE_MIPMAPS) != TextureUsageBit::NONE)
-	{
-		dstStages |= VK_PIPELINE_STAGE_TRANSFER_BIT;
-
-		if(level == 0)
-		{
-			dstAccesses |= VK_ACCESS_TRANSFER_READ_BIT;
-		}
-		else
-		{
-			ANKI_ASSERT(0 && "This will happen in generateMipmaps");
-		}
-	}
-
-	if((after & TextureUsageBit::UPLOAD) != TextureUsageBit::NONE)
-	{
-		dstStages |= VK_PIPELINE_STAGE_TRANSFER_BIT;
-		dstAccesses |= VK_ACCESS_TRANSFER_WRITE_BIT;
-	}
-
-	if((after & TextureUsageBit::CLEAR) != TextureUsageBit::NONE)
-	{
-		dstStages |= VK_PIPELINE_STAGE_TRANSFER_BIT;
-		dstAccesses |= VK_ACCESS_TRANSFER_WRITE_BIT;
-	}
-
-	ANKI_ASSERT(dstStages);
-}
-
-//==============================================================================
-VkImageLayout computeLayout(
-	TextureUsageBit usage, Bool isDepthStencil, U level, U levelCount)
-{
-	ANKI_ASSERT(level < levelCount && levelCount > 0);
-
-	VkImageLayout out = VK_IMAGE_LAYOUT_MAX_ENUM;
-	Bool lastLevel = level == levelCount - 1;
-
-	if(usage == TextureUsageBit::NONE)
-	{
-		out = VK_IMAGE_LAYOUT_UNDEFINED;
-	}
-	else if(isDepthStencil)
-	{
-		if(usage == TextureUsageBit::FRAGMENT_SHADER_SAMPLED
-			|| usage == TextureUsageBit::COMPUTE_SHADER_SAMPLED)
-		{
-			out = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
-		}
-		else if(usage == TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE
-			|| usage == TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ_WRITE)
-		{
-			out = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
-		}
-		else if(usage == (TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ
-							 | TextureUsageBit::FRAGMENT_SHADER_SAMPLED))
-		{
-			out = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
-		}
-		else if(usage == TextureUsageBit::GENERATE_MIPMAPS)
-		{
-			if(!lastLevel)
-			{
-				out = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
-			}
-			else
-			{
-				out = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
-			}
-		}
-		else if(usage == TextureUsageBit::CLEAR)
-		{
-			out = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
-		}
-	}
-	else
-	{
-		if(usage == TextureUsageBit::FRAGMENT_SHADER_SAMPLED
-			|| usage == TextureUsageBit::COMPUTE_SHADER_SAMPLED)
-		{
-			out = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
-		}
-		else if(usage == TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ_WRITE
-			|| usage == TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE)
-		{
-			out = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
-		}
-		else if(usage == TextureUsageBit::GENERATE_MIPMAPS)
-		{
-			if(!lastLevel)
-			{
-				out = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
-			}
-			else
-			{
-				out = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
-			}
-		}
-		else if(usage == TextureUsageBit::UPLOAD)
-		{
-			out = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
-		}
-		else if(usage == TextureUsageBit::CLEAR)
-		{
-			out = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
-		}
-	}
-
-	ANKI_ASSERT(out != VK_IMAGE_LAYOUT_MAX_ENUM);
-	return out;
-}
-
 //==============================================================================
 VkCompareOp convertCompareOp(CompareOperation ak)
 {

+ 25 - 12
src/gr/vulkan/FramebufferImpl.cpp

@@ -80,12 +80,20 @@ Error FramebufferImpl::init(const FramebufferInitInfo& init)
 
 //==============================================================================
 void FramebufferImpl::setupAttachmentDescriptor(
-	const FramebufferAttachmentInfo& att,
-	VkAttachmentDescription& desc,
-	Bool depthStencil)
+	const FramebufferAttachmentInfo& att, VkAttachmentDescription& desc)
 {
-	VkImageLayout layout =
-		computeLayout(att.m_usageInsideRenderPass, depthStencil, 0, 1);
+	// TODO This func won't work if it's default but this is a depth attachment
+
+	VkImageLayout layout;
+	if(m_defaultFramebuffer)
+	{
+		layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+	}
+	else
+	{
+		layout = att.m_texture->getImplementation().computeLayout(
+			att.m_usageInsideRenderPass, 0);
+	}
 
 	desc = {};
 	desc.format = (m_defaultFramebuffer)
@@ -115,11 +123,15 @@ Error FramebufferImpl::initRenderPass(const FramebufferInitInfo& init)
 
 	for(U i = 0; i < init.m_colorAttachmentCount; ++i)
 	{
-		setupAttachmentDescriptor(
-			init.m_colorAttachments[i], attachmentDescriptions[i], false);
+		const FramebufferAttachmentInfo& att = init.m_colorAttachments[i];
+
+		setupAttachmentDescriptor(att, attachmentDescriptions[i]);
 
 		references[i].attachment = i;
-		references[i].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+		references[i].layout = (att.m_texture)
+			? att.m_texture->getImplementation().computeLayout(
+				  att.m_usageInsideRenderPass, 0)
+			: VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
 
 		++ci.attachmentCount;
 	}
@@ -128,12 +140,13 @@ Error FramebufferImpl::initRenderPass(const FramebufferInitInfo& init)
 	if(hasDepthStencil)
 	{
 		setupAttachmentDescriptor(init.m_depthStencilAttachment,
-			attachmentDescriptions[ci.attachmentCount],
-			true);
+			attachmentDescriptions[ci.attachmentCount]);
 
 		dsReference.attachment = ci.attachmentCount;
-		dsReference.layout = computeLayout(
-			init.m_depthStencilAttachment.m_usageInsideRenderPass, true, 0, 1);
+		dsReference.layout =
+			init.m_depthStencilAttachment.m_texture->getImplementation()
+				.computeLayout(
+					init.m_depthStencilAttachment.m_usageInsideRenderPass, 0);
 
 		++ci.attachmentCount;
 	}

+ 16 - 2
src/gr/vulkan/GrManagerImpl.cpp

@@ -477,7 +477,7 @@ Error GrManagerImpl::initGlobalDsetLayout()
 	ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
 
 	const U BINDING_COUNT = MAX_TEXTURE_BINDINGS + MAX_UNIFORM_BUFFER_BINDINGS
-		+ MAX_STORAGE_BUFFER_BINDINGS;
+		+ MAX_STORAGE_BUFFER_BINDINGS + MAX_IMAGE_BINDINGS;
 	ci.bindingCount = BINDING_COUNT;
 
 	Array<VkDescriptorSetLayoutBinding, BINDING_COUNT> bindings;
@@ -522,6 +522,18 @@ Error GrManagerImpl::initGlobalDsetLayout()
 		++count;
 	}
 
+	// Images
+	for(U i = 0; i < MAX_IMAGE_BINDINGS; ++i)
+	{
+		VkDescriptorSetLayoutBinding& binding = bindings[count];
+		binding.binding = count;
+		binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
+		binding.descriptorCount = 1;
+		binding.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
+
+		++count;
+	}
+
 	ANKI_ASSERT(count == BINDING_COUNT);
 
 	ANKI_VK_CHECK(vkCreateDescriptorSetLayout(
@@ -533,13 +545,15 @@ Error GrManagerImpl::initGlobalDsetLayout()
 //==============================================================================
 Error GrManagerImpl::initGlobalDsetPool()
 {
-	Array<VkDescriptorPoolSize, 3> pools = {{}};
+	Array<VkDescriptorPoolSize, 4> pools = {{}};
 	pools[0] = VkDescriptorPoolSize{VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
 		MAX_TEXTURE_BINDINGS * MAX_RESOURCE_GROUPS};
 	pools[1] = VkDescriptorPoolSize{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
 		MAX_UNIFORM_BUFFER_BINDINGS * MAX_RESOURCE_GROUPS};
 	pools[2] = VkDescriptorPoolSize{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
 		MAX_STORAGE_BUFFER_BINDINGS * MAX_RESOURCE_GROUPS};
+	pools[3] = VkDescriptorPoolSize{VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
+		MAX_IMAGE_BINDINGS * MAX_RESOURCE_GROUPS};
 
 	VkDescriptorPoolCreateInfo ci = {};
 	ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;

+ 141 - 21
src/gr/vulkan/ResourceGroupImpl.cpp

@@ -26,21 +26,24 @@ ResourceGroupImpl::~ResourceGroupImpl()
 
 //==============================================================================
 U ResourceGroupImpl::calcRefCount(
-	const ResourceGroupInitInfo& init, Bool& hasUploaded)
+	const ResourceGroupInitInfo& init, Bool& hasUploaded, Bool& needsDSet)
 {
 	U count = 0;
 	hasUploaded = false;
+	needsDSet = false;
 
 	for(U i = 0; i < MAX_TEXTURE_BINDINGS; ++i)
 	{
 		if(init.m_textures[i].m_texture)
 		{
 			++count;
+			needsDSet = true;
 		}
 
 		if(init.m_textures[i].m_sampler)
 		{
 			++count;
+			needsDSet = true;
 		}
 	}
 
@@ -49,10 +52,35 @@ U ResourceGroupImpl::calcRefCount(
 		if(init.m_uniformBuffers[i].m_buffer)
 		{
 			++count;
+			needsDSet = true;
 		}
 		else if(init.m_uniformBuffers[i].m_uploadedMemory)
 		{
 			hasUploaded = true;
+			needsDSet = true;
+		}
+	}
+
+	for(U i = 0; i < MAX_STORAGE_BUFFER_BINDINGS; ++i)
+	{
+		if(init.m_storageBuffers[i].m_buffer)
+		{
+			++count;
+			needsDSet = true;
+		}
+		else if(init.m_storageBuffers[i].m_uploadedMemory)
+		{
+			hasUploaded = true;
+			needsDSet = true;
+		}
+	}
+
+	for(U i = 0; i < MAX_IMAGE_BINDINGS; ++i)
+	{
+		if(init.m_images[i].m_texture)
+		{
+			++count;
+			needsDSet = true;
 		}
 	}
 
@@ -73,8 +101,6 @@ U ResourceGroupImpl::calcRefCount(
 		++count;
 	}
 
-	// TODO: The rest of the resources
-
 	return count;
 }
 
@@ -84,20 +110,32 @@ Error ResourceGroupImpl::init(const ResourceGroupInitInfo& init)
 	// Store the references
 	//
 	Bool hasUploaded = false;
-	U refCount = calcRefCount(init, hasUploaded);
+	Bool needsDSet = false;
+	U refCount = calcRefCount(init, hasUploaded, needsDSet);
 	ANKI_ASSERT(refCount > 0 || hasUploaded);
 	if(refCount)
 	{
 		m_refs.create(getAllocator(), refCount);
 	}
 
+	// Create DSet
+	//
+	if(needsDSet)
+	{
+		ANKI_CHECK(getGrManagerImpl().allocateDescriptorSet(m_handle));
+	}
+
 	// Update
 	//
 	Array<VkDescriptorImageInfo, MAX_TEXTURE_BINDINGS> texes = {{}};
 	U texAndSamplerCount = 0;
 	Array<VkDescriptorBufferInfo, MAX_UNIFORM_BUFFER_BINDINGS> unis = {{}};
 	U uniCount = 0;
-	Array<VkWriteDescriptorSet, 2> write = {{}};
+	Array<VkDescriptorBufferInfo, MAX_STORAGE_BUFFER_BINDINGS> storages = {{}};
+	U storageCount = 0;
+	Array<VkDescriptorImageInfo, MAX_IMAGE_BINDINGS> images = {{}};
+	U imageCount = 0;
+	Array<VkWriteDescriptorSet, 4> write = {{}};
 	U writeCount = 0;
 	refCount = 0;
 
@@ -124,11 +162,11 @@ Error ResourceGroupImpl::init(const ResourceGroupInitInfo& init)
 			else
 			{
 				inf.sampler = teximpl.m_sampler->getImplementation().m_handle;
-				// No need for ref
+				// No need to ref
 			}
 
-			// TODO need another layout
-			inf.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+			inf.imageLayout =
+				teximpl.computeLayout(init.m_textures[i].m_usage, 0);
 
 			++texAndSamplerCount;
 		}
@@ -136,11 +174,6 @@ Error ResourceGroupImpl::init(const ResourceGroupInitInfo& init)
 
 	if(texAndSamplerCount)
 	{
-		if(m_handle == VK_NULL_HANDLE)
-		{
-			ANKI_CHECK(getGrManagerImpl().allocateDescriptorSet(m_handle));
-		}
-
 		VkWriteDescriptorSet& w = write[writeCount++];
 		w.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
 		w.descriptorCount = texAndSamplerCount;
@@ -186,11 +219,6 @@ Error ResourceGroupImpl::init(const ResourceGroupInitInfo& init)
 
 	if(uniCount)
 	{
-		if(m_handle == VK_NULL_HANDLE)
-		{
-			ANKI_CHECK(getGrManagerImpl().allocateDescriptorSet(m_handle));
-		}
-
 		VkWriteDescriptorSet& w = write[writeCount++];
 		w.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
 		w.descriptorCount = uniCount;
@@ -200,7 +228,85 @@ Error ResourceGroupImpl::init(const ResourceGroupInitInfo& init)
 		w.dstSet = m_handle;
 	}
 
-	// TODO Storage buffers
+	// 3nd the storage buffers
+	for(U i = 0; i < MAX_STORAGE_BUFFER_BINDINGS; ++i)
+	{
+		if(init.m_storageBuffers[i].m_buffer)
+		{
+			VkDescriptorBufferInfo& inf = storages[storageCount++];
+			inf.buffer = init.m_storageBuffers[i]
+							 .m_buffer->getImplementation()
+							 .getHandle();
+			inf.offset = init.m_storageBuffers[i].m_offset;
+			inf.range = init.m_storageBuffers[i].m_range;
+			if(inf.range == 0)
+			{
+				inf.range = VK_WHOLE_SIZE;
+			}
+
+			m_refs[refCount++] = init.m_storageBuffers[i].m_buffer;
+
+			m_storageBindingCount = i + 1;
+		}
+		else if(init.m_storageBuffers[i].m_uploadedMemory)
+		{
+			VkDescriptorBufferInfo& inf = storages[storageCount++];
+			inf.buffer =
+				getGrManagerImpl().getTransientMemoryManager().getBufferHandle(
+					BufferUsageBit::STORAGE_ANY);
+			inf.range = VK_WHOLE_SIZE;
+
+			m_dynamicBuffersMask.set(MAX_UNIFORM_BUFFER_BINDINGS + i);
+
+			m_storageBindingCount = i + 1;
+		}
+	}
+
+	if(storageCount)
+	{
+		VkWriteDescriptorSet& w = write[writeCount++];
+		w.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+		w.descriptorCount = storageCount;
+		w.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
+		w.dstBinding = MAX_TEXTURE_BINDINGS + MAX_UNIFORM_BUFFER_BINDINGS;
+		w.pBufferInfo = &storages[0];
+		w.dstSet = m_handle;
+	}
+
+	// 4th images
+	for(U i = 0; i < MAX_IMAGE_BINDINGS; ++i)
+	{
+		const ImageBinding& binding = init.m_images[i];
+		if(binding.m_texture)
+		{
+			VkDescriptorImageInfo& inf = images[imageCount++];
+			const TextureImpl& tex = binding.m_texture->getImplementation();
+
+			if(binding.m_level == 0)
+			{
+				inf.imageView = tex.m_viewHandle;
+			}
+			else
+			{
+				inf.imageView = tex.m_viewsEveryLevel[binding.m_level - 1];
+			}
+			inf.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
+
+			m_refs[refCount++] = binding.m_texture;
+		}
+	}
+
+	if(imageCount)
+	{
+		VkWriteDescriptorSet& w = write[writeCount++];
+		w.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+		w.descriptorCount = imageCount;
+		w.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
+		w.dstBinding = MAX_TEXTURE_BINDINGS + MAX_UNIFORM_BUFFER_BINDINGS
+			+ MAX_STORAGE_BUFFER_BINDINGS;
+		w.pImageInfo = &images[0];
+		w.dstSet = m_handle;
+	}
 
 	// Check if it was created. It's not created only if the rc group contains
 	// only vertex info.
@@ -278,11 +384,25 @@ void ResourceGroupImpl::setupDynamicOffsets(
 					dynInfo->m_uniformBuffers[i];
 
 				ANKI_ASSERT(token.m_range);
-				ANKI_ASSERT((token.m_usage & BufferUsageBit::UNIFORM_ANY_SHADER)
-					!= BufferUsageBit::NONE);
+				ANKI_ASSERT(
+					!!(token.m_usage & BufferUsageBit::UNIFORM_ANY_SHADER));
 				dynOffsets[i] = token.m_offset;
 			}
 		}
+
+		for(U i = 0; i < m_storageBindingCount; ++i)
+		{
+			if(m_dynamicBuffersMask.get(MAX_UNIFORM_BUFFER_BINDINGS + i))
+			{
+				// Uploaded
+				const TransientMemoryToken& token =
+					dynInfo->m_storageBuffers[i];
+
+				ANKI_ASSERT(token.m_range);
+				ANKI_ASSERT(!!(token.m_usage & BufferUsageBit::STORAGE_ANY));
+				dynOffsets[MAX_UNIFORM_BUFFER_BINDINGS + i] = token.m_offset;
+			}
+		}
 	}
 }
 

+ 5 - 2
src/gr/vulkan/ShaderImpl.cpp

@@ -153,9 +153,10 @@ static const char* SHADER_HEADER = R"(#version 450 core
 #define ANKI_VK 1
 #define %s
 #define gl_VertexID gl_VertexIndex
+#define ANKI_TEX_BINDING(set_, binding_) set = set_, binding = %u + binding_
 #define ANKI_UBO_BINDING(set_, binding_) set = set_, binding = %u + binding_
 #define ANKI_SS_BINDING(set_, binding_) set = set_, binding = %u + binding_
-#define ANKI_TEX_BINDING(set_, binding_) set = set_, binding = %u + binding_
+#define ANKI_IMAGE_BINDING(set_, binding_) set = set_, binding = %u + binding_
 
 #if defined(FRAGMENT_SHADER)
 #define ANKI_USING_FRAG_COORD(h_) vec4 anki_fragCoord = \
@@ -235,9 +236,11 @@ Error ShaderImpl::init(ShaderType shaderType, const CString& source)
 
 	fullSrc.sprintf(SHADER_HEADER,
 		shaderName[shaderType],
+		0,
 		MAX_TEXTURE_BINDINGS,
 		MAX_TEXTURE_BINDINGS + MAX_UNIFORM_BUFFER_BINDINGS,
-		0,
+		MAX_TEXTURE_BINDINGS + MAX_UNIFORM_BUFFER_BINDINGS
+			+ MAX_STORAGE_BUFFER_BINDINGS,
 		&source[0]);
 
 	std::vector<unsigned int> spirv;

+ 260 - 6
src/gr/vulkan/TextureImpl.cpp

@@ -43,6 +43,13 @@ TextureImpl::~TextureImpl()
 		vkDestroyImageView(getDevice(), m_viewHandle, nullptr);
 	}
 
+	for(VkImageView view : m_viewsEveryLevel)
+	{
+		vkDestroyImageView(getDevice(), view, nullptr);
+	}
+
+	m_viewsEveryLevel.destroy(getAllocator());
+
 	if(m_imageHandle)
 	{
 		vkDestroyImage(getDevice(), m_imageHandle, nullptr);
@@ -154,7 +161,9 @@ Error TextureImpl::init(const TextureInitInfo& init_, Texture* tex)
 
 	m_layerCount = init.m_layerCount;
 
-	if(formatIsDepthStencil(init.m_format))
+	m_format = init.m_format;
+	m_depthStencil = formatIsDepthStencil(m_format);
+	if(m_depthStencil)
 	{
 		m_aspect = VK_IMAGE_ASPECT_DEPTH_BIT;
 	}
@@ -164,7 +173,6 @@ Error TextureImpl::init(const TextureInitInfo& init_, Texture* tex)
 	}
 
 	m_usage = init.m_usage;
-	m_format = init.m_format;
 
 	CreateContext ctx;
 	ctx.m_init = init;
@@ -178,10 +186,7 @@ Error TextureImpl::init(const TextureInitInfo& init_, Texture* tex)
 		ANKI_ASSERT(!(init.m_initialUsage & TextureUsageBit::GENERATE_MIPMAPS)
 			&& "That doesn't make any sense");
 
-		VkImageLayout initialLayout = computeLayout(init.m_initialUsage,
-			formatIsDepthStencil(init.m_format),
-			0,
-			m_mipCount);
+		VkImageLayout initialLayout = computeLayout(init.m_initialUsage, 0);
 
 		CommandBufferInitInfo cmdbinit;
 		cmdbinit.m_flags =
@@ -348,7 +353,256 @@ Error TextureImpl::initView(CreateContext& ctx)
 
 	ANKI_VK_CHECK(vkCreateImageView(getDevice(), &ci, nullptr, &m_viewHandle));
 
+	// Create the rest of the views
+	if(!!(m_usage & TextureUsageBit::COMPUTE_SHADER_IMAGE_READ_WRITE))
+	{
+		ci.subresourceRange.levelCount = 1;
+
+		m_viewsEveryLevel.create(getAllocator(), m_mipCount - 1);
+
+		for(U i = 0; i < m_viewsEveryLevel.getSize(); ++i)
+		{
+			ci.subresourceRange.baseArrayLayer = i + 1;
+			ANKI_VK_CHECK(vkCreateImageView(
+				getDevice(), &ci, nullptr, &m_viewsEveryLevel[i]));
+		}
+	}
+
 	return ErrorCode::NONE;
 }
 
+//==============================================================================
+void TextureImpl::computeBarrierInfo(TextureUsageBit before,
+	TextureUsageBit after,
+	U level,
+	VkPipelineStageFlags& srcStages,
+	VkAccessFlags& srcAccesses,
+	VkPipelineStageFlags& dstStages,
+	VkAccessFlags& dstAccesses) const
+{
+	ANKI_ASSERT(level < m_mipCount);
+	ANKI_ASSERT(usageValid(before) && usageValid(after));
+	srcStages = 0;
+	srcAccesses = 0;
+	dstStages = 0;
+	dstAccesses = 0;
+	Bool lastLevel = level == m_mipCount - 1u;
+
+	//
+	// Before
+	//
+	if(!!(before & TextureUsageBit::FRAGMENT_SHADER_SAMPLED))
+	{
+		srcStages |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+		srcAccesses |= VK_ACCESS_SHADER_READ_BIT;
+	}
+
+	if(!!(before & TextureUsageBit::COMPUTE_SHADER_SAMPLED))
+	{
+		srcStages |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
+		srcAccesses |= VK_ACCESS_SHADER_READ_BIT;
+	}
+
+	if(!!(before & TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ))
+	{
+		if(m_depthStencil)
+		{
+			srcStages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
+				| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
+			srcAccesses |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
+		}
+		else
+		{
+			srcStages |= VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
+			srcAccesses |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
+		}
+	}
+
+	if(!!(before & TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE))
+	{
+		srcStages |= VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
+
+		if(m_depthStencil)
+		{
+			srcAccesses |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
+		}
+		else
+		{
+			srcAccesses |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+		}
+	}
+
+	if(!!(before & TextureUsageBit::GENERATE_MIPMAPS))
+	{
+		srcStages |= VK_PIPELINE_STAGE_TRANSFER_BIT;
+
+		if(!lastLevel)
+		{
+			srcAccesses |= VK_ACCESS_TRANSFER_READ_BIT;
+		}
+		else
+		{
+			srcAccesses |= VK_ACCESS_TRANSFER_WRITE_BIT;
+		}
+	}
+
+	if(!!(before & TextureUsageBit::UPLOAD))
+	{
+		srcStages |= VK_PIPELINE_STAGE_TRANSFER_BIT;
+		srcAccesses |= VK_ACCESS_TRANSFER_WRITE_BIT;
+	}
+
+	if(!!(before & TextureUsageBit::CLEAR))
+	{
+		srcStages |= VK_PIPELINE_STAGE_TRANSFER_BIT;
+		srcAccesses |= VK_ACCESS_TRANSFER_WRITE_BIT;
+	}
+
+	if(srcStages == 0)
+	{
+		srcStages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
+	}
+
+	//
+	// After
+	//
+	if(!!(after & TextureUsageBit::FRAGMENT_SHADER_SAMPLED))
+	{
+		dstStages |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+		dstAccesses |= VK_ACCESS_SHADER_READ_BIT;
+	}
+
+	if(!!(after & TextureUsageBit::COMPUTE_SHADER_SAMPLED))
+	{
+		dstStages |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
+		dstAccesses |= VK_ACCESS_SHADER_READ_BIT;
+	}
+
+	if(!!(after & TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ))
+	{
+		if(m_depthStencil)
+		{
+			dstStages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
+				| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
+			dstAccesses |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
+		}
+		else
+		{
+			dstStages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+			dstAccesses |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
+		}
+	}
+
+	if(!!(after & TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE))
+	{
+		if(m_depthStencil)
+		{
+			dstStages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
+				| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
+			dstAccesses |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
+		}
+		else
+		{
+			dstStages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+			dstAccesses |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+		}
+	}
+
+	if(!!(after & TextureUsageBit::GENERATE_MIPMAPS))
+	{
+		dstStages |= VK_PIPELINE_STAGE_TRANSFER_BIT;
+
+		if(level == 0)
+		{
+			dstAccesses |= VK_ACCESS_TRANSFER_READ_BIT;
+		}
+		else
+		{
+			ANKI_ASSERT(0 && "This will happen in generateMipmaps");
+		}
+	}
+
+	if(!!(after & TextureUsageBit::UPLOAD))
+	{
+		dstStages |= VK_PIPELINE_STAGE_TRANSFER_BIT;
+		dstAccesses |= VK_ACCESS_TRANSFER_WRITE_BIT;
+	}
+
+	if(!!(after & TextureUsageBit::CLEAR))
+	{
+		dstStages |= VK_PIPELINE_STAGE_TRANSFER_BIT;
+		dstAccesses |= VK_ACCESS_TRANSFER_WRITE_BIT;
+	}
+
+	ANKI_ASSERT(dstStages);
+}
+
+//==============================================================================
+VkImageLayout TextureImpl::computeLayout(TextureUsageBit usage, U level) const
+{
+	ANKI_ASSERT(level < m_mipCount);
+	ANKI_ASSERT(usageValid(usage));
+
+	VkImageLayout out = VK_IMAGE_LAYOUT_MAX_ENUM;
+	Bool lastLevel = level == m_mipCount - 1u;
+
+	if(usage == TextureUsageBit::NONE)
+	{
+		out = VK_IMAGE_LAYOUT_UNDEFINED;
+	}
+	else if(!!(usage & TextureUsageBit::ANY_SHADER_SAMPLED)
+		&& !(usage & ~TextureUsageBit::ANY_SHADER_SAMPLED))
+	{
+		out = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+	}
+	else if(!!(usage & TextureUsageBit::COMPUTE_SHADER_IMAGE_READ_WRITE)
+		&& !(usage & ~TextureUsageBit::COMPUTE_SHADER_IMAGE_READ_WRITE))
+	{
+		out = VK_IMAGE_LAYOUT_GENERAL;
+	}
+	else if(usage == TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE
+		|| usage == TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ_WRITE)
+	{
+		if(m_depthStencil)
+		{
+			out = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+		}
+		else
+		{
+			out = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+		}
+	}
+	else if(m_depthStencil
+		&& !!(usage & TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ)
+		&& !!(usage & TextureUsageBit::ANY_GRAPHICS_SHADER_SAMPLED)
+		&& !(usage
+				& ~(TextureUsageBit::ANY_GRAPHICS_SHADER_SAMPLED
+					  | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ)))
+	{
+		out = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
+	}
+	else if(usage == TextureUsageBit::GENERATE_MIPMAPS)
+	{
+		if(!lastLevel)
+		{
+			out = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
+		}
+		else
+		{
+			out = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
+		}
+	}
+	else if(usage == TextureUsageBit::CLEAR)
+	{
+		out = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
+	}
+	else if(!m_depthStencil && usage == TextureUsageBit::UPLOAD)
+	{
+		out = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
+	}
+
+	ANKI_ASSERT(out != VK_IMAGE_LAYOUT_MAX_ENUM);
+	return out;
+}
+
 } // end namespace anki

+ 1 - 1
src/gr/vulkan/TextureMisc.cpp

@@ -8,7 +8,7 @@
 namespace anki
 {
 
-static_assert(MAX_RESOURCE_GROUPS == 2, "Code bellow assumes that");
+static_assert(MAX_BOUND_RESOURCE_GROUPS == 2, "Code bellow assumes that");
 
 static const CString UPLOAD_R8G8B8_COMPUTE_SHADER = R"(
 const uint WORKGROUP_SIZE_X = 4u;