Panagiotis Christopoulos Charitos 9 лет назад
Родитель
Сommit
f39f81e94c

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

@@ -194,7 +194,7 @@ public:
 
 	void dispatchCompute(U32 groupCountX, U32 groupCountY, U32 groupCountZ);
 
-	void generateMipmaps(TexturePtr tex, U depth, U face);
+	void generateMipmaps(TexturePtr tex, U depth, U face, U layer);
 
 	void copyTextureToTexture(TexturePtr src,
 		const TextureSurfaceInfo& srcSurf,

+ 35 - 1
include/anki/gr/Common.h

@@ -97,16 +97,18 @@ public:
 
 	TextureSurfaceInfo(const TextureSurfaceInfo&) = default;
 
-	TextureSurfaceInfo(U level, U depth, U face)
+	TextureSurfaceInfo(U level, U depth, U face, U layer)
 		: m_level(level)
 		, m_depth(depth)
 		, m_face(face)
+		, m_layer(layer)
 	{
 	}
 
 	U32 m_level = 0;
 	U32 m_depth = 0;
 	U32 m_face = 0;
+	U32 m_layer = 0;
 };
 
 // Some constants
@@ -190,6 +192,38 @@ inline U computeMaxMipmapCount(U w, U h, U d)
 void logShaderErrorCode(const CString& error,
 	const CString& source,
 	GenericMemoryPoolAllocator<U8> alloc);
+
+inline void checkTextureSurface(TextureType type,
+	U depth,
+	U mipCount,
+	U layerCount,
+	const TextureSurfaceInfo& surf)
+{
+	ANKI_ASSERT(surf.m_level < mipCount);
+	switch(type)
+	{
+	case TextureType::_2D:
+		ANKI_ASSERT(surf.m_depth == 0 && surf.m_face == 0 && surf.m_layer == 0);
+		break;
+	case TextureType::CUBE:
+		ANKI_ASSERT(surf.m_depth == 0 && surf.m_face < 6 && surf.m_layer == 0);
+		break;
+	case TextureType::_3D:
+		ANKI_ASSERT(
+			surf.m_depth < depth && surf.m_face == 0 && surf.m_layer == 0);
+		break;
+	case TextureType::_2D_ARRAY:
+		ANKI_ASSERT(
+			surf.m_depth == 0 && surf.m_face == 0 && surf.m_layer < layerCount);
+		break;
+	case TextureType::CUBE_ARRAY:
+		ANKI_ASSERT(
+			surf.m_depth == 0 && surf.m_face < 6 && surf.m_layer < layerCount);
+		break;
+	default:
+		ANKI_ASSERT(0);
+	};
+}
 /// @}
 
 } // end namespace anki

+ 2 - 8
include/anki/gr/Framebuffer.h

@@ -20,10 +20,7 @@ class Attachment
 {
 public:
 	TexturePtr m_texture;
-	U32 m_arrayIndex = 0; ///< For array textures
-	U32 m_depth = 0; ///< For 3D textures
-	U32 m_faceIndex = 0; ///< For cubemap textures
-	U32 m_mipmap = 0;
+	TextureSurfaceInfo m_surface;
 	PixelFormat m_format;
 	AttachmentLoadOperation m_loadOperation = AttachmentLoadOperation::CLEAR;
 	AttachmentStoreOperation m_storeOperation = AttachmentStoreOperation::STORE;
@@ -41,10 +38,7 @@ public:
 	Attachment& operator=(const Attachment& b)
 	{
 		m_texture = b.m_texture;
-		m_arrayIndex = b.m_arrayIndex;
-		m_depth = b.m_depth;
-		m_faceIndex = b.m_faceIndex;
-		m_mipmap = b.m_mipmap;
+		m_surface = b.m_surface;
 		m_format = b.m_format;
 		m_loadOperation = b.m_loadOperation;
 		m_storeOperation = b.m_storeOperation;

+ 45 - 4
include/anki/gr/Texture.h

@@ -42,17 +42,58 @@ public:
 	TextureType m_type = TextureType::_2D;
 	U32 m_width = 0;
 	U32 m_height = 0;
-
-	/// Relevant only for 3D, 2DynamicArray and CubeArray textures.
-	U32 m_depth = 0;
+	U32 m_depth = 0; //< Relevant only for 3D textures.
+	U32 m_layerCount = 0; ///< Relevant only for texture arrays.
+	U8 m_mipmapsCount = 0;
 
 	PixelFormat m_format;
-	U8 m_mipmapsCount = 0;
 	U8 m_samples = 1;
 
 	Bool8 m_framebufferAttachment = false;
 
 	SamplerInitInfo m_sampling;
+
+	/// Check the validity of the structure.
+	Bool isValid() const
+	{
+#define ANKI_CHECK_VAL_VALIDITY(x)                                             \
+	do                                                                         \
+	{                                                                          \
+		if(!(x))                                                               \
+		{                                                                      \
+			return false;                                                      \
+		}                                                                      \
+	} while(0)
+
+		ANKI_CHECK_VAL_VALIDITY(m_mipmapsCount > 0);
+		ANKI_CHECK_VAL_VALIDITY(m_width > 0);
+		ANKI_CHECK_VAL_VALIDITY(m_height > 0);
+		switch(m_type)
+		{
+		case TextureType::_2D:
+			ANKI_CHECK_VAL_VALIDITY(m_depth == 1);
+			ANKI_CHECK_VAL_VALIDITY(m_layerCount == 1);
+			break;
+		case TextureType::CUBE:
+			ANKI_CHECK_VAL_VALIDITY(m_depth == 1);
+			ANKI_CHECK_VAL_VALIDITY(m_layerCount == 1);
+			break;
+		case TextureType::_3D:
+			ANKI_CHECK_VAL_VALIDITY(m_depth > 0);
+			ANKI_CHECK_VAL_VALIDITY(m_layerCount == 1);
+			break;
+		case TextureType::_2D_ARRAY:
+		case TextureType::CUBE_ARRAY:
+			ANKI_CHECK_VAL_VALIDITY(m_depth == 1);
+			ANKI_CHECK_VAL_VALIDITY(m_layerCount > 0);
+			break;
+		default:
+			ANKI_CHECK_VAL_VALIDITY(0);
+		};
+
+		return true;
+#undef ANKI_CHECK_VAL_VALIDITY
+	}
 };
 
 /// GPU texture

+ 10 - 2
include/anki/gr/gl/TextureImpl.h

@@ -22,10 +22,12 @@ public:
 	GLenum m_internalFormat = GL_NONE; ///< GL_COMPRESSED_RED, GL_RGB16 etc
 	GLenum m_format = GL_NONE;
 	GLenum m_type = GL_NONE;
+	TextureType m_texType = TextureType::_1D;
 	U32 m_width = 0;
 	U32 m_height = 0;
 	U32 m_depth = 0;
-	U32 m_surfaceCount = 0;
+	U32 m_layerCount = 0;
+	U32 m_surfaceCountPerLevel = 0;
 	U8 m_mipsCount = 0;
 	U8 m_faceCount = 0; ///< 6 for cubes and 1 for the rest
 	Bool8 m_compressed = false;
@@ -38,6 +40,12 @@ public:
 
 	~TextureImpl();
 
+	void checkSurface(const TextureSurfaceInfo& surf) const
+	{
+		checkTextureSurface(
+			m_texType, m_depth, m_mipsCount, m_layerCount, surf);
+	}
+
 	/// Create the texture storage.
 	void init(const TextureInitInfo& init);
 
@@ -45,7 +53,7 @@ public:
 	void write(const TextureSurfaceInfo& surf, void* data, PtrSize dataSize);
 
 	/// Generate mipmaps.
-	void generateMipmaps(U depth, U face);
+	void generateMipmaps(U depth, U face, U layer);
 
 	/// Copy a single surface from one texture to another.
 	static void copy(const TextureImpl& src,

+ 1 - 1
include/anki/renderer/Is.h

@@ -60,7 +60,7 @@ anki_internal:
 
 	void generateMipmaps(CommandBufferPtr& cmdb)
 	{
-		cmdb->generateMipmaps(m_rt, 0, 0);
+		cmdb->generateMipmaps(m_rt, 0, 0, 0);
 	}
 
 private:

+ 16 - 6
include/anki/resource/ImageLoader.h

@@ -14,7 +14,6 @@ namespace anki
 {
 
 /// Image loader.
-/// Used in Texture::load. Supported types: TGA and an AnKi specific format.
 class ImageLoader
 {
 public:
@@ -87,8 +86,16 @@ public:
 
 	U getDepth() const
 	{
-		ANKI_ASSERT(m_depth != 0);
-		return m_depth;
+		ANKI_ASSERT(
+			m_depthOrLayerCount != 0 && m_textureType == TextureType::_3D);
+		return m_depthOrLayerCount;
+	}
+
+	U getLayerCount() const
+	{
+		ANKI_ASSERT(m_depthOrLayerCount != 0
+			&& m_textureType == TextureType::_2D_ARRAY);
+		return m_depthOrLayerCount;
 	}
 
 	TextureType getTextureType() const
@@ -97,7 +104,7 @@ public:
 		return m_textureType;
 	}
 
-	const Surface& getSurface(U mipLevel, U layer) const;
+	const Surface& getSurface(U level, U depth, U face, U layer) const;
 
 	GenericMemoryPoolAllocator<U8> getAllocator() const
 	{
@@ -117,10 +124,13 @@ public:
 private:
 	GenericMemoryPoolAllocator<U8> m_alloc;
 	Atomic<I32> m_refcount = {0};
-	/// [mip][depthFace]
+
+	/// [mip][depth or face or layer]. Loader doesn't support cube arrays ATM
+	/// so face and layer won't be used at the same time.
 	DynamicArray<Surface> m_surfaces;
+
 	U8 m_mipLevels = 0;
-	U8 m_depth = 0;
+	U8 m_depthOrLayerCount = 0;
 	DataCompression m_compression = DataCompression::NONE;
 	ColorFormat m_colorFormat = ColorFormat::NONE;
 	TextureType m_textureType = TextureType::NONE;

+ 14 - 4
include/anki/resource/TextureResource.h

@@ -43,24 +43,34 @@ public:
 		return m_tex;
 	}
 
-	U32 getWidth() const
+	U getWidth() const
 	{
+		ANKI_ASSERT(m_size.x());
 		return m_size.x();
 	}
 
-	U32 getHeight() const
+	U getHeight() const
 	{
+		ANKI_ASSERT(m_size.y());
 		return m_size.y();
 	}
 
-	U32 getDepth() const
+	U getDepth() const
 	{
+		ANKI_ASSERT(m_size.z());
 		return m_size.z();
 	}
 
+	U getLayerCount() const
+	{
+		ANKI_ASSERT(m_layerCount);
+		return m_layerCount;
+	}
+
 private:
 	TexturePtr m_tex;
-	UVec3 m_size;
+	UVec3 m_size = UVec3(0u);
+	U32 m_layerCount = 0;
 };
 /// @}
 

+ 6 - 4
src/gr/gl/CommandBuffer.cpp

@@ -431,25 +431,27 @@ public:
 	TexturePtr m_tex;
 	U32 m_depth;
 	U8 m_face;
+	U32 m_layer;
 
-	GenMipsCommand(const TexturePtr& tex, U depth, U face)
+	GenMipsCommand(const TexturePtr& tex, U depth, U face, U layer)
 		: m_tex(tex)
 		, m_depth(depth)
 		, m_face(face)
+		, m_layer(layer)
 	{
 	}
 
 	Error operator()(GlState&)
 	{
-		m_tex->getImplementation().generateMipmaps(m_depth, m_face);
+		m_tex->getImplementation().generateMipmaps(m_depth, m_face, m_layer);
 		return ErrorCode::NONE;
 	}
 };
 
-void CommandBuffer::generateMipmaps(TexturePtr tex, U depth, U face)
+void CommandBuffer::generateMipmaps(TexturePtr tex, U depth, U face, U layer)
 {
 	ANKI_ASSERT(!m_impl->m_dbg.m_insideRenderPass);
-	m_impl->pushBackNewCommand<GenMipsCommand>(tex, depth, face);
+	m_impl->pushBackNewCommand<GenMipsCommand>(tex, depth, face, layer);
 }
 
 //==============================================================================

+ 17 - 31
src/gr/gl/FramebufferImpl.cpp

@@ -81,7 +81,7 @@ Error FramebufferImpl::init(const FramebufferInitInfo& init)
 void FramebufferImpl::attachTextureInternal(
 	GLenum attachment, const TextureImpl& tex, const Attachment& info)
 {
-	ANKI_ASSERT(info.m_mipmap < tex.m_mipsCount);
+	tex.checkSurface(info.m_surface);
 
 	const GLenum target = GL_FRAMEBUFFER;
 	switch(tex.m_target)
@@ -90,53 +90,39 @@ void FramebufferImpl::attachTextureInternal(
 #if ANKI_GL == ANKI_GL_DESKTOP
 	case GL_TEXTURE_2D_MULTISAMPLE:
 #endif
-		ANKI_ASSERT(info.m_arrayIndex == 0);
-		ANKI_ASSERT(info.m_depth == 0);
-		ANKI_ASSERT(info.m_faceIndex == 0);
-
-		glFramebufferTexture2D(
-			target, attachment, tex.m_target, tex.getGlName(), info.m_mipmap);
+		glFramebufferTexture2D(target,
+			attachment,
+			tex.m_target,
+			tex.getGlName(),
+			info.m_surface.m_level);
 		break;
 	case GL_TEXTURE_CUBE_MAP:
-		ANKI_ASSERT(info.m_arrayIndex == 0);
-		ANKI_ASSERT(info.m_depth == 0);
-		ANKI_ASSERT(info.m_faceIndex < 6);
-
 		glFramebufferTexture2D(target,
 			attachment,
-			GL_TEXTURE_CUBE_MAP_POSITIVE_X + info.m_faceIndex,
+			GL_TEXTURE_CUBE_MAP_POSITIVE_X + info.m_surface.m_face,
 			tex.getGlName(),
-			info.m_mipmap);
+			info.m_surface.m_level);
 		break;
 	case GL_TEXTURE_2D_ARRAY:
-		ANKI_ASSERT(info.m_arrayIndex < tex.m_depth);
-		ANKI_ASSERT(info.m_depth == 0);
-		ANKI_ASSERT(info.m_faceIndex == 0);
-
 		glFramebufferTextureLayer(target,
 			attachment,
 			tex.getGlName(),
-			info.m_mipmap,
-			info.m_arrayIndex);
+			info.m_surface.m_level,
+			info.m_surface.m_layer);
 		break;
 	case GL_TEXTURE_3D:
-		ANKI_ASSERT(info.m_arrayIndex == 0);
-		ANKI_ASSERT(info.m_depth < tex.m_depth);
-		ANKI_ASSERT(info.m_faceIndex == 0);
-
-		glFramebufferTextureLayer(
-			target, attachment, tex.getGlName(), info.m_mipmap, info.m_depth);
+		glFramebufferTextureLayer(target,
+			attachment,
+			tex.getGlName(),
+			info.m_surface.m_level,
+			info.m_surface.m_depth);
 		break;
 	case GL_TEXTURE_CUBE_MAP_ARRAY:
-		ANKI_ASSERT(info.m_arrayIndex < tex.m_depth);
-		ANKI_ASSERT(info.m_depth == 0);
-		ANKI_ASSERT(info.m_faceIndex < 6);
-
 		glFramebufferTextureLayer(target,
 			attachment,
 			tex.getGlName(),
-			info.m_mipmap,
-			info.m_arrayIndex * 6 + info.m_faceIndex);
+			info.m_surface.m_level,
+			info.m_surface.m_layer * 6 + info.m_surface.m_face);
 		break;
 	default:
 		ANKI_ASSERT(0);

+ 1 - 0
src/gr/gl/Texture.cpp

@@ -52,6 +52,7 @@ public:
 
 void Texture::init(const TextureInitInfo& init)
 {
+	ANKI_ASSERT(init.isValid());
 	m_impl.reset(getAllocator().newInstance<TextureImpl>(&getManager()));
 
 	CommandBufferPtr cmdb =

+ 47 - 34
src/gr/gl/TextureImpl.cpp

@@ -277,9 +277,7 @@ void TextureImpl::init(const TextureInitInfo& init)
 	// Sanity checks
 	//
 	ANKI_ASSERT(!isCreated());
-	ANKI_ASSERT(init.m_width > 0 && init.m_height > 0);
-	ANKI_ASSERT(init.m_mipmapsCount > 0);
-	ANKI_ASSERT(init.m_samples > 0);
+	ANKI_ASSERT(init.isValid());
 
 	// Create
 	//
@@ -290,13 +288,24 @@ void TextureImpl::init(const TextureInitInfo& init)
 	m_height = init.m_height;
 	m_depth = init.m_depth;
 	ANKI_ASSERT(m_depth > 0);
+	m_layerCount = init.m_layerCount;
+	ANKI_ASSERT(m_layerCount > 0);
 	m_target = convertTextureType(init.m_type);
+	m_texType = init.m_type;
 
 	convertTextureInformation(
 		init.m_format, m_compressed, m_format, m_internalFormat, m_type);
 
-	m_mipsCount =
-		min<U>(init.m_mipmapsCount, computeMaxMipmapCount(m_width, m_height));
+	if(m_target != GL_TEXTURE_3D)
+	{
+		m_mipsCount = min<U>(
+			init.m_mipmapsCount, computeMaxMipmapCount(m_width, m_height));
+	}
+	else
+	{
+		m_mipsCount = min<U>(init.m_mipmapsCount,
+			computeMaxMipmapCount(m_width, m_height, m_depth));
+	}
 
 	// Bind
 	bind();
@@ -315,16 +324,23 @@ void TextureImpl::init(const TextureInitInfo& init)
 			m_internalFormat,
 			m_width,
 			m_height,
-			init.m_depth * 6);
+			m_layerCount * 6);
 		break;
 	case GL_TEXTURE_2D_ARRAY:
+		glTexStorage3D(m_target,
+			m_mipsCount,
+			m_internalFormat,
+			m_width,
+			m_height,
+			m_layerCount);
+		break;
 	case GL_TEXTURE_3D:
 		glTexStorage3D(m_target,
 			m_mipsCount,
 			m_internalFormat,
 			m_width,
 			m_height,
-			init.m_depth);
+			m_depth);
 		break;
 	case GL_TEXTURE_2D_MULTISAMPLE:
 		glTexStorage2DMultisample(m_target,
@@ -344,20 +360,23 @@ void TextureImpl::init(const TextureInitInfo& init)
 	case GL_TEXTURE_1D:
 	case GL_TEXTURE_2D:
 	case GL_TEXTURE_2D_MULTISAMPLE:
-		m_surfaceCount = 1;
+		m_surfaceCountPerLevel = 1;
 		m_faceCount = 1;
 		break;
 	case GL_TEXTURE_CUBE_MAP:
-		m_surfaceCount = 6;
+		m_surfaceCountPerLevel = 6;
 		m_faceCount = 6;
 		break;
 	case GL_TEXTURE_CUBE_MAP_ARRAY:
-		m_surfaceCount = init.m_depth * 6;
+		m_surfaceCountPerLevel = m_layerCount * 6;
 		m_faceCount = 6;
 		break;
 	case GL_TEXTURE_2D_ARRAY:
+		m_surfaceCountPerLevel = m_layerCount;
+		m_faceCount = 1;
+		break;
 	case GL_TEXTURE_3D:
-		m_surfaceCount = init.m_depth;
+		m_surfaceCountPerLevel = m_depth;
 		m_faceCount = 1;
 		break;
 	default:
@@ -419,16 +438,14 @@ void TextureImpl::init(const TextureInitInfo& init)
 void TextureImpl::write(
 	const TextureSurfaceInfo& surf, void* data, PtrSize dataSize)
 {
-	U mipmap = surf.m_level;
-	U surfIdx = computeSurfaceIdx(surf);
-
+	checkSurface(surf);
 	ANKI_ASSERT(data);
 	ANKI_ASSERT(dataSize > 0);
-	ANKI_ASSERT(mipmap < m_mipsCount);
 
+	U mipmap = surf.m_level;
+	U surfIdx = computeSurfaceIdx(surf);
 	U w = m_width >> mipmap;
 	U h = m_height >> mipmap;
-
 	ANKI_ASSERT(w > 0);
 	ANKI_ASSERT(h > 0);
 
@@ -476,8 +493,6 @@ void TextureImpl::write(
 		break;
 	case GL_TEXTURE_2D_ARRAY:
 	case GL_TEXTURE_3D:
-		ANKI_ASSERT(m_depth > 0);
-
 		if(!m_compressed)
 		{
 			glTexSubImage3D(m_target,
@@ -515,22 +530,21 @@ void TextureImpl::write(
 }
 
 //==============================================================================
-void TextureImpl::generateMipmaps(U depth, U face)
+void TextureImpl::generateMipmaps(U depth, U face, U layer)
 {
-	U surface = computeSurfaceIdx(TextureSurfaceInfo(0, depth, face));
-	ANKI_ASSERT(surface < m_surfaceCount);
+	U surface = computeSurfaceIdx(TextureSurfaceInfo(0, depth, face, layer));
 	ANKI_ASSERT(!m_compressed);
 
-	if(m_surfaceCount > 1)
+	if(m_surfaceCountPerLevel > 1)
 	{
-		// Create the view array
+		// Lazily create the view array
 		if(m_texViews.getSize() == 0)
 		{
-			m_texViews.create(getAllocator(), m_surfaceCount);
+			m_texViews.create(getAllocator(), m_surfaceCountPerLevel);
 			memset(&m_texViews[0], 0, m_texViews.getSize() * sizeof(GLuint));
 		}
 
-		// Create the view
+		// Lazily create the view
 		if(m_texViews[surface] == 0)
 		{
 			glGenTextures(1, &m_texViews[surface]);
@@ -630,23 +644,22 @@ void TextureImpl::clear(
 //==============================================================================
 U TextureImpl::computeSurfaceIdx(const TextureSurfaceInfo& surf) const
 {
-	ANKI_ASSERT(surf.m_face < m_faceCount);
-	ANKI_ASSERT(surf.m_depth < m_depth);
-	ANKI_ASSERT(surf.m_level < m_mipsCount);
+	checkSurface(surf);
+	U out;
 
 	if(m_target == GL_TEXTURE_3D)
 	{
 		// Check depth for this level
-		U depth = m_depth >> surf.m_level;
-		ANKI_ASSERT(surf.m_depth < depth);
-		(void)depth;
-
-		return surf.m_depth;
+		ANKI_ASSERT(surf.m_depth < (m_depth >> surf.m_level));
+		out = surf.m_depth;
 	}
 	else
 	{
-		return m_faceCount * surf.m_depth + surf.m_face;
+		out = m_faceCount * surf.m_layer + surf.m_face;
 	}
+
+	ANKI_ASSERT(out < m_surfaceCountPerLevel);
+	return out;
 }
 
 } // end namespace anki

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

@@ -295,7 +295,7 @@ void CommandBufferImpl::uploadTextureSurface(TexturePtr tex,
 		range.baseArrayLayer = surf.m_depth;
 		break;
 	case TextureType::_3D:
-		range.baseArrayLayer = surf.m_depth;
+		range.baseArrayLayer = 0;
 		break;
 	default:
 		ANKI_ASSERT(0);

+ 1 - 1
src/renderer/DownscaleBlur.cpp

@@ -51,7 +51,7 @@ Error DownscaleBlur::initSubpass(U idx, const UVec2& inputTexSize)
 	fbInit.m_colorAttachments[0].m_texture = m_r->getIs().getRt();
 	fbInit.m_colorAttachments[0].m_loadOperation =
 		AttachmentLoadOperation::DONT_CARE;
-	fbInit.m_colorAttachments[0].m_mipmap = idx + 1;
+	fbInit.m_colorAttachments[0].m_surface.m_level = idx + 1;
 	pass.m_fb = getGrManager().newInstance<Framebuffer>(fbInit);
 
 	// Resources

+ 1 - 1
src/renderer/Fs.cpp

@@ -42,7 +42,7 @@ Error Fs::init(const ConfigSet&)
 	fbInit.m_depthStencilAttachment.m_texture = m_r->getMs().getDepthRt();
 	fbInit.m_depthStencilAttachment.m_loadOperation =
 		AttachmentLoadOperation::LOAD;
-	fbInit.m_depthStencilAttachment.m_mipmap = 1;
+	fbInit.m_depthStencilAttachment.m_surface.m_level = 1;
 	m_fb = getGrManager().newInstance<Framebuffer>(fbInit);
 
 	// Init the global resources

+ 12 - 10
src/renderer/Ir.cpp

@@ -79,7 +79,8 @@ Error Ir::init(const ConfigSet& config)
 
 	texinit.m_width = m_fbSize;
 	texinit.m_height = m_fbSize;
-	texinit.m_depth = m_cubemapArrSize;
+	texinit.m_layerCount = m_cubemapArrSize;
+	texinit.m_depth = 1;
 	texinit.m_type = TextureType::CUBE_ARRAY;
 	texinit.m_format = Is::RT_PIXEL_FORMAT;
 	texinit.m_mipmapsCount = MAX_U8;
@@ -112,13 +113,14 @@ Error Ir::init(const ConfigSet& config)
 			{
 				// Do env
 				cmdb->clearTexture(
-					m_envCubemapArr, TextureSurfaceInfo(l, i, f), clear);
+					m_envCubemapArr, TextureSurfaceInfo(l, 0, f, i), clear);
 			}
 
 			for(U l = 0; l < irrMipCount; ++l)
 			{
-				cmdb->clearTexture(
-					m_irradianceCubemapArr, TextureSurfaceInfo(l, i, f), clear);
+				cmdb->clearTexture(m_irradianceCubemapArr,
+					TextureSurfaceInfo(l, 0, f, i),
+					clear);
 			}
 		}
 	}
@@ -270,12 +272,12 @@ Error Ir::renderReflection(RenderingContext& ctx,
 
 		// Copy env texture
 		cmdb->copyTextureToTexture(m_nestedR.getIs().getRt(),
-			TextureSurfaceInfo(0, 0, 0),
+			TextureSurfaceInfo(0, 0, 0, 0),
 			m_envCubemapArr,
-			TextureSurfaceInfo(0, cubemapIdx, i));
+			TextureSurfaceInfo(0, 0, i, cubemapIdx));
 
 		// Gen mips of env tex
-		cmdb->generateMipmaps(m_envCubemapArr, cubemapIdx, i);
+		cmdb->generateMipmaps(m_envCubemapArr, 0, i, cubemapIdx);
 	}
 
 	// Compute irradiance
@@ -294,8 +296,8 @@ Error Ir::renderReflection(RenderingContext& ctx,
 		FramebufferInitInfo fbinit;
 		fbinit.m_colorAttachmentCount = 1;
 		fbinit.m_colorAttachments[0].m_texture = m_irradianceCubemapArr;
-		fbinit.m_colorAttachments[0].m_arrayIndex = cubemapIdx;
-		fbinit.m_colorAttachments[0].m_faceIndex = i;
+		fbinit.m_colorAttachments[0].m_surface.m_layer = cubemapIdx;
+		fbinit.m_colorAttachments[0].m_surface.m_face = i;
 		fbinit.m_colorAttachments[0].m_format = Is::RT_PIXEL_FORMAT;
 		fbinit.m_colorAttachments[0].m_loadOperation =
 			AttachmentLoadOperation::DONT_CARE;
@@ -306,7 +308,7 @@ Error Ir::renderReflection(RenderingContext& ctx,
 		m_r->drawQuad(cmdb);
 		cmdb->endRenderPass();
 
-		cmdb->generateMipmaps(m_irradianceCubemapArr, cubemapIdx, i);
+		cmdb->generateMipmaps(m_irradianceCubemapArr, 0, i, cubemapIdx);
 	}
 
 	return ErrorCode::NONE;

+ 3 - 2
src/renderer/Renderer.cpp

@@ -275,8 +275,8 @@ Error Renderer::render(RenderingContext& ctx)
 
 	m_is->run(ctx);
 
-	cmdb->generateMipmaps(m_ms->getDepthRt(), 0, 0);
-	cmdb->generateMipmaps(m_ms->getRt2(), 0, 0);
+	cmdb->generateMipmaps(m_ms->getDepthRt(), 0, 0, 0);
+	cmdb->generateMipmaps(m_ms->getRt2(), 0, 0, 0);
 
 	m_fs->run(ctx);
 	m_lf->run(ctx);
@@ -368,6 +368,7 @@ void Renderer::createRenderTarget(U32 w,
 	init.m_width = w;
 	init.m_height = h;
 	init.m_depth = 1;
+	init.m_layerCount = 1;
 	init.m_type = TextureType::_2D;
 	init.m_format = format;
 	init.m_mipmapsCount = mipsCount;

+ 5 - 4
src/renderer/Sm.cpp

@@ -37,7 +37,8 @@ Error Sm::init(const ConfigSet& config)
 	sminit.m_type = TextureType::_2D_ARRAY;
 	sminit.m_width = m_resolution;
 	sminit.m_height = m_resolution;
-	sminit.m_depth = config.getNumber("sm.maxLights");
+	sminit.m_layerCount = config.getNumber("sm.maxLights");
+	sminit.m_depth = 1;
 	sminit.m_format = DEPTH_RT_PIXEL_FORMAT;
 	sminit.m_mipmapsCount = 1;
 	sminit.m_sampling.m_minMagFilter =
@@ -63,7 +64,7 @@ Error Sm::init(const ConfigSet& config)
 	{
 		sm.m_layerId = layer;
 
-		fbInit.m_depthStencilAttachment.m_arrayIndex = layer;
+		fbInit.m_depthStencilAttachment.m_surface.m_layer = layer;
 		sm.m_fb = getGrManager().newInstance<Framebuffer>(fbInit);
 
 		++layer;
@@ -81,8 +82,8 @@ Error Sm::init(const ConfigSet& config)
 
 		for(U i = 0; i < 6; ++i)
 		{
-			fbInit.m_depthStencilAttachment.m_arrayIndex = layer;
-			fbInit.m_depthStencilAttachment.m_faceIndex = i;
+			fbInit.m_depthStencilAttachment.m_surface.m_layer = layer;
+			fbInit.m_depthStencilAttachment.m_surface.m_face = i;
 			sm.m_fb[i] = getGrManager().newInstance<Framebuffer>(fbInit);
 		}
 

+ 3 - 1
src/renderer/Ssao.cpp

@@ -108,6 +108,7 @@ Error Ssao::initInternal(const ConfigSet& config)
 
 	tinit.m_width = tinit.m_height = NOISE_TEX_SIZE;
 	tinit.m_depth = 1;
+	tinit.m_layerCount = 1;
 	tinit.m_type = TextureType::_2D;
 	tinit.m_format =
 		PixelFormat(ComponentFormat::R32G32B32, TransformFormat::FLOAT);
@@ -128,7 +129,8 @@ Error Ssao::initInternal(const ConfigSet& config)
 
 	genNoise(noise, noise + NOISE_TEX_SIZE * NOISE_TEX_SIZE);
 
-	cmdb->uploadTextureSurface(m_noiseTex, TextureSurfaceInfo(0, 0, 0), token);
+	cmdb->uploadTextureSurface(
+		m_noiseTex, TextureSurfaceInfo(0, 0, 0, 0), token);
 	cmdb->flush();
 
 	//

+ 28 - 29
src/resource/ImageLoader.cpp

@@ -203,7 +203,7 @@ public:
 	Array<U8, 8> m_magic;
 	U32 m_width;
 	U32 m_height;
-	U32 m_depth;
+	U32 m_depthOrLayerCount;
 	ImageLoader::TextureType m_type;
 	ImageLoader::ColorFormat m_colorFormat;
 	ImageLoader::DataCompression m_compressionFormats;
@@ -256,21 +256,21 @@ static PtrSize calcSizeOfSegment(
 	U width = header.m_width;
 	U height = header.m_height;
 	U mips = header.m_mipLevels;
-	U layers = 0;
+	U surfCountPerMip = 0;
 
 	ANKI_ASSERT(mips > 0);
 
 	switch(header.m_type)
 	{
 	case ImageLoader::TextureType::_2D:
-		layers = 1;
+		surfCountPerMip = 1;
 		break;
 	case ImageLoader::TextureType::CUBE:
-		layers = 6;
+		surfCountPerMip = 6;
 		break;
 	case ImageLoader::TextureType::_2D_ARRAY:
 	case ImageLoader::TextureType::_3D:
-		layers = header.m_depth;
+		surfCountPerMip = header.m_depthOrLayerCount;
 		break;
 	default:
 		ANKI_ASSERT(0);
@@ -279,8 +279,8 @@ static PtrSize calcSizeOfSegment(
 
 	while(mips-- != 0)
 	{
-		out +=
-			calcSurfaceSize(width, height, comp, header.m_colorFormat) * layers;
+		out += calcSurfaceSize(width, height, comp, header.m_colorFormat)
+			* surfCountPerMip;
 
 		width /= 2;
 		height /= 2;
@@ -295,7 +295,7 @@ static ANKI_USE_RESULT Error loadAnkiTexture(ResourceFilePtr file,
 	ImageLoader::DataCompression& preferredCompression,
 	DynamicArray<ImageLoader::Surface>& surfaces,
 	GenericMemoryPoolAllocator<U8>& alloc,
-	U8& depth,
+	U8& depthOrLayerCount,
 	U8& mipLevels,
 	ImageLoader::TextureType& textureType,
 	ImageLoader::ColorFormat& colorFormat)
@@ -322,9 +322,9 @@ static ANKI_USE_RESULT Error loadAnkiTexture(ResourceFilePtr file,
 		return ErrorCode::USER_DATA;
 	}
 
-	if(header.m_depth < 1 || header.m_depth > 128)
+	if(header.m_depthOrLayerCount < 1 || header.m_depthOrLayerCount > 128)
 	{
-		ANKI_LOGE("Zero or too big depth");
+		ANKI_LOGE("Zero or too big depth or layerCount");
 		return ErrorCode::USER_DATA;
 	}
 
@@ -395,14 +395,14 @@ static ANKI_USE_RESULT Error loadAnkiTexture(ResourceFilePtr file,
 	switch(header.m_type)
 	{
 	case ImageLoader::TextureType::_2D:
-		depth = 1;
+		depthOrLayerCount = 1;
 		break;
 	case ImageLoader::TextureType::CUBE:
-		depth = 6;
+		depthOrLayerCount = 6;
 		break;
 	case ImageLoader::TextureType::_3D:
 	case ImageLoader::TextureType::_2D_ARRAY:
-		depth = header.m_depth;
+		depthOrLayerCount = header.m_depthOrLayerCount;
 		break;
 	default:
 		ANKI_ASSERT(0);
@@ -455,7 +455,7 @@ static ANKI_USE_RESULT Error loadAnkiTexture(ResourceFilePtr file,
 	//
 
 	// Allocate the surfaces
-	surfaces.create(alloc, mipLevels * depth);
+	surfaces.create(alloc, mipLevels * depthOrLayerCount);
 
 	// Read all surfaces
 	U mipWidth = header.m_width;
@@ -463,7 +463,7 @@ static ANKI_USE_RESULT Error loadAnkiTexture(ResourceFilePtr file,
 	U index = 0;
 	for(U mip = 0; mip < header.m_mipLevels; mip++)
 	{
-		for(U d = 0; d < depth; d++)
+		for(U d = 0; d < depthOrLayerCount; d++)
 		{
 			U dataSize = calcSurfaceSize(mipWidth,
 				mipHeight,
@@ -523,7 +523,7 @@ Error ImageLoader::load(
 		m_surfaces.create(m_alloc, 1);
 
 		m_mipLevels = 1;
-		m_depth = 1;
+		m_depthOrLayerCount = 1;
 		ANKI_CHECK(loadTga(file,
 			m_surfaces[0].m_width,
 			m_surfaces[0].m_height,
@@ -559,7 +559,7 @@ Error ImageLoader::load(
 			m_compression,
 			m_surfaces,
 			m_alloc,
-			m_depth,
+			m_depthOrLayerCount,
 			m_mipLevels,
 			m_textureType,
 			m_colorFormat));
@@ -574,34 +574,33 @@ Error ImageLoader::load(
 }
 
 //==============================================================================
-const ImageLoader::Surface& ImageLoader::getSurface(U mipLevel, U layer) const
+const ImageLoader::Surface& ImageLoader::getSurface(
+	U level, U depth, U face, U layer) const
 {
-	ANKI_ASSERT(mipLevel < m_mipLevels);
+	ANKI_ASSERT(level < m_mipLevels);
 
-	U layers = 0;
+	U idx = 0;
 
 	switch(m_textureType)
 	{
 	case TextureType::_2D:
-		layers = 1;
+		idx = level;
 		break;
 	case TextureType::CUBE:
-		layers = 6;
+		ANKI_ASSERT(face < 6);
+		idx = level * 6 + face;
 		break;
 	case TextureType::_3D:
+		idx = level * m_depthOrLayerCount + depth;
+		break;
 	case TextureType::_2D_ARRAY:
-		layers = m_depth;
+		idx = level * m_depthOrLayerCount + layer;
 		break;
 	default:
 		ANKI_ASSERT(0);
 	}
 
-	// [mip][depthFace]
-	U index = mipLevel * layers + layer;
-
-	ANKI_ASSERT(index < m_surfaces.getSize());
-
-	return m_surfaces[index];
+	return m_surfaces[idx];
 }
 
 //==============================================================================

+ 61 - 56
src/resource/TextureResource.cpp

@@ -23,6 +23,7 @@ public:
 	TexturePtr m_tex;
 	GrManager* m_gr ANKI_DBG_NULLIFY_PTR;
 	U m_depth = 0;
+	U m_layers = 0;
 	U m_faces = 0;
 
 	class
@@ -31,6 +32,7 @@ public:
 		U m_depth = 0;
 		U m_face = 0;
 		U m_mip = 0;
+		U m_layer = 0;
 	} m_ctx;
 
 	TexUploadTask(GenericMemoryPoolAllocator<U8> alloc)
@@ -47,52 +49,62 @@ Error TexUploadTask::operator()(AsyncLoaderTaskContext& ctx)
 	CommandBufferPtr cmdb;
 
 	// Upload the data
-	for(U depth = m_ctx.m_depth; depth < m_depth; ++depth)
+	for(U layer = m_ctx.m_layer; layer < m_layers; ++layer)
 	{
-		for(U face = m_ctx.m_face; face < m_faces; ++face)
+		for(U depth = m_ctx.m_depth; depth < m_depth; ++depth)
 		{
-			for(U mip = m_ctx.m_mip; mip < m_loader.getMipLevelsCount(); ++mip)
+			for(U face = m_ctx.m_face; face < m_faces; ++face)
 			{
-				U surfIdx = max(depth, face);
-				const auto& surf = m_loader.getSurface(mip, surfIdx);
-
-				TransientMemoryToken token;
-				Error err = ErrorCode::NONE;
-				void* data = m_gr->allocateFrameTransientMemory(
-					surf.m_data.getSize(), BufferUsage::TRANSFER, token, &err);
-
-				if(!err)
+				for(U mip = m_ctx.m_mip; mip < m_loader.getMipLevelsCount();
+					++mip)
 				{
-					// There is enough transfer memory
-
-					memcpy(data, &surf.m_data[0], surf.m_data.getSize());
-
-					if(!cmdb)
+					const auto& surf =
+						m_loader.getSurface(mip, depth, face, layer);
+
+					TransientMemoryToken token;
+					Error err = ErrorCode::NONE;
+					void* data = m_gr->allocateFrameTransientMemory(
+						surf.m_data.getSize(),
+						BufferUsage::TRANSFER,
+						token,
+						&err);
+
+					if(!err)
 					{
-						cmdb = m_gr->newInstance<CommandBuffer>(
-							CommandBufferInitInfo());
-					}
+						// There is enough transfer memory
 
-					cmdb->uploadTextureSurface(
-						m_tex, TextureSurfaceInfo(mip, depth, face), token);
-				}
-				else
-				{
-					// Not enough transfer memory. Move the work to the future
+						memcpy(data, &surf.m_data[0], surf.m_data.getSize());
 
-					if(cmdb)
-					{
-						cmdb->flush();
+						if(!cmdb)
+						{
+							cmdb = m_gr->newInstance<CommandBuffer>(
+								CommandBufferInitInfo());
+						}
+
+						cmdb->uploadTextureSurface(m_tex,
+							TextureSurfaceInfo(mip, depth, face, layer),
+							token);
 					}
+					else
+					{
+						// Not enough transfer memory. Move the work to the
+						// future
+
+						if(cmdb)
+						{
+							cmdb->flush();
+						}
 
-					m_ctx.m_depth = depth;
-					m_ctx.m_mip = mip;
-					m_ctx.m_face = face;
+						m_ctx.m_depth = depth;
+						m_ctx.m_mip = mip;
+						m_ctx.m_face = face;
+						m_ctx.m_layer = layer;
 
-					ctx.m_pause = true;
-					ctx.m_resubmitTask = true;
+						ctx.m_pause = true;
+						ctx.m_resubmitTask = true;
 
-					return ErrorCode::NONE;
+						return ErrorCode::NONE;
+					}
 				}
 			}
 		}
@@ -120,7 +132,6 @@ TextureResource::~TextureResource()
 Error TextureResource::load(const ResourceFilename& filename)
 {
 	TextureInitInfo init;
-	U depth = 0;
 	U faces = 0;
 
 	// Load image
@@ -133,43 +144,35 @@ Error TextureResource::load(const ResourceFilename& filename)
 
 	ANKI_CHECK(loader.load(file, filename, getManager().getMaxTextureSize()));
 
-	// width + height
-	const auto& tmpSurf = loader.getSurface(0, 0);
+	// Various sizes
+	const auto& tmpSurf = loader.getSurface(0, 0, 0, 0);
 	init.m_width = tmpSurf.m_width;
 	init.m_height = tmpSurf.m_height;
 
-	// depth
-	if(loader.getTextureType() == ImageLoader::TextureType::_2D_ARRAY
-		|| loader.getTextureType() == ImageLoader::TextureType::_3D)
-	{
-		init.m_depth = loader.getDepth();
-	}
-	else
-	{
-		init.m_depth = 1;
-	}
-
-	// target
 	switch(loader.getTextureType())
 	{
 	case ImageLoader::TextureType::_2D:
 		init.m_type = TextureType::_2D;
-		depth = 1;
+		init.m_depth = 1;
 		faces = 1;
+		init.m_layerCount = 1;
 		break;
 	case ImageLoader::TextureType::CUBE:
 		init.m_type = TextureType::CUBE;
-		depth = 1;
+		init.m_depth = 1;
 		faces = 6;
+		init.m_layerCount = 1;
 		break;
 	case ImageLoader::TextureType::_2D_ARRAY:
 		init.m_type = TextureType::_2D_ARRAY;
-		depth = init.m_depth;
+		init.m_layerCount = loader.getLayerCount();
+		init.m_depth = 1;
 		faces = 1;
 		break;
 	case ImageLoader::TextureType::_3D:
 		init.m_type = TextureType::_3D;
-		depth = init.m_depth;
+		init.m_depth = loader.getDepth();
+		init.m_layerCount = 1;
 		faces = 1;
 		break;
 	default:
@@ -235,14 +238,15 @@ Error TextureResource::load(const ResourceFilename& filename)
 	// repeat
 	init.m_sampling.m_repeat = true;
 
-	// anisotropyLevel
+	// Anisotropy
 	init.m_sampling.m_anisotropyLevel = getManager().getTextureAnisotropy();
 
 	// Create the texture
 	m_tex = getManager().getGrManager().newInstance<Texture>(init);
 
 	// Upload the data asynchronously
-	task->m_depth = depth;
+	task->m_depth = init.m_depth;
+	task->m_layers = init.m_layerCount;
 	task->m_faces = faces;
 	task->m_gr = &getManager().getGrManager();
 	task->m_tex = m_tex;
@@ -251,6 +255,7 @@ Error TextureResource::load(const ResourceFilename& filename)
 
 	// Done
 	m_size = UVec3(init.m_width, init.m_height, init.m_depth);
+	m_layerCount = init.m_layerCount;
 	return ErrorCode::NONE;
 }
 

+ 2 - 2
src/ui/UiInterfaceImpl.cpp

@@ -224,10 +224,10 @@ Error UiInterfaceImpl::createR8Image(
 	void* loadData = m_gr->allocateFrameTransientMemory(
 		data.getSize(), BufferUsage::TRANSFER, token);
 	memcpy(loadData, &data[0], data.getSize());
-	cmdb->uploadTextureSurface(tex, TextureSurfaceInfo(0, 0, 0), token);
+	cmdb->uploadTextureSurface(tex, TextureSurfaceInfo(0, 0, 0, 0), token);
 
 	// Gen mips
-	cmdb->generateMipmaps(tex, 0, 0);
+	cmdb->generateMipmaps(tex, 0, 0, 0);
 	cmdb->flush();
 
 	// Create the UiImage