Kaynağa Gözat

[REFACTORING] Move the image load/store to use texture views

Panagiotis Christopoulos Charitos 8 yıl önce
ebeveyn
işleme
810d3691f5

+ 1 - 0
src/anki/Gr.h

@@ -7,6 +7,7 @@
 
 #include <anki/gr/Buffer.h>
 #include <anki/gr/Texture.h>
+#include <anki/gr/TextureView.h>
 #include <anki/gr/Sampler.h>
 #include <anki/gr/Shader.h>
 #include <anki/gr/ShaderProgram.h>

+ 1 - 1
src/anki/gr/CommandBuffer.h

@@ -256,7 +256,7 @@ public:
 	void bindStorageBuffer(U32 set, U32 binding, BufferPtr buff, PtrSize offset, PtrSize range);
 
 	/// Bind load/store image.
-	void bindImage(U32 set, U32 binding, TexturePtr img, U32 level);
+	void bindImage(U32 set, U32 binding, TextureViewPtr img);
 
 	/// Bind texture buffer.
 	void bindTextureBuffer(U32 set, U32 binding, BufferPtr buff, PtrSize offset, PtrSize range, PixelFormat fmt);

+ 39 - 6
src/anki/gr/Common.h

@@ -142,6 +142,11 @@ public:
 class TextureSurfaceInfo
 {
 public:
+	U32 m_level = 0;
+	U32 m_depth = 0;
+	U32 m_face = 0;
+	U32 m_layer = 0;
+
 	TextureSurfaceInfo() = default;
 
 	TextureSurfaceInfo(const TextureSurfaceInfo&) = default;
@@ -168,17 +173,14 @@ public:
 	{
 		return anki::computeHash(this, sizeof(*this), 0x1234567);
 	}
-
-	U32 m_level = 0;
-	U32 m_depth = 0;
-	U32 m_face = 0;
-	U32 m_layer = 0;
 };
 
 /// A way to identify a volume in 3D textures.
 class TextureVolumeInfo
 {
 public:
+	U32 m_level = 0;
+
 	TextureVolumeInfo() = default;
 
 	TextureVolumeInfo(const TextureVolumeInfo&) = default;
@@ -187,8 +189,39 @@ public:
 		: m_level(level)
 	{
 	}
+};
 
-	U32 m_level = 0;
+/// Defines a subset of a texture.
+class TextureSubresourceInfo
+{
+public:
+	U32 m_baseMipmap = 0;
+	U32 m_mipmapCount = 1;
+
+	U32 m_baseLayer = 0;
+	U32 m_layerCount = 1;
+
+	U8 m_baseFace = 0;
+	U8 m_faceCount = 1;
+
+	DepthStencilAspectBit m_depthStencilAspect = DepthStencilAspectBit::NONE;
+
+	U8 _m_padding[1] = {0};
+
+	TextureSubresourceInfo() = default;
+
+	TextureSubresourceInfo(const TextureSubresourceInfo&) = default;
+
+	TextureSubresourceInfo(const TextureSurfaceInfo& surf, DepthStencilAspectBit aspect = DepthStencilAspectBit::NONE)
+		: m_baseMipmap(surf.m_level)
+		, m_mipmapCount(1)
+		, m_baseLayer(surf.m_layer)
+		, m_layerCount(1)
+		, m_baseFace(surf.m_face)
+		, m_faceCount(1)
+		, m_depthStencilAspect(aspect)
+	{
+	}
 };
 
 enum class DescriptorType : U8

+ 23 - 1
src/anki/gr/Enums.h

@@ -119,6 +119,8 @@ enum class VertexStepRate : U8
 	COUNT
 };
 
+/// Pixel and vertex component format.
+/// @note WARNING Be careful when changing this. You need updates to multiple places.
 enum class ComponentFormat : U8
 {
 	NONE,
@@ -139,7 +141,6 @@ enum class ComponentFormat : U8
 	// Special
 	R10G10B10A2,
 	R11G11B10,
-	DEFAULT_FRAMEBUFFER, ///< Implicit format.
 
 	// Compressed
 	R8G8B8_BC1, ///< DXT1
@@ -162,6 +163,21 @@ enum class ComponentFormat : U8
 	LAST_DEPTH_STENCIL = S8
 };
 
+inline Bool componentFormatIsDepthStencil(const ComponentFormat fmt)
+{
+	return fmt >= ComponentFormat::FIRST_DEPTH_STENCIL && fmt <= ComponentFormat::LAST_DEPTH_STENCIL;
+}
+
+inline Bool componentFormatIsDepth(const ComponentFormat fmt)
+{
+	return fmt >= ComponentFormat::D16 && fmt <= ComponentFormat::D32S8;
+}
+
+inline Bool componentFormatIsStencil(const ComponentFormat fmt)
+{
+	return fmt == ComponentFormat::D24S8 || fmt == ComponentFormat::D32S8 || fmt == ComponentFormat::S8;
+}
+
 enum class TransformFormat : U8
 {
 	NONE,
@@ -172,6 +188,7 @@ enum class TransformFormat : U8
 	FLOAT
 };
 
+/// Texture type.
 enum class TextureType : U8
 {
 	_1D,
@@ -183,6 +200,11 @@ enum class TextureType : U8
 	COUNT
 };
 
+inline Bool textureTypeIsCube(const TextureType t)
+{
+	return t == TextureType::CUBE || t == TextureType::CUBE_ARRAY;
+}
+
 /// Texture usage hints. They are very important.
 enum class TextureUsageBit : U16
 {

+ 49 - 0
src/anki/gr/Texture.h

@@ -108,6 +108,55 @@ public:
 		return m_format;
 	}
 
+	Bool isSubresourceValid(const TextureSubresourceInfo& subresource) const
+	{
+#define ANKI_TEX_SUBRESOURCE_ASSERT(x_) \
+	if(!(x_))                           \
+	{                                   \
+		return false;                   \
+	}
+		const TextureType type = m_texType;
+		const Bool cube = textureTypeIsCube(type);
+
+		// Mips
+		ANKI_TEX_SUBRESOURCE_ASSERT(subresource.m_mipmapCount > 0);
+		ANKI_TEX_SUBRESOURCE_ASSERT(subresource.m_baseMipmap + subresource.m_mipmapCount <= m_mipCount);
+
+		// Layers
+		ANKI_TEX_SUBRESOURCE_ASSERT(subresource.m_layerCount > 0);
+		ANKI_TEX_SUBRESOURCE_ASSERT(subresource.m_baseLayer + subresource.m_layerCount <= m_layerCount);
+
+		// Faces
+		const U8 faceCount = (cube) ? 6 : 1;
+		ANKI_TEX_SUBRESOURCE_ASSERT(subresource.m_faceCount == 1 || subresource.m_faceCount == 6);
+		ANKI_TEX_SUBRESOURCE_ASSERT(subresource.m_baseFace + subresource.m_faceCount <= faceCount);
+
+		// Aspect
+		const PixelFormat fmt = m_format;
+		DepthStencilAspectBit aspect =
+			(componentFormatIsDepth(fmt.m_components)) ? DepthStencilAspectBit::DEPTH : DepthStencilAspectBit::NONE;
+		aspect |=
+			(componentFormatIsStencil(fmt.m_components)) ? DepthStencilAspectBit::STENCIL : DepthStencilAspectBit::NONE;
+		if(!!aspect)
+		{
+			ANKI_TEX_SUBRESOURCE_ASSERT(!!(aspect & subresource.m_depthStencilAspect));
+		}
+		else
+		{
+			ANKI_TEX_SUBRESOURCE_ASSERT(aspect == DepthStencilAspectBit::NONE);
+		}
+
+		// Misc
+		if(type == TextureType::CUBE_ARRAY && subresource.m_layerCount > 1)
+		{
+			// Because of the way surfaces are arranged in cube arrays
+			ANKI_TEX_SUBRESOURCE_ASSERT(subresource.m_faceCount == 6);
+		}
+
+#undef ANKI_TEX_SUBRESOURCE_ASSERT
+		return true;
+	}
+
 protected:
 	U32 m_width = 0;
 	U32 m_height = 0;

+ 67 - 41
src/anki/gr/TextureView.h

@@ -15,22 +15,11 @@ namespace anki
 /// @{
 
 /// TextureView init info.
-class TextureViewInitInfo : public GrBaseInitInfo
+class TextureViewInitInfo : public GrBaseInitInfo, public TextureSubresourceInfo
 {
 public:
 	TexturePtr m_texture;
 
-	U32 m_baseMipmap = MAX_U32;
-	U32 m_mipmapCount = MAX_U32;
-
-	U32 m_baseLayer = MAX_U32;
-	U32 m_layerCount = MAX_U32;
-
-	U8 m_baseFace = MAX_U8;
-	U8 m_faceCount = MAX_U8;
-
-	DepthStencilAspectBit m_depthStencilAspect = DepthStencilAspectBit::NONE;
-
 	TextureViewInitInfo(TexturePtr tex, CString name = {})
 		: GrBaseInitInfo(name)
 		, m_texture(tex)
@@ -42,7 +31,12 @@ public:
 		m_baseFace = 0;
 		m_faceCount =
 			(tex->getTextureType() == TextureType::CUBE_ARRAY || tex->getTextureType() == TextureType::CUBE) ? 6 : 1;
-		// TODO: m_depthStencilAspect = ?
+
+		const PixelFormat fmt = tex->getPixelFormat();
+		m_depthStencilAspect =
+			(componentFormatIsDepth(fmt.m_components)) ? DepthStencilAspectBit::DEPTH : DepthStencilAspectBit::NONE;
+		m_depthStencilAspect |=
+			(componentFormatIsStencil(fmt.m_components)) ? DepthStencilAspectBit::STENCIL : DepthStencilAspectBit::NONE;
 	}
 
 	TextureViewInitInfo(CString name = {})
@@ -50,38 +44,34 @@ public:
 	{
 	}
 
-	Bool isValid() const
+	TextureViewInitInfo(TexturePtr tex,
+		const TextureSurfaceInfo& surf,
+		DepthStencilAspectBit aspect = DepthStencilAspectBit::NONE,
+		CString name = {})
+		: GrBaseInitInfo(name)
+		, m_texture(tex)
 	{
-#define ANKI_TEX_VIEW_ASSERT(x_) \
-	if(!(x_))                    \
-	{                            \
-		return false;            \
+		m_baseMipmap = surf.m_level;
+		m_mipmapCount = 1;
+		m_baseLayer = surf.m_layer;
+		m_layerCount = 1;
+		m_baseFace = surf.m_face;
+		m_faceCount = 1;
+		m_depthStencilAspect = aspect;
+		ANKI_ASSERT(isValid());
 	}
-		ANKI_TEX_VIEW_ASSERT(m_texture.isCreated());
-		const TextureType type = m_texture->getTextureType();
-		const Bool cube = type == TextureType::CUBE_ARRAY || type == TextureType::CUBE;
 
-		// Mips
-		ANKI_TEX_VIEW_ASSERT(m_mipmapCount > 0);
-		ANKI_TEX_VIEW_ASSERT(m_baseMipmap + m_mipmapCount <= m_texture->getMipmapCount());
-
-		// Layers
-		ANKI_TEX_VIEW_ASSERT(m_layerCount > 0);
-		ANKI_TEX_VIEW_ASSERT(m_baseLayer + m_layerCount <= m_texture->getLayerCount());
-
-		// Faces
-		const U8 faceCount = (cube) ? 6 : 1;
-		ANKI_TEX_VIEW_ASSERT(m_faceCount > 0);
-		ANKI_TEX_VIEW_ASSERT(m_baseFace + m_faceCount <= faceCount);
-
-		// Misc
-		if(type == TextureType::CUBE_ARRAY && m_layerCount > 1)
-		{
-			ANKI_TEX_VIEW_ASSERT(m_faceCount == 6); // Because of the way surfaces are arranged in cube arrays
-		}
+	TextureViewInitInfo(TexturePtr tex, const TextureSubresourceInfo& subresource, CString name = {})
+		: GrBaseInitInfo(name)
+		, m_texture(tex)
+	{
+		static_cast<TextureSubresourceInfo&>(*this) = subresource;
+		ANKI_ASSERT(isValid());
+	}
 
-#undef ANKI_TEX_VIEW_VALID
-		return true;
+	Bool isValid() const
+	{
+		return m_texture.isCreated() && m_texture->isSubresourceValid(*this);
 	}
 };
 
@@ -119,6 +109,42 @@ public:
 		return m_mipCount == 1;
 	}
 
+	U32 getBaseMipmap() const
+	{
+		ANKI_ASSERT(initialized());
+		return m_baseMip;
+	}
+
+	U32 getMipmapCount() const
+	{
+		ANKI_ASSERT(initialized());
+		return m_mipCount;
+	}
+
+	U32 getBaseLayer() const
+	{
+		ANKI_ASSERT(initialized());
+		return m_baseLayer;
+	}
+
+	U32 getLayerCount() const
+	{
+		ANKI_ASSERT(initialized());
+		return m_layerCount;
+	}
+
+	U32 getBaseFace() const
+	{
+		ANKI_ASSERT(initialized());
+		return m_baseFace;
+	}
+
+	U32 getFaceCount() const
+	{
+		ANKI_ASSERT(initialized());
+		return m_faceCount;
+	}
+
 protected:
 	TextureType m_texType = TextureType::COUNT;
 	DepthStencilAspectBit m_aspect = DepthStencilAspectBit::NONE;

+ 2 - 2
src/anki/gr/vulkan/CommandBuffer.cpp

@@ -192,10 +192,10 @@ void CommandBuffer::bindStorageBuffer(U32 set, U32 binding, BufferPtr buff, PtrS
 	self.bindStorageBuffer(set, binding, buff, offset, range);
 }
 
-void CommandBuffer::bindImage(U32 set, U32 binding, TexturePtr img, U32 level)
+void CommandBuffer::bindImage(U32 set, U32 binding, TextureViewPtr img)
 {
 	ANKI_VK_SELF(CommandBufferImpl);
-	self.bindImage(set, binding, img, level);
+	self.bindImage(set, binding, img);
 }
 
 void CommandBuffer::bindTextureBuffer(

+ 9 - 9
src/anki/gr/vulkan/CommandBufferImpl.cpp

@@ -308,7 +308,7 @@ void CommandBufferImpl::generateMipmaps2d(TexturePtr tex, U face, U layer)
 		if(i > 0)
 		{
 			VkImageSubresourceRange range;
-			impl.computeSubResourceRange(TextureSurfaceInfo(i, 0, face, layer), impl.m_akAspect, range);
+			impl.computeSubResourceRange(TextureSurfaceInfo(i, 0, face, layer), impl.m_aspect, range);
 
 			setImageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
 				VK_ACCESS_TRANSFER_WRITE_BIT,
@@ -323,7 +323,7 @@ void CommandBufferImpl::generateMipmaps2d(TexturePtr tex, U face, U layer)
 		// Transition destination
 		{
 			VkImageSubresourceRange range;
-			impl.computeSubResourceRange(TextureSurfaceInfo(i + 1, 0, face, layer), impl.m_akAspect, range);
+			impl.computeSubResourceRange(TextureSurfaceInfo(i + 1, 0, face, layer), impl.m_aspect, range);
 
 			setImageBarrier(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
 				0,
@@ -362,14 +362,14 @@ void CommandBufferImpl::generateMipmaps2d(TexturePtr tex, U face, U layer)
 		}
 
 		VkImageBlit blit;
-		blit.srcSubresource.aspectMask = impl.m_aspect;
+		blit.srcSubresource.aspectMask = convertImageAspect(impl.m_aspect);
 		blit.srcSubresource.baseArrayLayer = vkLayer;
 		blit.srcSubresource.layerCount = 1;
 		blit.srcSubresource.mipLevel = i;
 		blit.srcOffsets[0] = {0, 0, 0};
 		blit.srcOffsets[1] = {srcWidth, srcHeight, 1};
 
-		blit.dstSubresource.aspectMask = impl.m_aspect;
+		blit.dstSubresource.aspectMask = convertImageAspect(impl.m_aspect);
 		blit.dstSubresource.baseArrayLayer = vkLayer;
 		blit.dstSubresource.layerCount = 1;
 		blit.dstSubresource.mipLevel = i + 1;
@@ -383,7 +383,7 @@ void CommandBufferImpl::generateMipmaps2d(TexturePtr tex, U face, U layer)
 					 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
 					 1,
 					 &blit,
-					 (impl.m_depthStencil) ? VK_FILTER_NEAREST : VK_FILTER_LINEAR),
+					 (!!impl.m_aspect) ? VK_FILTER_NEAREST : VK_FILTER_LINEAR),
 			ANY_OTHER_COMMAND);
 	}
 
@@ -668,7 +668,7 @@ void CommandBufferImpl::copyBufferToTextureSurface(
 
 		// Copy
 		VkBufferImageCopy region;
-		region.imageSubresource.aspectMask = impl.m_aspect;
+		region.imageSubresource.aspectMask = convertImageAspect(impl.m_aspect);
 		region.imageSubresource.baseArrayLayer = impl.computeVkArrayLayer(surf);
 		region.imageSubresource.layerCount = 1;
 		region.imageSubresource.mipLevel = surf.m_level;
@@ -732,7 +732,7 @@ void CommandBufferImpl::copyBufferToTextureSurface(
 
 		// Do the copy to the image
 		VkBufferImageCopy region;
-		region.imageSubresource.aspectMask = impl.m_aspect;
+		region.imageSubresource.aspectMask = convertImageAspect(impl.m_aspect);
 		region.imageSubresource.baseArrayLayer = impl.computeVkArrayLayer(surf);
 		region.imageSubresource.layerCount = 1;
 		region.imageSubresource.mipLevel = surf.m_level;
@@ -775,7 +775,7 @@ void CommandBufferImpl::copyBufferToTextureVolume(
 
 		// Copy
 		VkBufferImageCopy region;
-		region.imageSubresource.aspectMask = impl.m_aspect;
+		region.imageSubresource.aspectMask = convertImageAspect(impl.m_aspect);
 		region.imageSubresource.baseArrayLayer = impl.computeVkArrayLayer(vol);
 		region.imageSubresource.layerCount = 1;
 		region.imageSubresource.mipLevel = vol.m_level;
@@ -844,7 +844,7 @@ void CommandBufferImpl::copyBufferToTextureVolume(
 
 		// Do the copy to the image
 		VkBufferImageCopy region;
-		region.imageSubresource.aspectMask = impl.m_aspect;
+		region.imageSubresource.aspectMask = convertImageAspect(impl.m_aspect);
 		region.imageSubresource.baseArrayLayer = impl.computeVkArrayLayer(vol);
 		region.imageSubresource.layerCount = 1;
 		region.imageSubresource.mipLevel = vol.m_level;

+ 3 - 3
src/anki/gr/vulkan/CommandBufferImpl.h

@@ -226,19 +226,19 @@ public:
 		const U realBinding = binding;
 		const Texture& tex = *tex_;
 		const TextureImpl& teximpl = static_cast<const TextureImpl&>(tex);
-		ANKI_ASSERT((!teximpl.m_depthStencil || !!aspect) && "Need to set aspect for DS textures");
+		ANKI_ASSERT((!teximpl.m_aspect || !!aspect) && "Need to set aspect for DS textures");
 		const VkImageLayout lay = teximpl.computeLayout(usage, 0);
 		m_dsetState[set].bindTextureAndSampler(realBinding, &tex, sampler.get(), aspect, lay);
 		m_microCmdb->pushObjectRef(tex_);
 		m_microCmdb->pushObjectRef(sampler);
 	}
 
-	void bindImage(U32 set, U32 binding, TexturePtr& img, U32 level)
+	void bindImage(U32 set, U32 binding, TextureViewPtr& img)
 	{
 		commandCommon();
 		const U realBinding =
 			binding + MAX_TEXTURE_BINDINGS + MAX_UNIFORM_BUFFER_BINDINGS + MAX_STORAGE_BUFFER_BINDINGS;
-		m_dsetState[set].bindImage(realBinding, img.get(), level);
+		m_dsetState[set].bindImage(realBinding, img.get());
 		m_microCmdb->pushObjectRef(img);
 	}
 

+ 3 - 3
src/anki/gr/vulkan/CommandBufferImpl.inl.h

@@ -161,7 +161,7 @@ inline void CommandBufferImpl::setTextureSurfaceBarrier(
 	impl.checkSurfaceOrVolume(surf);
 
 	VkImageSubresourceRange range;
-	impl.computeSubResourceRange(surf, impl.m_akAspect, range);
+	impl.computeSubResourceRange(surf, impl.m_aspect, range);
 	setTextureBarrierRange(tex, prevUsage, nextUsage, range);
 }
 
@@ -178,7 +178,7 @@ inline void CommandBufferImpl::setTextureVolumeBarrier(
 	impl.checkSurfaceOrVolume(vol);
 
 	VkImageSubresourceRange range;
-	impl.computeSubResourceRange(vol, impl.m_akAspect, range);
+	impl.computeSubResourceRange(vol, impl.m_aspect, range);
 	setTextureBarrierRange(tex, prevUsage, nextUsage, range);
 }
 
@@ -385,7 +385,7 @@ inline void CommandBufferImpl::clearTextureInternal(
 	memcpy(&vclear, &clearValue, sizeof(clearValue));
 
 	const TextureImpl& impl = static_cast<const TextureImpl&>(*tex);
-	if(impl.m_aspect == VK_IMAGE_ASPECT_COLOR_BIT)
+	if(!impl.m_aspect)
 	{
 		ANKI_CMD(vkCmdClearColorImage(
 					 m_handle, impl.m_imageHandle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &vclear, 1, &range),

+ 1 - 17
src/anki/gr/vulkan/Common.cpp

@@ -279,22 +279,6 @@ VkFormat convertFormat(PixelFormat ak)
 	return out;
 }
 
-VkImageAspectFlags convertImageAspect(PixelFormat ak)
-{
-	VkImageAspectFlags out = 0;
-	for(U i = 0; i < CONVERT_FORMAT_TABLE_SIZE; ++i)
-	{
-		const ConvertFormat& entry = CONVERT_FORMAT_TABLE[i];
-		if(ak == entry.m_ak)
-		{
-			out = static_cast<VkImageAspectFlags>(entry.m_aspect);
-		}
-	}
-
-	ANKI_ASSERT(out);
-	return out;
-}
-
 VkPrimitiveTopology convertTopology(PrimitiveTopology ak)
 {
 	VkPrimitiveTopology out = VK_PRIMITIVE_TOPOLOGY_MAX_ENUM;
@@ -625,7 +609,7 @@ VkImageUsageFlags convertTextureUsage(TextureUsageBit ak, const PixelFormat& for
 
 	if(!!(ak & TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ_WRITE))
 	{
-		if(formatIsDepthStencil(format))
+		if(componentFormatIsDepthStencil(format.m_components))
 		{
 			out |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
 		}

+ 34 - 4
src/anki/gr/vulkan/Common.h

@@ -87,12 +87,42 @@ ANKI_USE_RESULT VkCompareOp convertCompareOp(CompareOperation ak);
 ANKI_USE_RESULT VkFormat convertFormat(PixelFormat ak);
 
 /// Get format aspect mask.
-ANKI_USE_RESULT VkImageAspectFlags convertImageAspect(PixelFormat ak);
+ANKI_USE_RESULT inline DepthStencilAspectBit getImageAspectFromFormat(const PixelFormat& ak)
+{
+	DepthStencilAspectBit out = DepthStencilAspectBit::NONE;
+	if(componentFormatIsStencil(ak.m_components))
+	{
+		out = DepthStencilAspectBit::STENCIL;
+	}
+
+	if(componentFormatIsDepth(ak.m_components))
+	{
+		out |= DepthStencilAspectBit::DEPTH;
+	}
 
-ANKI_USE_RESULT inline Bool formatIsDepthStencil(PixelFormat fmt)
+	return out;
+}
+
+/// Convert image aspect.
+ANKI_USE_RESULT inline VkImageAspectFlags convertImageAspect(const DepthStencilAspectBit ak)
 {
-	VkImageAspectFlags aspect = convertImageAspect(fmt);
-	return !!(aspect & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT));
+	VkImageAspectFlags out = 0;
+	if(!!(ak & DepthStencilAspectBit::DEPTH))
+	{
+		out |= VK_IMAGE_ASPECT_DEPTH_BIT;
+	}
+
+	if(!!(ak & DepthStencilAspectBit::STENCIL))
+	{
+		out |= VK_IMAGE_ASPECT_STENCIL_BIT;
+	}
+
+	if(!out)
+	{
+		out = VK_IMAGE_ASPECT_COLOR_BIT;
+	}
+
+	return out;
 }
 
 /// Convert topology.

+ 2 - 3
src/anki/gr/vulkan/DescriptorSet.cpp

@@ -305,8 +305,7 @@ void DSThreadAllocator::writeSet(const Array<AnyBinding, MAX_BINDINGS_PER_DESCRI
 				break;
 			case DescriptorType::IMAGE:
 				tex[texCount].sampler = VK_NULL_HANDLE;
-				tex[texCount].imageView =
-					b.m_image.m_tex->getOrCreateSingleLevelView(b.m_image.m_level, b.m_tex.m_aspect);
+				tex[texCount].imageView = b.m_image.m_texView->m_handle;
 				tex[texCount].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
 
 				w.pImageInfo = &tex[texCount];
@@ -518,7 +517,7 @@ void DescriptorSetState::flush(Bool& stateDirty,
 				dynamicOffsetsDirty = dynamicOffsetsDirty || m_dynamicOffsetDirty.get(i);
 				break;
 			case DescriptorType::IMAGE:
-				toHash[toHashCount++] = m_bindings[i].m_image.m_level;
+				// Nothing
 				break;
 			default:
 				ANKI_ASSERT(0);

+ 10 - 10
src/anki/gr/vulkan/DescriptorSet.h

@@ -6,11 +6,9 @@
 #pragma once
 
 #include <anki/gr/vulkan/Common.h>
-#include <anki/gr/Buffer.h>
 #include <anki/gr/vulkan/BufferImpl.h>
-#include <anki/gr/Texture.h>
 #include <anki/gr/vulkan/TextureImpl.h>
-#include <anki/gr/Sampler.h>
+#include <anki/gr/vulkan/TextureViewImpl.h>
 #include <anki/gr/vulkan/SamplerImpl.h>
 #include <anki/util/BitSet.h>
 
@@ -83,8 +81,7 @@ public:
 class ImageBinding
 {
 public:
-	const TextureImpl* m_tex = nullptr;
-	U16 m_level = 0;
+	const TextureViewImpl* m_texView = nullptr;
 };
 
 class AnyBinding
@@ -157,15 +154,18 @@ public:
 		m_dynamicOffsetDirty.set(binding);
 	}
 
-	void bindImage(U binding, const Texture* tex, U32 level)
+	void bindImage(U binding, const TextureView* texView)
 	{
+		ANKI_ASSERT(texView);
+		const TextureViewImpl* impl = static_cast<const TextureViewImpl*>(texView);
+		ANKI_ASSERT(impl->goodForImageLoadStore());
+
 		AnyBinding& b = m_bindings[binding];
 		b = {};
 		b.m_type = DescriptorType::IMAGE;
-		b.m_uuids[0] = b.m_uuids[1] = tex->getUuid();
-
-		b.m_image.m_tex = static_cast<const TextureImpl*>(tex);
-		b.m_image.m_level = level;
+		ANKI_ASSERT(impl->m_hash);
+		b.m_uuids[0] = b.m_uuids[1] = impl->m_hash;
+		b.m_image.m_texView = impl;
 
 		m_anyBindingDirty = true;
 	}

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

@@ -53,11 +53,11 @@ Error FramebufferImpl::init(const FramebufferInitInfo& init)
 		{
 			m_aspect = DepthStencilAspectBit::STENCIL;
 		}
-		else if(tex.m_akAspect == DepthStencilAspectBit::DEPTH)
+		else if(tex.m_aspect == DepthStencilAspectBit::DEPTH)
 		{
 			m_aspect = DepthStencilAspectBit::DEPTH;
 		}
-		else if(tex.m_akAspect == DepthStencilAspectBit::STENCIL)
+		else if(tex.m_aspect == DepthStencilAspectBit::STENCIL)
 		{
 			m_aspect = DepthStencilAspectBit::STENCIL;
 		}

+ 18 - 30
src/anki/gr/vulkan/TextureImpl.cpp

@@ -75,19 +75,9 @@ Error TextureImpl::init(const TextureInitInfo& init_)
 
 	m_format = init.m_format;
 	m_vkFormat = convertFormat(m_format);
-	m_depthStencil = formatIsDepthStencil(m_format);
-	m_aspect = convertImageAspect(m_format);
+	m_aspect = getImageAspectFromFormat(m_format);
 	m_usage = init.m_usage;
 
-	if(m_aspect & VK_IMAGE_ASPECT_DEPTH_BIT)
-	{
-		m_akAspect |= DepthStencilAspectBit::DEPTH;
-	}
-	if(m_aspect & VK_IMAGE_ASPECT_STENCIL_BIT)
-	{
-		m_akAspect |= DepthStencilAspectBit::STENCIL;
-	}
-
 	ANKI_CHECK(initImage(init));
 
 	// Init the template
@@ -100,7 +90,7 @@ Error TextureImpl::init(const TextureInitInfo& init_)
 	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.aspectMask = convertImageAspect(m_aspect);
 	m_viewCreateInfoTemplate.subresourceRange.baseArrayLayer = 0;
 	m_viewCreateInfoTemplate.subresourceRange.baseMipLevel = 0;
 	m_viewCreateInfoTemplate.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
@@ -117,7 +107,7 @@ Error TextureImpl::init(const TextureInitInfo& init_)
 		CommandBufferPtr cmdb = getManager().newCommandBuffer(cmdbinit);
 
 		VkImageSubresourceRange range;
-		range.aspectMask = m_aspect;
+		range.aspectMask = convertImageAspect(m_aspect);
 		range.baseArrayLayer = 0;
 		range.baseMipLevel = 0;
 		range.layerCount = m_layerCount;
@@ -145,7 +135,7 @@ VkFormatFeatureFlags TextureImpl::calcFeatures(const TextureInitInfo& init)
 
 	if(!!(init.m_usage & TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ_WRITE))
 	{
-		if(formatIsDepthStencil(init.m_format))
+		if(componentFormatIsDepthStencil(init.m_format.m_components))
 		{
 			flags |= VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
 		}
@@ -225,8 +215,6 @@ Error TextureImpl::initImage(const TextureInitInfo& init_)
 			m_format = init.m_format;
 			m_vkFormat = convertFormat(m_format);
 			m_workarounds = TextureImplWorkaround::S8_TO_D24S8;
-			m_aspect = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
-			m_akAspect = DepthStencilAspectBit::DEPTH | DepthStencilAspectBit::STENCIL;
 		}
 		else if(init.m_format.m_components == ComponentFormat::D24S8)
 		{
@@ -236,8 +224,6 @@ Error TextureImpl::initImage(const TextureInitInfo& init_)
 			m_format = init.m_format;
 			m_vkFormat = convertFormat(m_format);
 			m_workarounds = TextureImplWorkaround::D24S8_TO_D32S8;
-			m_aspect = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
-			m_akAspect = DepthStencilAspectBit::DEPTH | DepthStencilAspectBit::STENCIL;
 		}
 		else
 		{
@@ -384,7 +370,8 @@ void TextureImpl::computeBarrierInfo(TextureUsageBit before,
 	srcAccesses = 0;
 	dstStages = 0;
 	dstAccesses = 0;
-	Bool lastLevel = level == m_mipCount - 1u;
+	const Bool lastLevel = level == m_mipCount - 1u;
+	const Bool depthStencil = !!m_aspect;
 
 	//
 	// Before
@@ -433,7 +420,7 @@ void TextureImpl::computeBarrierInfo(TextureUsageBit before,
 
 	if(!!(before & TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ))
 	{
-		if(m_depthStencil)
+		if(depthStencil)
 		{
 			srcStages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
 			srcAccesses |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
@@ -447,7 +434,7 @@ void TextureImpl::computeBarrierInfo(TextureUsageBit before,
 
 	if(!!(before & TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE))
 	{
-		if(m_depthStencil)
+		if(depthStencil)
 		{
 			srcStages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
 			srcAccesses |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
@@ -537,7 +524,7 @@ void TextureImpl::computeBarrierInfo(TextureUsageBit before,
 
 	if(!!(after & TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ))
 	{
-		if(m_depthStencil)
+		if(depthStencil)
 		{
 			dstStages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
 			dstAccesses |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
@@ -551,7 +538,7 @@ void TextureImpl::computeBarrierInfo(TextureUsageBit before,
 
 	if(!!(after & TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE))
 	{
-		if(m_depthStencil)
+		if(depthStencil)
 		{
 			dstStages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
 			dstAccesses |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
@@ -598,7 +585,8 @@ VkImageLayout TextureImpl::computeLayout(TextureUsageBit usage, U level) const
 	ANKI_ASSERT(usageValid(usage));
 
 	VkImageLayout out = VK_IMAGE_LAYOUT_MAX_ENUM;
-	Bool lastLevel = level == m_mipCount - 1u;
+	const Bool lastLevel = level == m_mipCount - 1u;
+	const Bool depthStencil = !!m_aspect;
 
 	if(usage == TextureUsageBit::NONE)
 	{
@@ -617,7 +605,7 @@ VkImageLayout TextureImpl::computeLayout(TextureUsageBit usage, U level) const
 	else if(!(usage & ~TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ_WRITE))
 	{
 		// Only FB access
-		if(m_depthStencil)
+		if(depthStencil)
 		{
 			out = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
 		}
@@ -626,13 +614,13 @@ VkImageLayout TextureImpl::computeLayout(TextureUsageBit usage, U level) const
 			out = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
 		}
 	}
-	else if(m_depthStencil
+	else if(depthStencil
 		&& !(usage & ~(TextureUsageBit::SAMPLED_ALL_GRAPHICS | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ)))
 	{
 		// FB read & shader read
 		out = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
 	}
-	else if(m_depthStencil
+	else if(depthStencil
 		&& !(usage & ~(TextureUsageBit::SAMPLED_ALL_GRAPHICS | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ_WRITE)))
 	{
 		// Wild guess: One aspect is shader read and the other is read write
@@ -653,7 +641,7 @@ VkImageLayout TextureImpl::computeLayout(TextureUsageBit usage, U level) const
 	{
 		out = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
 	}
-	else if(!m_depthStencil && usage == TextureUsageBit::TRANSFER_DESTINATION)
+	else if(!depthStencil && usage == TextureUsageBit::TRANSFER_DESTINATION)
 	{
 		out = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
 	}
@@ -669,7 +657,7 @@ VkImageView TextureImpl::getOrCreateSingleLevelView(U32 mip, DepthStencilAspectB
 	VkImageViewCreateInfo ci = m_viewCreateInfoTemplate;
 	ci.subresourceRange.baseMipLevel = mip;
 	ci.subresourceRange.levelCount = 1;
-	ci.subresourceRange.aspectMask = convertAspect(aspect);
+	ci.subresourceRange.aspectMask = convertImageAspect(aspect);
 
 	return getOrCreateView(ci);
 }
@@ -689,7 +677,7 @@ VkImageView TextureImpl::getOrCreateSingleSurfaceView(
 VkImageView TextureImpl::getOrCreateResourceGroupView(DepthStencilAspectBit aspect) const
 {
 	VkImageViewCreateInfo ci = m_viewCreateInfoTemplate;
-	ci.subresourceRange.aspectMask = convertAspect(aspect);
+	ci.subresourceRange.aspectMask = convertImageAspect(aspect);
 
 	return getOrCreateView(ci);
 }

+ 2 - 5
src/anki/gr/vulkan/TextureImpl.h

@@ -39,11 +39,10 @@ public:
 	GpuMemoryHandle m_memHandle;
 
 	U32 m_surfaceOrVolumeCount = 0;
-	VkImageAspectFlags m_aspect = 0;
-	DepthStencilAspectBit m_akAspect = DepthStencilAspectBit::NONE;
+	DepthStencilAspectBit m_aspect = DepthStencilAspectBit::NONE;
+
 	VkFormat m_vkFormat = VK_FORMAT_UNDEFINED;
 
-	Bool m_depthStencil = false;
 	TextureImplWorkaround m_workarounds = TextureImplWorkaround::NONE;
 
 	TextureImpl(GrManager* manager)
@@ -105,8 +104,6 @@ public:
 	/// Predict the image layout.
 	VkImageLayout computeLayout(TextureUsageBit usage, U level) const;
 
-	VkImageAspectFlags convertAspect(DepthStencilAspectBit ak) const;
-
 	void checkSubresourceRange(const VkImageSubresourceRange& range) const
 	{
 		ANKI_ASSERT(range.baseArrayLayer < m_layerCount);

+ 2 - 20
src/anki/gr/vulkan/TextureImpl.inl.h

@@ -8,29 +8,11 @@
 namespace anki
 {
 
-inline VkImageAspectFlags TextureImpl::convertAspect(DepthStencilAspectBit ak) const
-{
-	VkImageAspectFlags out = 0;
-	if(m_aspect == (VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_DEPTH_BIT))
-	{
-		out = !!(ak & DepthStencilAspectBit::DEPTH) ? VK_IMAGE_ASPECT_DEPTH_BIT : 0;
-		out |= !!(ak & DepthStencilAspectBit::STENCIL) ? VK_IMAGE_ASPECT_STENCIL_BIT : 0;
-	}
-	else
-	{
-		out = m_aspect;
-	}
-
-	ANKI_ASSERT(out != 0);
-	ANKI_ASSERT((out & m_aspect) == out);
-	return out;
-}
-
 inline void TextureImpl::computeSubResourceRange(
 	const TextureSurfaceInfo& surf, DepthStencilAspectBit aspect, VkImageSubresourceRange& range) const
 {
 	checkSurfaceOrVolume(surf);
-	range.aspectMask = convertAspect(aspect);
+	range.aspectMask = convertImageAspect(m_aspect);
 	range.baseMipLevel = surf.m_level;
 	range.levelCount = 1;
 	switch(m_texType)
@@ -61,7 +43,7 @@ inline void TextureImpl::computeSubResourceRange(
 	const TextureVolumeInfo& vol, DepthStencilAspectBit aspect, VkImageSubresourceRange& range) const
 {
 	checkSurfaceOrVolume(vol);
-	range.aspectMask = convertAspect(aspect);
+	range.aspectMask = convertImageAspect(m_aspect);
 	range.baseMipLevel = vol.m_level;
 	range.levelCount = 1;
 	range.baseArrayLayer = 0;

+ 6 - 2
src/anki/gr/vulkan/TextureViewImpl.cpp

@@ -33,18 +33,22 @@ Error TextureViewImpl::init(const TextureViewInitInfo& inf)
 
 	// Compute the VK range
 	VkImageSubresourceRange range;
-	range.aspectMask = tex.convertAspect(m_aspect);
+	range.aspectMask = convertImageAspect(m_aspect & tex.m_aspect);
 	range.baseMipLevel = m_baseMip;
 	range.levelCount = m_mipCount;
 
 	const TextureType type = tex.getTextureType();
-	const U32 faceCount = type == TextureType::CUBE_ARRAY || type == TextureType::CUBE;
+	const U32 faceCount = textureTypeIsCube(type) ? 6 : 1;
 	range.baseArrayLayer = m_baseLayer * faceCount + m_baseFace;
 	range.layerCount = m_layerCount * m_faceCount;
 
 	// Ask the texture for a view
 	m_handle = tex.getOrCreateView(range);
 
+	// Create the hash
+	Array<U64, 2> toHash = {{tex.getUuid(), ptrToNumber(m_handle)}};
+	m_hash = computeHash(&toHash[0], sizeof(toHash));
+
 	return Error::NONE;
 }
 

+ 9 - 0
src/anki/gr/vulkan/TextureViewImpl.h

@@ -21,6 +21,10 @@ public:
 	VkImageView m_handle = {};
 	TexturePtr m_tex; ///< Hold a reference.
 
+	/// This is a hash that depends on the Texture and the VkImageView. It's used as a replacement of
+	/// TextureView::m_uuid since it creates less unique IDs.
+	U64 m_hash = 0;
+
 	TextureViewImpl(GrManager* manager)
 		: TextureView(manager)
 	{
@@ -29,6 +33,11 @@ public:
 	~TextureViewImpl();
 
 	ANKI_USE_RESULT Error init(const TextureViewInitInfo& inf);
+
+	Bool goodForImageLoadStore() const
+	{
+		return m_mipCount == 1 && !m_aspect;
+	}
 };
 /// @}
 

+ 9 - 1
tests/gr/Gr.cpp

@@ -883,6 +883,9 @@ ANKI_TEST(Gr, Texture)
 
 	TexturePtr b = gr->newTexture(init);
 
+	TextureViewInitInfo view(b);
+	TextureViewPtr v = gr->newTextureView(view);
+
 	COMMON_END()
 }
 
@@ -1308,6 +1311,11 @@ ANKI_TEST(Gr, ImageLoadStore)
 
 	TexturePtr tex = gr->newTexture(init);
 
+	TextureViewInitInfo viewInit(tex);
+	viewInit.m_baseMipmap = 1;
+	viewInit.m_mipmapCount = 1;
+	TextureViewPtr view = gr->newTextureView(viewInit);
+
 	// Prog
 	ShaderProgramPtr prog = createProgram(VERT_QUAD_SRC, FRAG_SIMPLE_TEX_SRC, *gr);
 
@@ -1362,7 +1370,7 @@ ANKI_TEST(Gr, ImageLoadStore)
 		cmdb->setTextureSurfaceBarrier(
 			tex, TextureUsageBit::NONE, TextureUsageBit::IMAGE_COMPUTE_WRITE, TextureSurfaceInfo(1, 0, 0, 0));
 		cmdb->bindShaderProgram(compProg);
-		cmdb->bindImage(0, 0, tex, 1);
+		cmdb->bindImage(0, 0, view);
 		cmdb->dispatchCompute(WIDTH / 2, HEIGHT / 2, 1);
 		cmdb->setTextureSurfaceBarrier(tex,
 			TextureUsageBit::IMAGE_COMPUTE_WRITE,