Prechádzať zdrojové kódy

Vulkan: Rework the way of finding the image layout

Panagiotis Christopoulos Charitos 8 rokov pred
rodič
commit
0a2304b405

+ 5 - 0
sandbox/Main.cpp

@@ -191,6 +191,11 @@ Error MyApp::userMainLoop(Bool& quit)
 	}
 #endif
 
+	if(in.getEvent(InputEvent::WINDOW_CLOSED))
+	{
+		quit = true;
+	}
+
 	if(m_profile && getGlobalTimestamp() == 500)
 	{
 		quit = true;

+ 1 - 4
src/anki/core/App.cpp

@@ -28,8 +28,6 @@
 #include <android_native_app_glue.h>
 #endif
 
-// Sybsystems
-
 namespace anki
 {
 
@@ -386,8 +384,7 @@ Error App::mainLoop()
 
 		ANKI_CHECK(m_renderer->render(*m_scene));
 
-		// Pause and sync async loader. That will force all tasks before the
-		// pause to finish in this frame.
+		// Pause and sync async loader. That will force all tasks before the pause to finish in this frame.
 		m_resources->getAsyncLoader().pause();
 
 		m_gr->swapBuffers();

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

@@ -362,8 +362,16 @@ public:
 	/// The command buffer will have to know the current usage of a texture. That can be known if there was a barrier
 	/// but if it wasn't use this method.
 	/// @param tex The texture.
+	/// @param surf The texture surface.
 	/// @param crntUsage The texture's current usage.
-	void informTextureCurrentUsage(TexturePtr tex, TextureUsageBit crntUsage);
+	void informTextureSurfaceCurrentUsage(TexturePtr tex, const TextureSurfaceInfo& surf, TextureUsageBit crntUsage);
+
+	/// The command buffer will have to know the current usage of a texture. That can be known if there was a barrier
+	/// but if it wasn't use this method.
+	/// @param tex The texture.
+	/// @param vol The texture volume.
+	/// @param crntUsage The texture's current usage.
+	void informTextureVolumeCurrentUsage(TexturePtr tex, const TextureVolumeInfo& vol, TextureUsageBit crntUsage);
 	/// @}
 
 	/// @name Other

+ 8 - 1
src/anki/gr/gl/CommandBuffer.cpp

@@ -1489,7 +1489,14 @@ void CommandBuffer::writeOcclusionQueryResultToBuffer(OcclusionQueryPtr query, P
 	m_impl->pushBackNewCommand<WriteOcclResultToBuff>(query, offset, buff);
 }
 
-void CommandBuffer::informTextureCurrentUsage(TexturePtr tex, TextureUsageBit crntUsage)
+void CommandBuffer::informTextureSurfaceCurrentUsage(
+	TexturePtr tex, const TextureSurfaceInfo& surf, TextureUsageBit crntUsage)
+{
+	// Nothing for GL
+}
+
+void CommandBuffer::informTextureVolumeCurrentUsage(
+	TexturePtr tex, const TextureVolumeInfo& vol, TextureUsageBit crntUsage)
 {
 	// Nothing for GL
 }

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

@@ -318,9 +318,16 @@ void CommandBuffer::setBufferBarrier(
 	m_impl->setBufferBarrier(buff, before, after, offset, size);
 }
 
-void CommandBuffer::informTextureCurrentUsage(TexturePtr tex, TextureUsageBit crntUsage)
+void CommandBuffer::informTextureSurfaceCurrentUsage(
+	TexturePtr tex, const TextureSurfaceInfo& surf, TextureUsageBit crntUsage)
 {
-	m_impl->informTextureCurrentUsage(tex, crntUsage);
+	m_impl->informTextureSurfaceCurrentUsage(tex, surf, crntUsage);
+}
+
+void CommandBuffer::informTextureVolumeCurrentUsage(
+	TexturePtr tex, const TextureVolumeInfo& vol, TextureUsageBit crntUsage)
+{
+	m_impl->informTextureVolumeCurrentUsage(tex, vol, crntUsage);
 }
 
 void CommandBuffer::resetOcclusionQuery(OcclusionQueryPtr query)

+ 51 - 243
src/anki/gr/vulkan/CommandBufferImpl.cpp

@@ -49,21 +49,12 @@ CommandBufferImpl::~CommandBufferImpl()
 	m_buffBarriers.destroy(m_alloc);
 	m_queryResetAtoms.destroy(m_alloc);
 	m_writeQueryAtoms.destroy(m_alloc);
+
+	m_texUsageTracker.destroy(m_alloc);
 }
 
-Error CommandBufferImpl::init(const CommandBufferInitInfo& init)
+void CommandBufferImpl::beginRecording()
 {
-	auto& pool = getGrManagerImpl().getAllocator().getMemoryPool();
-	m_alloc = StackAllocator<U8>(
-		pool.getAllocationCallback(), pool.getAllocationCallbackUserData(), init.m_hints.m_chunkSize, 1.0, 0, false);
-
-	m_flags = init.m_flags;
-	m_tid = Thread::getCurrentThreadId();
-
-	m_handle = getGrManagerImpl().newCommandBuffer(m_tid, m_flags);
-	ANKI_ASSERT(m_handle);
-
-	// Begin recording
 	VkCommandBufferInheritanceInfo inheritance = {};
 	inheritance.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
 
@@ -74,25 +65,57 @@ Error CommandBufferImpl::init(const CommandBufferInitInfo& init)
 
 	if(!!(m_flags & CommandBufferFlag::SECOND_LEVEL))
 	{
-		const FramebufferImpl& impl = *init.m_framebuffer->m_impl;
+		FramebufferImpl& impl = *m_activeFb->m_impl;
 
-		// TODO inheritance.renderPass = impl.getRenderPassHandle();
+		// Calc the layouts
+		Array<VkImageLayout, MAX_COLOR_ATTACHMENTS> colAttLayouts;
+		for(U i = 0; i < impl.getColorAttachmentCount(); ++i)
+		{
+			colAttLayouts[i] = m_texUsageTracker.findLayout(*impl.getColorAttachment(i), impl.getAttachedSurfaces()[i]);
+		}
+
+		VkImageLayout dsAttLayout = VK_IMAGE_LAYOUT_MAX_ENUM;
+		if(impl.hasDepthStencil())
+		{
+			dsAttLayout = m_texUsageTracker.findLayout(
+				*impl.getDepthStencilAttachment(), impl.getAttachedSurfaces()[MAX_COLOR_ATTACHMENTS]);
+		}
+
+		inheritance.renderPass = impl.getRenderPassHandle(colAttLayouts, dsAttLayout);
 		inheritance.subpass = 0;
 
-		// TODO
-		/*if(!impl.isDefaultFramebuffer())
+		if(!impl.isDefaultFramebuffer())
 		{
 			inheritance.framebuffer = impl.getFramebufferHandle(0);
 		}
 		else
 		{
 			inheritance.framebuffer = impl.getFramebufferHandle(getGrManagerImpl().getCurrentBackbufferIndex());
-		}*/
+		}
 
 		begin.flags |= VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
 	}
 
 	vkBeginCommandBuffer(m_handle, &begin);
+}
+
+Error CommandBufferImpl::init(const CommandBufferInitInfo& init)
+{
+	auto& pool = getGrManagerImpl().getAllocator().getMemoryPool();
+	m_alloc = StackAllocator<U8>(
+		pool.getAllocationCallback(), pool.getAllocationCallbackUserData(), init.m_hints.m_chunkSize, 1.0, 0, false);
+
+	m_flags = init.m_flags;
+	m_tid = Thread::getCurrentThreadId();
+
+	m_handle = getGrManagerImpl().newCommandBuffer(m_tid, m_flags);
+	ANKI_ASSERT(m_handle);
+
+	if(!!(m_flags & CommandBufferFlag::SECOND_LEVEL))
+	{
+		m_activeFb = init.m_framebuffer;
+		m_state.beginRenderPass(m_activeFb);
+	}
 
 	return ErrorCode::NONE;
 }
@@ -128,20 +151,21 @@ void CommandBufferImpl::beginRenderPassInternal()
 		bi.framebuffer = impl.getFramebufferHandle(0);
 		impl.getAttachmentsSize(bi.renderArea.extent.width, bi.renderArea.extent.height);
 
-		// Calc the usage
-		Array<TextureUsageBit, MAX_COLOR_ATTACHMENTS> colAttUsages;
+		// Calc the layouts
+		Array<VkImageLayout, MAX_COLOR_ATTACHMENTS> colAttLayouts;
 		for(U i = 0; i < impl.getColorAttachmentCount(); ++i)
 		{
-			colAttUsages[i] = m_texUsageTracker.findUsage(*impl.getColorAttachment(i));
+			colAttLayouts[i] = m_texUsageTracker.findLayout(*impl.getColorAttachment(i), impl.getAttachedSurfaces()[i]);
 		}
 
-		TextureUsageBit dsAttUsage = TextureUsageBit::NONE;
+		VkImageLayout dsAttLayout = VK_IMAGE_LAYOUT_MAX_ENUM;
 		if(impl.hasDepthStencil())
 		{
-			dsAttUsage = m_texUsageTracker.findUsage(*impl.getDepthStencilAttachment());
+			dsAttLayout = m_texUsageTracker.findLayout(
+				*impl.getDepthStencilAttachment(), impl.getAttachedSurfaces()[MAX_COLOR_ATTACHMENTS]);
 		}
 
-		bi.renderPass = impl.getRenderPassHandle(colAttUsages, dsAttUsage);
+		bi.renderPass = impl.getRenderPassHandle(colAttLayouts, dsAttLayout);
 	}
 	else
 	{
@@ -149,8 +173,8 @@ void CommandBufferImpl::beginRenderPassInternal()
 		m_renderedToDefaultFb = true;
 
 		bi.framebuffer = impl.getFramebufferHandle(getGrManagerImpl().getCurrentBackbufferIndex());
-		Array<TextureUsageBit, MAX_COLOR_ATTACHMENTS> dummy;
-		bi.renderPass = impl.getRenderPassHandle(dummy, TextureUsageBit::NONE);
+		Array<VkImageLayout, MAX_COLOR_ATTACHMENTS> dummy;
+		bi.renderPass = impl.getRenderPassHandle(dummy, VK_IMAGE_LAYOUT_MAX_ENUM);
 
 		bi.renderArea.extent.width = getGrManagerImpl().getDefaultSurfaceWidth();
 		bi.renderArea.extent.height = getGrManagerImpl().getDefaultSurfaceHeight();
@@ -195,6 +219,7 @@ void CommandBufferImpl::endRenderPass()
 	}
 
 	m_activeFb.reset(nullptr);
+	m_state.endRenderPass();
 }
 
 void CommandBufferImpl::endRecording()
@@ -304,222 +329,6 @@ void CommandBufferImpl::generateMipmaps2d(TexturePtr tex, U face, U layer)
 	m_texList.pushBack(m_alloc, tex);
 }
 
-#if 0
-void CommandBufferImpl::uploadTextureSurface(
-	TexturePtr tex, const TextureSurfaceInfo& surf, const TransientMemoryToken& token)
-{
-	commandCommon();
-
-	TextureImpl& impl = *tex->m_impl;
-	impl.checkSurface(surf);
-	ANKI_ASSERT(impl.usageValid(TextureUsageBit::TRANSFER_DESTINATION));
-
-	if(!impl.m_workarounds)
-	{
-		U width = impl.m_width >> surf.m_level;
-		U height = impl.m_height >> surf.m_level;
-		ANKI_ASSERT(token.m_range == computeSurfaceSize(width, height, impl.m_format));
-
-		// Copy
-		VkBufferImageCopy region;
-		region.imageSubresource.aspectMask = impl.m_aspect;
-		region.imageSubresource.baseArrayLayer = impl.computeVkArrayLayer(surf);
-		region.imageSubresource.layerCount = 1;
-		region.imageSubresource.mipLevel = surf.m_level;
-		region.imageOffset = {0, 0, I32(surf.m_depth)};
-		region.imageExtent.width = width;
-		region.imageExtent.height = height;
-		region.imageExtent.depth = 1;
-		region.bufferOffset = token.m_offset;
-		region.bufferImageHeight = 0;
-		region.bufferRowLength = 0;
-
-		ANKI_CMD(vkCmdCopyBufferToImage(m_handle,
-					 getGrManagerImpl().getTransientMemoryManager().getBufferHandle(token.m_usage),
-					 impl.m_imageHandle,
-					 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
-					 1,
-					 &region),
-			ANY_OTHER_COMMAND);
-	}
-	else if(!!(impl.m_workarounds & TextureImplWorkaround::R8G8B8_TO_R8G8B8A8))
-	{
-		// Find the offset to the RGBA staging buff
-		U width = impl.m_width >> surf.m_level;
-		U height = impl.m_height >> surf.m_level;
-		PtrSize dstOffset =
-			computeSurfaceSize(width, height, PixelFormat(ComponentFormat::R8G8B8, TransformFormat::UNORM));
-		alignRoundUp(16, dstOffset);
-		ANKI_ASSERT(token.m_range
-			== dstOffset
-				+ computeSurfaceSize(width, height, PixelFormat(ComponentFormat::R8G8B8A8, TransformFormat::UNORM)));
-		dstOffset += token.m_offset;
-
-		// Create the copy regions
-		DynamicArrayAuto<VkBufferCopy> copies(m_alloc);
-		copies.create(width * height);
-		U count = 0;
-		for(U x = 0; x < width; ++x)
-		{
-			for(U y = 0; y < height; ++y)
-			{
-				VkBufferCopy& c = copies[count++];
-				c.srcOffset = (y * width + x) * 3 + token.m_offset;
-				c.dstOffset = (y * width + x) * 4 + dstOffset;
-				c.size = 3;
-			}
-		}
-
-		// Copy buffer to buffer
-		VkBuffer buffHandle = getGrManagerImpl().getTransientMemoryManager().getBufferHandle(token.m_usage);
-		ANKI_CMD(vkCmdCopyBuffer(m_handle, buffHandle, buffHandle, copies.getSize(), &copies[0]), ANY_OTHER_COMMAND);
-
-		// Set barrier
-		setBufferBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
-			VK_ACCESS_TRANSFER_WRITE_BIT,
-			VK_PIPELINE_STAGE_TRANSFER_BIT,
-			VK_ACCESS_TRANSFER_READ_BIT,
-			dstOffset,
-			token.m_range - (dstOffset - token.m_offset),
-			buffHandle);
-
-		// Do the copy to the image
-		VkBufferImageCopy region;
-		region.imageSubresource.aspectMask = impl.m_aspect;
-		region.imageSubresource.baseArrayLayer = impl.computeVkArrayLayer(surf);
-		region.imageSubresource.layerCount = 1;
-		region.imageSubresource.mipLevel = surf.m_level;
-		region.imageOffset = {0, 0, I32(surf.m_depth)};
-		region.imageExtent.width = width;
-		region.imageExtent.height = height;
-		region.imageExtent.depth = 1;
-		region.bufferOffset = dstOffset;
-		region.bufferImageHeight = 0;
-		region.bufferRowLength = 0;
-
-		ANKI_CMD(vkCmdCopyBufferToImage(
-					 m_handle, buffHandle, impl.m_imageHandle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region),
-			ANY_OTHER_COMMAND);
-	}
-	else
-	{
-		ANKI_ASSERT(0);
-	}
-
-	m_texList.pushBack(m_alloc, tex);
-}
-
-void CommandBufferImpl::uploadTextureVolume(
-	TexturePtr tex, const TextureVolumeInfo& vol, const TransientMemoryToken& token)
-{
-	commandCommon();
-
-	TextureImpl& impl = *tex->m_impl;
-	impl.checkVolume(vol);
-	ANKI_ASSERT(impl.usageValid(TextureUsageBit::TRANSFER_DESTINATION));
-
-	if(!impl.m_workarounds)
-	{
-		U width = impl.m_width >> vol.m_level;
-		U height = impl.m_height >> vol.m_level;
-		U depth = impl.m_depth >> vol.m_level;
-		(void)depth;
-		ANKI_ASSERT(token.m_range == computeVolumeSize(width, height, depth, impl.m_format));
-
-		// Copy
-		VkBufferImageCopy region;
-		region.imageSubresource.aspectMask = impl.m_aspect;
-		region.imageSubresource.baseArrayLayer = impl.computeVkArrayLayer(vol);
-		region.imageSubresource.layerCount = 1;
-		region.imageSubresource.mipLevel = vol.m_level;
-		region.imageOffset = {0, 0, 0};
-		region.imageExtent.width = width;
-		region.imageExtent.height = height;
-		region.imageExtent.depth = impl.m_depth;
-		region.bufferOffset = token.m_offset;
-		region.bufferImageHeight = 0;
-		region.bufferRowLength = 0;
-
-		ANKI_CMD(vkCmdCopyBufferToImage(m_handle,
-					 getGrManagerImpl().getTransientMemoryManager().getBufferHandle(token.m_usage),
-					 impl.m_imageHandle,
-					 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
-					 1,
-					 &region),
-			ANY_OTHER_COMMAND);
-	}
-	else if(!!(impl.m_workarounds & TextureImplWorkaround::R8G8B8_TO_R8G8B8A8))
-	{
-		// Find the offset to the RGBA staging buff
-		U width = impl.m_width >> vol.m_level;
-		U height = impl.m_height >> vol.m_level;
-		U depth = impl.m_depth >> vol.m_level;
-		PtrSize dstOffset =
-			computeVolumeSize(width, height, depth, PixelFormat(ComponentFormat::R8G8B8, TransformFormat::UNORM));
-		alignRoundUp(16, dstOffset);
-		ANKI_ASSERT(token.m_range
-			== dstOffset + computeVolumeSize(
-							   width, height, depth, PixelFormat(ComponentFormat::R8G8B8A8, TransformFormat::UNORM)));
-		dstOffset += token.m_offset;
-
-		// Create the copy regions
-		DynamicArrayAuto<VkBufferCopy> copies(m_alloc);
-		copies.create(width * height * depth);
-		U count = 0;
-		for(U x = 0; x < width; ++x)
-		{
-			for(U y = 0; y < height; ++y)
-			{
-				for(U d = 0; d < depth; ++d)
-				{
-					VkBufferCopy& c = copies[count++];
-					c.srcOffset = (d * height * width + y * width + x) * 3 + token.m_offset;
-					c.dstOffset = (d * height * width + y * width + x) * 4 + dstOffset;
-					c.size = 3;
-				}
-			}
-		}
-
-		// Copy buffer to buffer
-		VkBuffer buffHandle = getGrManagerImpl().getTransientMemoryManager().getBufferHandle(token.m_usage);
-		ANKI_CMD(vkCmdCopyBuffer(m_handle, buffHandle, buffHandle, copies.getSize(), &copies[0]), ANY_OTHER_COMMAND);
-
-		// Set barrier
-		setBufferBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
-			VK_ACCESS_TRANSFER_WRITE_BIT,
-			VK_PIPELINE_STAGE_TRANSFER_BIT,
-			VK_ACCESS_TRANSFER_READ_BIT,
-			dstOffset,
-			token.m_range - (dstOffset - token.m_offset),
-			buffHandle);
-
-		// Do the copy to the image
-		VkBufferImageCopy region;
-		region.imageSubresource.aspectMask = impl.m_aspect;
-		region.imageSubresource.baseArrayLayer = impl.computeVkArrayLayer(vol);
-		region.imageSubresource.layerCount = 1;
-		region.imageSubresource.mipLevel = vol.m_level;
-		region.imageOffset = {0, 0, 0};
-		region.imageExtent.width = width;
-		region.imageExtent.height = height;
-		region.imageExtent.depth = depth;
-		region.bufferOffset = dstOffset;
-		region.bufferImageHeight = 0;
-		region.bufferRowLength = 0;
-
-		ANKI_CMD(vkCmdCopyBufferToImage(
-					 m_handle, buffHandle, impl.m_imageHandle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region),
-			ANY_OTHER_COMMAND);
-	}
-	else
-	{
-		ANKI_ASSERT(0);
-	}
-
-	m_texList.pushBack(m_alloc, tex);
-}
-#endif
-
 void CommandBufferImpl::flushBarriers()
 {
 	if(m_imgBarrierCount == 0 && m_buffBarrierCount == 0)
@@ -787,8 +596,7 @@ void CommandBufferImpl::copyBufferToTextureSurface(
 	TextureImpl& impl = *tex->m_impl;
 	impl.checkSurface(surf);
 	ANKI_ASSERT(impl.usageValid(TextureUsageBit::TRANSFER_DESTINATION));
-	TextureUsageBit usage = m_texUsageTracker.findUsage(*tex);
-	const VkImageLayout layout = impl.computeLayout(usage, surf.m_level);
+	const VkImageLayout layout = m_texUsageTracker.findLayout(*tex, surf);
 
 	if(!impl.m_workarounds)
 	{

+ 46 - 23
src/anki/gr/vulkan/CommandBufferImpl.h

@@ -194,8 +194,7 @@ public:
 	{
 		const U realBinding = binding;
 		Texture& tex = *tex_;
-		TextureUsageBit usage = m_texUsageTracker.findUsage(tex);
-		VkImageLayout lay = tex.m_impl->computeLayout(usage, 0);
+		VkImageLayout lay = m_texUsageTracker.findLayout(tex);
 		m_dsetState[set].bindTexture(realBinding, &tex, aspect, lay);
 		m_texList.pushBack(m_alloc, tex_);
 	}
@@ -204,8 +203,7 @@ public:
 	{
 		const U realBinding = binding;
 		Texture& tex = *tex_;
-		TextureUsageBit usage = m_texUsageTracker.findUsage(tex);
-		VkImageLayout lay = tex.m_impl->computeLayout(usage, 0);
+		VkImageLayout lay = m_texUsageTracker.findLayout(tex);
 		m_dsetState[set].bindTextureAndSampler(realBinding, &tex, sampler.get(), aspect, lay);
 		m_texList.pushBack(m_alloc, tex_);
 		m_samplerList.pushBack(m_alloc, sampler);
@@ -288,10 +286,14 @@ public:
 	void copyBufferToTextureSurface(
 		BufferPtr buff, PtrSize offset, PtrSize range, TexturePtr tex, const TextureSurfaceInfo& surf);
 
-	void informTextureCurrentUsage(TexturePtr& tex, TextureUsageBit crntUsage)
+	void informTextureSurfaceCurrentUsage(TexturePtr& tex, const TextureSurfaceInfo& surf, TextureUsageBit crntUsage)
 	{
-		ANKI_ASSERT(tex->m_impl->usageValid(crntUsage));
-		m_texUsageTracker.setUsage(*tex, crntUsage, m_alloc);
+		m_texUsageTracker.setUsage(*tex, surf, crntUsage, m_alloc);
+	}
+
+	void informTextureVolumeCurrentUsage(TexturePtr& tex, const TextureVolumeInfo& vol, TextureUsageBit crntUsage)
+	{
+		m_texUsageTracker.setUsage(*tex, vol, crntUsage, m_alloc);
 	}
 
 private:
@@ -302,6 +304,7 @@ private:
 	Bool8 m_renderedToDefaultFb = false;
 	Bool8 m_finalized = false;
 	Bool8 m_empty = true;
+	Bool m_beganRecording = false;
 	ThreadId m_tid = 0;
 
 	U m_rpCommandCount = 0; ///< Number of drawcalls or pushed cmdbs in rp.
@@ -322,12 +325,8 @@ private:
 	List<CommandBufferPtr> m_cmdbList;
 	List<ShaderProgramPtr> m_progs;
 	List<SamplerPtr> m_samplerList;
-/// @}
+	/// @}
 
-#if ANKI_EXTRA_CHECKS
-	// Debug stuff
-	Bool8 m_insideRenderPass = false;
-#endif
 	VkSubpassContents m_subpassContents = VK_SUBPASS_CONTENTS_MAX_ENUM;
 
 	CommandBufferCommandType m_lastCmdType = CommandBufferCommandType::ANY_OTHER_COMMAND;
@@ -383,45 +382,67 @@ private:
 	class TextureUsageTracker
 	{
 	public:
-		ANKI_USE_RESULT TextureUsageBit findUsage(const Texture& tex) const
+		template<typename TextureInfo>
+		ANKI_USE_RESULT VkImageLayout findLayout(const Texture& tex, const TextureInfo& surf) const
 		{
 			auto it = m_map.find(tex.getUuid());
-			if(it != m_map.getEnd())
+			ANKI_ASSERT((it != m_map.getEnd() || tex.m_impl->m_usageWhenEncountered != TextureUsageBit::NONE)
+				&& "Cannot find the layout of the image");
+			if(it == m_map.getEnd())
+			{
+				return tex.m_impl->computeLayout(tex.m_impl->m_usageWhenEncountered, surf.m_level);
+			}
+			else
 			{
-				return (*it);
+				return tex.m_impl->getLayoutFromState(surf, *it);
 			}
-			else if(tex.m_impl->m_usageWhenEncountered != TextureUsageBit::NONE)
+		}
+
+		ANKI_USE_RESULT VkImageLayout findLayout(const Texture& tex) const
+		{
+			auto it = m_map.find(tex.getUuid());
+			ANKI_ASSERT((it != m_map.getEnd() || tex.m_impl->m_usageWhenEncountered != TextureUsageBit::NONE)
+				&& "Cannot find the layout of the image");
+			if(it == m_map.getEnd())
 			{
-				return tex.m_impl->m_usageWhenEncountered;
+				return tex.m_impl->computeLayout(tex.m_impl->m_usageWhenEncountered, 0);
 			}
 			else
 			{
-				ANKI_ASSERT(!"Cannot find the layout of the image");
-				return TextureUsageBit::NONE;
+				return tex.m_impl->getLayoutFromState(*it);
 			}
 		}
 
-		void setUsage(const Texture& tex, TextureUsageBit usage, StackAllocator<U8>& alloc)
+		template<typename TextureInfo>
+		void setUsage(const Texture& tex, const TextureInfo& surf, TextureUsageBit usage, StackAllocator<U8>& alloc)
 		{
 			ANKI_ASSERT(usage != TextureUsageBit::NONE);
+
 			auto it = m_map.find(tex.getUuid());
 			if(it != m_map.getEnd())
 			{
-				(*it) = usage;
+				tex.m_impl->updateUsageState(surf, usage, *it, alloc);
 			}
 			else
 			{
-				m_map.pushBack(alloc, tex.getUuid(), usage);
+				TextureUsageState state;
+				tex.m_impl->updateUsageState(surf, usage, state, alloc);
+				m_map.emplaceBack(alloc, tex.getUuid(), std::move(state));
 			}
 		}
 
 		void destroy(StackAllocator<U8>& alloc)
 		{
+			for(auto& it : m_map)
+			{
+				it.destroy(alloc);
+			}
+
 			m_map.destroy(alloc);
 		}
 
 	private:
-		HashMap<U64, TextureUsageBit> m_map;
+		HashMap<U64, TextureUsageState> m_map;
 	} m_texUsageTracker;
 
 	/// Some common operations per command.
@@ -462,6 +483,8 @@ private:
 		VkImageLayout newLayout,
 		VkImage img,
 		const VkImageSubresourceRange& range);
+
+	void beginRecording();
 };
 /// @}
 

+ 10 - 0
src/anki/gr/vulkan/CommandBufferImpl.inl.h

@@ -163,6 +163,8 @@ inline void CommandBufferImpl::setTextureSurfaceBarrier(
 	VkImageSubresourceRange range;
 	impl.computeSubResourceRange(surf, impl.m_akAspect, range);
 	setTextureBarrierRange(tex, prevUsage, nextUsage, range);
+
+	m_texUsageTracker.setUsage(*tex, surf, nextUsage, m_alloc);
 }
 
 inline void CommandBufferImpl::setTextureVolumeBarrier(
@@ -180,6 +182,8 @@ inline void CommandBufferImpl::setTextureVolumeBarrier(
 	VkImageSubresourceRange range;
 	impl.computeSubResourceRange(vol, impl.m_akAspect, range);
 	setTextureBarrierRange(tex, prevUsage, nextUsage, range);
+
+	m_texUsageTracker.setUsage(*tex, vol, nextUsage, m_alloc);
 }
 
 inline void CommandBufferImpl::setBufferBarrier(VkPipelineStageFlags srcStage,
@@ -511,6 +515,12 @@ inline void CommandBufferImpl::commandCommon()
 	ANKI_ASSERT(!m_finalized);
 	ANKI_ASSERT(m_handle);
 	m_empty = false;
+
+	if(ANKI_UNLIKELY(!m_beganRecording))
+	{
+		beginRecording();
+		m_beganRecording = true;
+	}
 }
 
 inline void CommandBufferImpl::flushBatches(CommandBufferCommandType type)

+ 1 - 1
src/anki/gr/vulkan/Common.h

@@ -158,7 +158,7 @@ ANKI_USE_RESULT inline VkDescriptorType convertDescriptorType(DescriptorType ak)
 	switch(ak)
 	{
 	case DescriptorType::TEXTURE:
-		out = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
+		out = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
 		break;
 	case DescriptorType::UNIFORM_BUFFER:
 		out = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;

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

@@ -381,7 +381,7 @@ Error DSLayoutCacheEntry::init(const DescriptorBinding* bindings, U bindingCount
 
 			switch(m_poolSizesCreateInf[poolSizeCount].type)
 			{
-			case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+			case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
 				m_poolSizesCreateInf[poolSizeCount].descriptorCount = MAX_TEXTURE_BINDINGS;
 				break;
 			case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:

+ 22 - 16
src/anki/gr/vulkan/FramebufferImpl.cpp

@@ -45,7 +45,7 @@ Error FramebufferImpl::init(const FramebufferInitInfo& init)
 	// Create the FBs
 	ANKI_CHECK(initFbs(init));
 
-	// Set clear values
+	// Set clear values and some other stuff
 	for(U i = 0; i < m_colorAttCount; ++i)
 	{
 		if(init.m_colorAttachments[i].m_loadOperation == AttachmentLoadOperation::CLEAR)
@@ -60,6 +60,8 @@ Error FramebufferImpl::init(const FramebufferInitInfo& init)
 		{
 			m_clearVals[i] = {};
 		}
+
+		m_attachedSurfaces[i] = init.m_colorAttachments[i].m_surface;
 	}
 
 	if(hasDepthStencil())
@@ -77,6 +79,8 @@ Error FramebufferImpl::init(const FramebufferInitInfo& init)
 		{
 			m_clearVals[m_colorAttCount] = {};
 		}
+
+		m_attachedSurfaces[MAX_COLOR_ATTACHMENTS] = init.m_depthStencilAttachment.m_surface;
 	}
 
 	return ErrorCode::NONE;
@@ -160,7 +164,7 @@ Error FramebufferImpl::initFbs(const FramebufferInitInfo& init)
 				m_height = tex.m_height >> att.m_surface.m_level;
 			}
 
-			m_refs[init.m_colorAttachmentCount] = att.m_texture;
+			m_refs[MAX_COLOR_ATTACHMENTS] = att.m_texture;
 		}
 
 		ci.width = m_width;
@@ -203,7 +207,7 @@ void FramebufferImpl::initRpassCreateInfo(const FramebufferInitInfo& init)
 		setupAttachmentDescriptor(att, m_attachmentDescriptions[i]);
 
 		m_references[i].attachment = i;
-		m_references[i].layout = (att.m_texture) ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+		m_references[i].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
 	}
 
 	const Bool hasDepthStencil = init.m_depthStencilAttachment.m_texture == true;
@@ -214,7 +218,7 @@ void FramebufferImpl::initRpassCreateInfo(const FramebufferInitInfo& init)
 		setupAttachmentDescriptor(init.m_depthStencilAttachment, m_attachmentDescriptions[init.m_colorAttachmentCount]);
 
 		dsReference.attachment = init.m_colorAttachmentCount;
-		dsReference.layout = VK_IMAGE_LAYOUT_UNDEFINED;
+		dsReference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
 	}
 
 	// Setup the render pass
@@ -233,31 +237,31 @@ void FramebufferImpl::initRpassCreateInfo(const FramebufferInitInfo& init)
 }
 
 VkRenderPass FramebufferImpl::getRenderPassHandle(
-	const Array<TextureUsageBit, MAX_COLOR_ATTACHMENTS>& colorUsages, TextureUsageBit dsUsage)
+	const Array<VkImageLayout, MAX_COLOR_ATTACHMENTS>& colorLayouts, VkImageLayout dsLayout)
 {
 	VkRenderPass out;
 
 	if(!m_defaultFb)
 	{
 		// Create hash
-		Array<TextureUsageBit, MAX_COLOR_ATTACHMENTS + 1> allUsages;
-		U allUsageCount = 0;
+		Array<VkImageLayout, MAX_COLOR_ATTACHMENTS + 1> allLayouts;
+		U allLayoutCount = 0;
 		for(U i = 0; i < MAX_COLOR_ATTACHMENTS; ++i)
 		{
 			if(m_colorAttachmentMask.get(i))
 			{
-				ANKI_ASSERT(!!(colorUsages[i]));
-				allUsages[allUsageCount++] = colorUsages[i];
+				ANKI_ASSERT(colorLayouts[i] != VK_IMAGE_LAYOUT_UNDEFINED);
+				allLayouts[allLayoutCount++] = colorLayouts[i];
 			}
 		}
 
 		if(m_depthAttachment || m_stencilAttachment)
 		{
-			ANKI_ASSERT(!!(dsUsage));
-			allUsages[allUsageCount++] = dsUsage;
+			ANKI_ASSERT(dsLayout != VK_IMAGE_LAYOUT_UNDEFINED);
+			allLayouts[allLayoutCount++] = dsLayout;
 		}
 
-		U64 hash = computeHash(&allUsages[0], allUsageCount * sizeof(allUsages[0]));
+		U64 hash = computeHash(&allLayouts[0], allLayoutCount * sizeof(allLayouts[0]));
 
 		// Get or create
 		LockGuard<Mutex> lock(m_rpassesMtx);
@@ -277,13 +281,14 @@ VkRenderPass FramebufferImpl::getRenderPassHandle(
 
 			// Fix pointers
 			subpassDescr.pColorAttachments = &references[0];
-			subpassDescr.pDepthStencilAttachment = &references[MAX_COLOR_ATTACHMENTS];
+			subpassDescr.pDepthStencilAttachment = &references[subpassDescr.colorAttachmentCount];
 			ci.pAttachments = &attachmentDescriptions[0];
 			ci.pSubpasses = &subpassDescr;
 
 			for(U i = 0; i < subpassDescr.colorAttachmentCount; ++i)
 			{
-				const VkImageLayout lay = m_refs[i]->m_impl->computeLayout(colorUsages[i], m_attachedMipLevels[i]);
+				const VkImageLayout lay = colorLayouts[i];
+				ANKI_ASSERT(lay != VK_IMAGE_LAYOUT_UNDEFINED);
 
 				attachmentDescriptions[i].initialLayout = lay;
 				attachmentDescriptions[i].finalLayout = lay;
@@ -293,8 +298,9 @@ VkRenderPass FramebufferImpl::getRenderPassHandle(
 
 			if(m_refs[MAX_COLOR_ATTACHMENTS])
 			{
-				const U i = MAX_COLOR_ATTACHMENTS;
-				const VkImageLayout lay = m_refs[i]->m_impl->computeLayout(dsUsage, m_attachedMipLevels[i]);
+				const U i = subpassDescr.colorAttachmentCount;
+				const VkImageLayout lay = dsLayout;
+				ANKI_ASSERT(lay != VK_IMAGE_LAYOUT_UNDEFINED);
 
 				attachmentDescriptions[i].initialLayout = lay;
 				attachmentDescriptions[i].finalLayout = lay;

+ 7 - 2
src/anki/gr/vulkan/FramebufferImpl.h

@@ -40,7 +40,7 @@ public:
 
 	/// Use it for binding.
 	VkRenderPass getRenderPassHandle(
-		const Array<TextureUsageBit, MAX_COLOR_ATTACHMENTS>& colorUsages, TextureUsageBit dsUsage);
+		const Array<VkImageLayout, MAX_COLOR_ATTACHMENTS>& colorLayouts, VkImageLayout dsLayout);
 
 	VkFramebuffer getFramebufferHandle(U frame) const
 	{
@@ -98,6 +98,11 @@ public:
 		height = m_height;
 	}
 
+	const Array<TextureSurfaceInfo, MAX_COLOR_ATTACHMENTS + 1>& getAttachedSurfaces() const
+	{
+		return m_attachedSurfaces;
+	}
+
 private:
 	U32 m_width = 0;
 	U32 m_height = 0;
@@ -112,7 +117,7 @@ private:
 	Array<VkClearValue, MAX_COLOR_ATTACHMENTS + 1> m_clearVals;
 
 	Array<TexturePtr, MAX_COLOR_ATTACHMENTS + 1> m_refs; ///< @note The pos of every attachment is fixed.
-	Array<U32, MAX_COLOR_ATTACHMENTS + 1> m_attachedMipLevels = {};
+	Array<TextureSurfaceInfo, MAX_COLOR_ATTACHMENTS + 1> m_attachedSurfaces = {};
 
 	// RenderPass create info
 	VkRenderPassCreateInfo m_rpassCi = {};

+ 24 - 20
src/anki/gr/vulkan/TextureImpl.cpp

@@ -259,22 +259,32 @@ Error TextureImpl::initImage(const TextureInitInfo& init_)
 	case TextureType::_2D:
 		ci.extent.depth = 1;
 		ci.arrayLayers = 1;
+
+		m_surfaceOrVolumeCount = m_mipCount;
 		break;
 	case TextureType::_2D_ARRAY:
 		ci.extent.depth = 1;
 		ci.arrayLayers = init.m_layerCount;
+
+		m_surfaceOrVolumeCount = m_mipCount * m_layerCount;
 		break;
 	case TextureType::CUBE:
 		ci.extent.depth = 1;
 		ci.arrayLayers = 6;
+
+		m_surfaceOrVolumeCount = m_mipCount * 6;
 		break;
 	case TextureType::CUBE_ARRAY:
 		ci.extent.depth = 1;
 		ci.arrayLayers = 6 * init.m_layerCount;
+
+		m_surfaceOrVolumeCount = m_mipCount * 6 * m_layerCount;
 		break;
 	case TextureType::_3D:
 		ci.extent.depth = init.m_depth;
 		ci.arrayLayers = 1;
+
+		m_surfaceOrVolumeCount = m_mipCount;
 		break;
 	default:
 		ANKI_ASSERT(0);
@@ -553,19 +563,19 @@ VkImageLayout TextureImpl::computeLayout(TextureUsageBit usage, U level) const
 	{
 		out = VK_IMAGE_LAYOUT_UNDEFINED;
 	}
-	else if(!!(usage & TextureUsageBit::SAMPLED_ALL) && !(usage & ~TextureUsageBit::SAMPLED_ALL))
+	else if(!(usage & ~TextureUsageBit::SAMPLED_ALL))
 	{
+		// Only sampling
 		out = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
 	}
-	else if(!!(usage & TextureUsageBit::IMAGE_COMPUTE_READ_WRITE)
-		&& !(usage & ~TextureUsageBit::IMAGE_COMPUTE_READ_WRITE))
+	else if(!(usage & ~TextureUsageBit::IMAGE_COMPUTE_READ_WRITE))
 	{
+		// Only image load/store
 		out = VK_IMAGE_LAYOUT_GENERAL;
 	}
-	else if(usage == TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE
-		|| usage == TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ_WRITE
-		|| usage == TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ)
+	else if(!(usage & ~TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ_WRITE))
 	{
+		// Only FB access
 		if(m_depthStencil)
 		{
 			out = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
@@ -575,12 +585,18 @@ VkImageLayout TextureImpl::computeLayout(TextureUsageBit usage, U level) const
 			out = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
 		}
 	}
-	else if(m_depthStencil && !!(usage & TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ)
-		&& !!(usage & TextureUsageBit::SAMPLED_ALL_GRAPHICS)
+	else if(m_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
+		&& !(usage & ~(TextureUsageBit::SAMPLED_ALL_GRAPHICS | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ_WRITE)))
+	{
+		// Wild guess: One aspect is shader read and the other is read write
+		out = VK_IMAGE_LAYOUT_GENERAL;
+	}
 	else if(usage == TextureUsageBit::GENERATE_MIPMAPS)
 	{
 		if(!lastLevel)
@@ -616,18 +632,6 @@ VkImageView TextureImpl::getOrCreateSingleSurfaceView(const TextureSurfaceInfo&
 	return getOrCreateView(ci);
 }
 
-VkImageView TextureImpl::getOrCreateSingleLevelView(U level, DepthStencilAspectBit aspect)
-{
-	ANKI_ASSERT(level < m_mipCount);
-
-	VkImageViewCreateInfo ci = m_viewCreateInfoTemplate;
-	ci.subresourceRange.baseMipLevel = level;
-	ci.subresourceRange.levelCount = 1;
-	ci.subresourceRange.aspectMask = convertAspect(aspect);
-
-	return getOrCreateView(ci);
-}
-
 VkImageView TextureImpl::getOrCreateResourceGroupView(DepthStencilAspectBit aspect)
 {
 	VkImageViewCreateInfo ci = m_viewCreateInfoTemplate;

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

@@ -25,6 +25,17 @@ enum class TextureImplWorkaround : U8
 };
 ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(TextureImplWorkaround, inline)
 
+class TextureUsageState
+{
+public:
+	DynamicArray<VkImageLayout> m_subResources; ///< Volumes or surfaces.
+
+	void destroy(StackAllocator<U8>& alloc)
+	{
+		m_subResources.destroy(alloc);
+	}
+};
+
 /// Texture container.
 class TextureImpl : public DescriptorObject
 {
@@ -41,6 +52,7 @@ public:
 	TextureType m_type = TextureType::CUBE;
 	U8 m_mipCount = 0;
 	U32 m_layerCount = 0;
+	U32 m_surfaceOrVolumeCount = 0;
 	VkImageAspectFlags m_aspect = 0;
 	DepthStencilAspectBit m_akAspect = DepthStencilAspectBit::NONE;
 	TextureUsageBit m_usage = TextureUsageBit::NONE;
@@ -89,8 +101,6 @@ public:
 
 	VkImageView getOrCreateSingleSurfaceView(const TextureSurfaceInfo& surf, DepthStencilAspectBit aspect);
 
-	VkImageView getOrCreateSingleLevelView(U level, DepthStencilAspectBit aspect);
-
 	/// That view will be used in descriptor sets.
 	VkImageView getOrCreateResourceGroupView(DepthStencilAspectBit aspect);
 
@@ -108,6 +118,73 @@ public:
 
 	VkImageAspectFlags convertAspect(DepthStencilAspectBit ak) const;
 
+	void checkSubresourceRange(const VkImageSubresourceRange& range) const
+	{
+		ANKI_ASSERT(range.baseArrayLayer < m_layerCount);
+		ANKI_ASSERT(range.baseArrayLayer + range.layerCount <= m_layerCount);
+		ANKI_ASSERT(range.levelCount < m_mipCount);
+		ANKI_ASSERT(range.baseMipLevel + range.levelCount <= m_mipCount);
+	}
+
+	VkImageLayout getLayoutFromState(const TextureSurfaceInfo& surf, const TextureUsageState& state) const
+	{
+		checkSurface(surf);
+		const U surfIdx = computeSubresourceIdx(surf);
+		ANKI_ASSERT(state.m_subResources[surfIdx] != VK_IMAGE_LAYOUT_UNDEFINED);
+		return state.m_subResources[surfIdx];
+	}
+
+	VkImageLayout getLayoutFromState(const TextureVolumeInfo& vol, const TextureUsageState& state) const
+	{
+		checkVolume(vol);
+		ANKI_ASSERT(state.m_subResources[vol.m_level] != VK_IMAGE_LAYOUT_UNDEFINED);
+		return state.m_subResources[vol.m_level];
+	}
+
+	VkImageLayout getLayoutFromState(const TextureUsageState& state) const
+	{
+		for(VkImageLayout l : state.m_subResources)
+		{
+			ANKI_ASSERT(l == state.m_subResources[0] && "Not all image subresources are in the same layout");
+		}
+		ANKI_ASSERT(state.m_subResources[0] != VK_IMAGE_LAYOUT_UNDEFINED);
+		return state.m_subResources[0];
+	}
+
+	void updateUsageState(const TextureSurfaceInfo& surf,
+		TextureUsageBit usage,
+		TextureUsageState& state,
+		StackAllocator<U8>& alloc) const
+	{
+		checkSurface(surf);
+		if(ANKI_UNLIKELY(state.m_subResources.getSize() == 0))
+		{
+			state.m_subResources.create(alloc, m_surfaceOrVolumeCount);
+			memorySet(reinterpret_cast<int*>(&state.m_subResources[0]),
+				int(VK_IMAGE_LAYOUT_UNDEFINED),
+				m_surfaceOrVolumeCount);
+		}
+		auto lay = computeLayout(usage, surf.m_level);
+		ANKI_ASSERT(lay != VK_IMAGE_LAYOUT_UNDEFINED);
+		state.m_subResources[computeSubresourceIdx(surf)] = lay;
+	}
+
+	void updateUsageState(
+		const TextureVolumeInfo& vol, TextureUsageBit usage, TextureUsageState& state, StackAllocator<U8>& alloc) const
+	{
+		checkVolume(vol);
+		if(ANKI_UNLIKELY(state.m_subResources.getSize() == 0))
+		{
+			state.m_subResources.create(alloc, m_surfaceOrVolumeCount);
+			memorySet(reinterpret_cast<int*>(&state.m_subResources[0]),
+				int(VK_IMAGE_LAYOUT_UNDEFINED),
+				m_surfaceOrVolumeCount);
+		}
+		auto lay = computeLayout(usage, vol.m_level);
+		ANKI_ASSERT(lay != VK_IMAGE_LAYOUT_UNDEFINED);
+		state.m_subResources[vol.m_level] = lay;
+	}
+
 private:
 	class ViewHasher
 	{
@@ -140,6 +217,8 @@ private:
 	ANKI_USE_RESULT Error initImage(const TextureInitInfo& init);
 
 	VkImageView getOrCreateView(const VkImageViewCreateInfo& ci);
+
+	U computeSubresourceIdx(const TextureSurfaceInfo& surf) const;
 };
 /// @}
 

+ 25 - 0
src/anki/gr/vulkan/TextureImpl.inl.h

@@ -96,4 +96,29 @@ inline U TextureImpl::computeVkArrayLayer(const TextureSurfaceInfo& surf) const
 	return layer;
 }
 
+inline U TextureImpl::computeSubresourceIdx(const TextureSurfaceInfo& surf) const
+{
+	checkSurface(surf);
+
+	switch(m_type)
+	{
+	case TextureType::_1D:
+	case TextureType::_2D:
+		return surf.m_level;
+		break;
+	case TextureType::_2D_ARRAY:
+		return surf.m_layer * m_mipCount + surf.m_level;
+		break;
+	case TextureType::CUBE:
+		return surf.m_face * m_mipCount + surf.m_level;
+		break;
+	case TextureType::CUBE_ARRAY:
+		return surf.m_layer * m_mipCount * 6 + surf.m_face * m_mipCount + surf.m_level;
+		break;
+	default:
+		ANKI_ASSERT(0);
+		return 0;
+	}
+}
+
 } // end namespace anki

+ 12 - 12
src/anki/input/Input.h

@@ -14,23 +14,23 @@
 namespace anki
 {
 
+// Forward
 class InputImpl;
 class NativeWindow;
 
+enum class InputEvent : U8
+{
+	WINDOW_FOCUS_LOST,
+	WINDOW_FOCUS_GAINED,
+	WINDOW_CLOSED,
+	COUNT
+};
+
 /// Handle the input and other events
-///
 /// @note All positions are in NDC space
 class Input
 {
 public:
-	enum class Event : U8
-	{
-		WINDOW_FOCUS_LOST,
-		WINDOW_FOCUS_GAINED,
-		WINDOW_CLOSED,
-		COUNT
-	};
-
 	Input()
 	{
 	}
@@ -64,7 +64,7 @@ public:
 	}
 
 	/// Get the times an event was triggered and resets the counter
-	U getEvent(Event eventId) const
+	U getEvent(InputEvent eventId) const
 	{
 		return m_events[static_cast<U>(eventId)];
 	}
@@ -89,7 +89,7 @@ public:
 	}
 
 	/// Add a new event
-	void addEvent(Event eventId)
+	void addEvent(InputEvent eventId)
 	{
 		++m_events[static_cast<U>(eventId)];
 	}
@@ -113,7 +113,7 @@ private:
 
 	Vec2 m_mousePosNdc = Vec2(2.0); ///< The coords are in the NDC space
 
-	Array<U8, static_cast<U>(Event::COUNT)> m_events;
+	Array<U8, static_cast<U>(InputEvent::COUNT)> m_events;
 
 	Bool8 m_lockCurs = false;
 

+ 1 - 1
src/anki/input/InputSdl.cpp

@@ -323,7 +323,7 @@ Error Input::handleEvents()
 			m_mousePosNdc.y() = -((F32)event.button.y / m_nativeWindow->getHeight() * 2.0 - 1.0);
 			break;
 		case SDL_QUIT:
-			addEvent(Event::WINDOW_CLOSED);
+			addEvent(InputEvent::WINDOW_CLOSED);
 			break;
 		case SDL_TEXTINPUT:
 			break;

+ 28 - 13
src/anki/util/Functions.h

@@ -13,6 +13,7 @@
 #include <cmath>
 #include <utility>
 #include <new>
+#include <cstring>
 
 namespace anki
 {
@@ -162,19 +163,6 @@ struct RemovePointer<T*>
 	typedef T Type;
 };
 
-/// Perform a static cast of a pointer
-template<typename To, typename From>
-To staticCastPtr(From from)
-{
-#if ANKI_EXTRA_CHECKS
-	To ptr = dynamic_cast<To>(from);
-	ANKI_ASSERT(ptr != nullptr);
-	return ptr;
-#else
-	return static_cast<To>(from);
-#endif
-}
-
 /// Check if types are the same.
 template<class T, class Y>
 struct TypesAreTheSame
@@ -193,6 +181,33 @@ struct TypesAreTheSame<T, T>
 		m_value = 1
 	};
 };
+
+template<typename T>
+void memorySet(T* dest, T value, const PtrSize count);
+
+#define ANKI_SPECIALISE_MEMORY_SET(T)                                                                                  \
+	template<>                                                                                                         \
+	inline void memorySet(T* dest, T value, const PtrSize count)                                                       \
+	{                                                                                                                  \
+		ANKI_ASSERT(dest);                                                                                             \
+		const T* end = dest + count;                                                                                   \
+		while(dest != end)                                                                                             \
+		{                                                                                                              \
+			memcpy(reinterpret_cast<char*>(dest), &value, sizeof(T));                                                  \
+			++dest;                                                                                                    \
+		}                                                                                                              \
+	}
+
+ANKI_SPECIALISE_MEMORY_SET(U8)
+ANKI_SPECIALISE_MEMORY_SET(I8)
+ANKI_SPECIALISE_MEMORY_SET(U16)
+ANKI_SPECIALISE_MEMORY_SET(I16)
+ANKI_SPECIALISE_MEMORY_SET(U32)
+ANKI_SPECIALISE_MEMORY_SET(I32)
+ANKI_SPECIALISE_MEMORY_SET(U64)
+ANKI_SPECIALISE_MEMORY_SET(I64)
+
+#undef ANKI_SPECIALISE_MEMORY_SET
 /// @}
 
 } // end namespace anki

+ 3 - 0
src/anki/util/System.h

@@ -19,6 +19,9 @@ extern U32 getCpuCoresCount();
 /// Print the backtrace
 extern void printBacktrace();
 
+/// Trap the sefaults.
+extern void trapSegfaults(void (*)(void*));
+
 /// @}
 
 } // end namespace anki

+ 10 - 2
tests/gr/Gr.cpp

@@ -849,8 +849,16 @@ ANKI_TEST(Gr, DrawWithTexture)
 		cmdb->setViewport(0, 0, WIDTH, HEIGHT);
 		cmdb->bindShaderProgram(prog);
 		cmdb->beginRenderPass(fb);
-		cmdb->informTextureCurrentUsage(a, TextureUsageBit::SAMPLED_FRAGMENT);
-		cmdb->informTextureCurrentUsage(b, TextureUsageBit::SAMPLED_FRAGMENT);
+
+		for(U i = 0; i < 2; ++i)
+		{
+			cmdb->informTextureSurfaceCurrentUsage(
+				a, TextureSurfaceInfo(i, 0, 0, 0), TextureUsageBit::SAMPLED_FRAGMENT);
+			cmdb->informTextureSurfaceCurrentUsage(
+				b, TextureSurfaceInfo(i, 0, 0, 0), TextureUsageBit::SAMPLED_FRAGMENT);
+		}
+		cmdb->informTextureSurfaceCurrentUsage(b, TextureSurfaceInfo(2, 0, 0, 0), TextureUsageBit::SAMPLED_FRAGMENT);
+
 		cmdb->bindTexture(0, 0, a);
 		cmdb->bindTexture(0, 1, b);
 		cmdb->drawArrays(PrimitiveTopology::TRIANGLES, 6);