Przeglądaj źródła

Move the mipmap generation to the renderer

Panagiotis Christopoulos Charitos 1 rok temu
rodzic
commit
dc8d7ea186
35 zmienionych plików z 335 dodań i 417 usunięć
  1. 0 5
      AnKi/Gr/CommandBuffer.h
  2. 4 5
      AnKi/Gr/Common.h
  3. 0 5
      AnKi/Gr/D3D/D3DCommandBuffer.cpp
  4. 23 20
      AnKi/Gr/Vulkan/VkAccelerationStructure.cpp
  5. 2 2
      AnKi/Gr/Vulkan/VkAccelerationStructure.h
  6. 16 6
      AnKi/Gr/Vulkan/VkBuffer.cpp
  7. 2 2
      AnKi/Gr/Vulkan/VkBuffer.h
  8. 13 164
      AnKi/Gr/Vulkan/VkCommandBuffer.cpp
  9. 0 5
      AnKi/Gr/Vulkan/VkCommon.cpp
  10. 29 47
      AnKi/Gr/Vulkan/VkTexture.cpp
  11. 4 4
      AnKi/Gr/Vulkan/VkTexture.h
  12. 1 0
      AnKi/Renderer/AccelerationStructureBuilder.cpp
  13. 2 1
      AnKi/Renderer/ForwardShading.cpp
  14. 3 1
      AnKi/Renderer/GBuffer.cpp
  15. 11 9
      AnKi/Renderer/IndirectDiffuseProbes.cpp
  16. 5 0
      AnKi/Renderer/LightShading.cpp
  17. 1 0
      AnKi/Renderer/PrimaryNonRenderableVisibility.cpp
  18. 19 26
      AnKi/Renderer/ProbeReflections.cpp
  19. 1 1
      AnKi/Renderer/ProbeReflections.h
  20. 7 8
      AnKi/Renderer/Renderer.cpp
  21. 0 46
      AnKi/Renderer/Renderer.h
  22. 18 10
      AnKi/Renderer/RendererObject.cpp
  23. 9 0
      AnKi/Renderer/RendererObject.def.h
  24. 1 3
      AnKi/Renderer/RendererObject.h
  25. 18 12
      AnKi/Renderer/ShadowMapping.cpp
  26. 9 19
      AnKi/Renderer/Utils/GpuVisibility.cpp
  27. 1 1
      AnKi/Renderer/Utils/HzbGenerator.cpp
  28. 60 0
      AnKi/Renderer/Utils/MipmapGenerator.cpp
  29. 40 0
      AnKi/Renderer/Utils/MipmapGenerator.h
  30. 6 0
      AnKi/Renderer/Utils/Readback.h
  31. 1 1
      AnKi/Scene/Components/ReflectionProbeComponent.cpp
  32. 6 6
      AnKi/Shaders/Intellisense.hlsl
  33. 20 0
      AnKi/Shaders/MipmapGenerator.ankiprog
  34. 2 0
      AnKi/Shaders/MotionVectors.ankiprog
  35. 1 8
      AnKi/Ui/Font.cpp

+ 0 - 5
AnKi/Gr/CommandBuffer.h

@@ -368,11 +368,6 @@ public:
 	/// @param depth Depth.
 	void traceRays(const BufferView& sbtBuffer, U32 sbtRecordSize, U32 hitGroupSbtRecordCount, U32 rayTypeCount, U32 width, U32 height, U32 depth);
 
-	/// Generate mipmaps for non-3D textures. You have to transition all the mip levels of this face and layer to
-	/// TextureUsageBit::kGenerateMipmaps before calling this method.
-	/// @param texView The texture view to generate mips. It should point to a texture view that contains the 1st mip.
-	void generateMipmaps2d(const TextureView& texView);
-
 	/// Blit from surface to surface.
 	void blitTexture(const TextureView& srcView, const TextureView& destView);
 

+ 4 - 5
AnKi/Gr/Common.h

@@ -497,7 +497,6 @@ enum class TextureUsageBit : U32
 	kFramebufferShadingRate = 1 << 14,
 
 	kTransferDestination = 1 << 15,
-	kGenerateMipmaps = 1 << 16,
 
 	kPresent = 1 << 17,
 
@@ -512,12 +511,12 @@ enum class TextureUsageBit : U32
 	kAllGraphics = kSampledGeometry | kSampledFragment | kStorageGeometryRead | kStorageGeometryWrite | kStorageFragmentRead | kStorageFragmentWrite
 				   | kFramebufferRead | kFramebufferWrite | kFramebufferShadingRate,
 	kAllCompute = kSampledCompute | kStorageComputeRead | kStorageComputeWrite,
-	kAllTransfer = kTransferDestination | kGenerateMipmaps,
+	kAllTransfer = kTransferDestination,
 
 	kAllRead = kAllSampled | kStorageGeometryRead | kStorageFragmentRead | kStorageComputeRead | kStorageTraceRaysRead | kFramebufferRead
-			   | kFramebufferShadingRate | kPresent | kGenerateMipmaps,
-	kAllWrite = kStorageGeometryWrite | kStorageFragmentWrite | kStorageComputeWrite | kStorageTraceRaysWrite | kFramebufferWrite
-				| kTransferDestination | kGenerateMipmaps,
+			   | kFramebufferShadingRate | kPresent,
+	kAllWrite =
+		kStorageGeometryWrite | kStorageFragmentWrite | kStorageComputeWrite | kStorageTraceRaysWrite | kFramebufferWrite | kTransferDestination,
 	kAll = kAllRead | kAllWrite,
 	kAllShaderResource = kAllSampled | kAllStorage,
 	kAllSrv = (kAllSampled | kAllStorage) & kAllRead,

+ 0 - 5
AnKi/Gr/D3D/D3DCommandBuffer.cpp

@@ -565,11 +565,6 @@ void CommandBuffer::traceRays([[maybe_unused]] const BufferView& sbtBuffer, [[ma
 	ANKI_ASSERT(!"TODO");
 }
 
-void CommandBuffer::generateMipmaps2d(const TextureView& texView)
-{
-	ANKI_ASSERT(!"TODO");
-}
-
 void CommandBuffer::blitTexture([[maybe_unused]] const TextureView& srcView, [[maybe_unused]] const TextureView& destView)
 {
 	ANKI_ASSERT(!"TODO");

+ 23 - 20
AnKi/Gr/Vulkan/VkAccelerationStructure.cpp

@@ -211,99 +211,102 @@ Error AccelerationStructureImpl::init(const AccelerationStructureInitInfo& inf)
 	return Error::kNone;
 }
 
-void AccelerationStructureImpl::computeBarrierInfo(AccelerationStructureUsageBit before, AccelerationStructureUsageBit after,
-												   VkPipelineStageFlags& srcStages, VkAccessFlags& srcAccesses, VkPipelineStageFlags& dstStages,
-												   VkAccessFlags& dstAccesses)
+VkMemoryBarrier AccelerationStructureImpl::computeBarrierInfo(AccelerationStructureUsageBit before, AccelerationStructureUsageBit after,
+															  VkPipelineStageFlags& srcStages_, VkPipelineStageFlags& dstStages_)
 {
+	VkMemoryBarrier barrier = {};
+	barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
+
 	// Before
-	srcStages = 0;
-	srcAccesses = 0;
+	VkPipelineStageFlags srcStages = 0;
 
 	if(before == AccelerationStructureUsageBit::kNone)
 	{
 		srcStages |= VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
-		srcAccesses |= 0;
+		barrier.srcAccessMask |= 0;
 	}
 
 	if(!!(before & AccelerationStructureUsageBit::kBuild))
 	{
 		srcStages |= VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR;
-		srcAccesses |= VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR;
+		barrier.srcAccessMask |= VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR;
 	}
 
 	if(!!(before & AccelerationStructureUsageBit::kAttach))
 	{
 		srcStages |= VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR;
-		srcAccesses |= VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
+		barrier.srcAccessMask |= VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
 	}
 
 	if(!!(before & AccelerationStructureUsageBit::kGeometryRead))
 	{
 		srcStages |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT
 					 | VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT | VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
-		srcAccesses |= VK_ACCESS_MEMORY_READ_BIT; // READ_BIT is the only viable solution by elimination
+		barrier.srcAccessMask |= VK_ACCESS_MEMORY_READ_BIT; // READ_BIT is the only viable solution by elimination
 	}
 
 	if(!!(before & AccelerationStructureUsageBit::kFragmentRead))
 	{
 		srcStages |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
-		srcAccesses |= VK_ACCESS_MEMORY_READ_BIT;
+		barrier.srcAccessMask |= VK_ACCESS_MEMORY_READ_BIT;
 	}
 
 	if(!!(before & AccelerationStructureUsageBit::kComputeRead))
 	{
 		srcStages |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
-		srcAccesses |= VK_ACCESS_MEMORY_READ_BIT;
+		barrier.srcAccessMask |= VK_ACCESS_MEMORY_READ_BIT;
 	}
 
 	if(!!(before & AccelerationStructureUsageBit::kTraceRaysRead))
 	{
 		srcStages |= VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
-		srcAccesses |= VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
+		barrier.srcAccessMask |= VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
 	}
 
 	// After
-	dstStages = 0;
-	dstAccesses = 0;
+	VkPipelineStageFlags dstStages = 0;
 
 	if(!!(after & AccelerationStructureUsageBit::kBuild))
 	{
 		dstStages |= VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR;
-		dstAccesses |= VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR;
+		barrier.dstAccessMask |= VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR;
 	}
 
 	if(!!(after & AccelerationStructureUsageBit::kAttach))
 	{
 		dstStages |= VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR;
-		dstAccesses |= VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
+		barrier.dstAccessMask |= VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
 	}
 
 	if(!!(after & AccelerationStructureUsageBit::kGeometryRead))
 	{
 		dstStages |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT
 					 | VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT | VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
-		dstAccesses |= VK_ACCESS_MEMORY_READ_BIT; // READ_BIT is the only viable solution by elimination
+		barrier.dstAccessMask |= VK_ACCESS_MEMORY_READ_BIT; // READ_BIT is the only viable solution by elimination
 	}
 
 	if(!!(after & AccelerationStructureUsageBit::kFragmentRead))
 	{
 		dstStages |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
-		dstAccesses |= VK_ACCESS_MEMORY_READ_BIT;
+		barrier.dstAccessMask |= VK_ACCESS_MEMORY_READ_BIT;
 	}
 
 	if(!!(after & AccelerationStructureUsageBit::kComputeRead))
 	{
 		dstStages |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
-		dstAccesses |= VK_ACCESS_MEMORY_READ_BIT;
+		barrier.dstAccessMask |= VK_ACCESS_MEMORY_READ_BIT;
 	}
 
 	if(!!(after & AccelerationStructureUsageBit::kTraceRaysRead))
 	{
 		dstStages |= VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
-		dstAccesses |= VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
+		barrier.dstAccessMask |= VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR;
 	}
 
 	ANKI_ASSERT(srcStages && dstStages);
+
+	srcStages_ |= srcStages;
+	dstStages_ |= dstStages;
 }
 
 } // end namespace anki

+ 2 - 2
AnKi/Gr/Vulkan/VkAccelerationStructure.h

@@ -52,8 +52,8 @@ public:
 		rangeInfo = m_rangeInfo;
 	}
 
-	static void computeBarrierInfo(AccelerationStructureUsageBit before, AccelerationStructureUsageBit after, VkPipelineStageFlags& srcStages,
-								   VkAccessFlags& srcAccesses, VkPipelineStageFlags& dstStages, VkAccessFlags& dstAccesses);
+	static VkMemoryBarrier computeBarrierInfo(AccelerationStructureUsageBit before, AccelerationStructureUsageBit after,
+											  VkPipelineStageFlags& srcStages, VkPipelineStageFlags& dstStages);
 
 private:
 	class ASBottomLevelInfo

+ 16 - 6
AnKi/Gr/Vulkan/VkBuffer.cpp

@@ -424,16 +424,26 @@ VkAccessFlags BufferImpl::computeAccessMask(BufferUsageBit usage)
 	return mask;
 }
 
-void BufferImpl::computeBarrierInfo(BufferUsageBit before, BufferUsageBit after, VkPipelineStageFlags& srcStages, VkAccessFlags& srcAccesses,
-									VkPipelineStageFlags& dstStages, VkAccessFlags& dstAccesses) const
+VkBufferMemoryBarrier BufferImpl::computeBarrierInfo(BufferUsageBit before, BufferUsageBit after, VkPipelineStageFlags& srcStages,
+													 VkPipelineStageFlags& dstStages) const
 {
 	ANKI_ASSERT(usageValid(before) && usageValid(after));
 	ANKI_ASSERT(!!after);
 
-	srcStages = computePplineStage(before);
-	dstStages = computePplineStage(after);
-	srcAccesses = computeAccessMask(before);
-	dstAccesses = computeAccessMask(after);
+	VkBufferMemoryBarrier barrier = {};
+	barrier.buffer = m_handle;
+	barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
+	barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+	barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+	barrier.srcAccessMask = computeAccessMask(before);
+	barrier.dstAccessMask = computeAccessMask(after);
+	barrier.offset = 0;
+	barrier.size = VK_WHOLE_SIZE; // All size because none cares really
+
+	srcStages |= computePplineStage(before);
+	dstStages |= computePplineStage(after);
+
+	return barrier;
 }
 
 VkBufferView BufferImpl::getOrCreateBufferView(Format fmt, PtrSize offset, PtrSize range) const

+ 2 - 2
AnKi/Gr/Vulkan/VkBuffer.h

@@ -46,8 +46,8 @@ public:
 		return m_actualSize;
 	}
 
-	void computeBarrierInfo(BufferUsageBit before, BufferUsageBit after, VkPipelineStageFlags& srcStages, VkAccessFlags& srcAccesses,
-							VkPipelineStageFlags& dstStages, VkAccessFlags& dstAccesses) const;
+	VkBufferMemoryBarrier computeBarrierInfo(BufferUsageBit before, BufferUsageBit after, VkPipelineStageFlags& srcStages,
+											 VkPipelineStageFlags& dstStages) const;
 
 	/// Only for texture buffers.
 	/// @note It's thread-safe

+ 13 - 164
AnKi/Gr/Vulkan/VkCommandBuffer.cpp

@@ -276,7 +276,7 @@ void CommandBuffer::bindTexture(Register reg, const TextureView& texView)
 	if(reg.m_resourceType == HlslResourceType::kSrv)
 	{
 		ANKI_ASSERT(texView.isGoodForSampling());
-		const VkImageLayout lay = tex.computeLayout(TextureUsageBit::kAllSampled & tex.getTextureUsage(), 0);
+		const VkImageLayout lay = tex.computeLayout(TextureUsageBit::kAllSampled & tex.getTextureUsage());
 		self.m_descriptorState.bindSampledTexture(reg.m_space, reg.m_bindPoint, tex.getImageView(texView.getSubresource()), lay);
 	}
 	else
@@ -447,7 +447,7 @@ void CommandBuffer::beginRenderPass(ConstWeakArray<RenderTarget> colorRts, Rende
 		vkColorAttachments[i] = {};
 		vkColorAttachments[i].sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR;
 		vkColorAttachments[i].imageView = tex.getImageView(view.getSubresource());
-		vkColorAttachments[i].imageLayout = tex.computeLayout(colorRts[i].m_usage, 0);
+		vkColorAttachments[i].imageLayout = tex.computeLayout(colorRts[i].m_usage);
 		vkColorAttachments[i].loadOp = convertLoadOp(colorRts[i].m_loadOperation);
 		vkColorAttachments[i].storeOp = convertStoreOp(colorRts[i].m_storeOperation);
 		vkColorAttachments[i].clearValue.color.float32[0] = colorRts[i].m_clearValue.m_colorf[0];
@@ -488,7 +488,7 @@ void CommandBuffer::beginRenderPass(ConstWeakArray<RenderTarget> colorRts, Rende
 			vkDepthAttachment = {};
 			vkDepthAttachment.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR;
 			vkDepthAttachment.imageView = tex.getImageView(view.getSubresource());
-			vkDepthAttachment.imageLayout = tex.computeLayout(depthStencilRt->m_usage, 0);
+			vkDepthAttachment.imageLayout = tex.computeLayout(depthStencilRt->m_usage);
 			vkDepthAttachment.loadOp = convertLoadOp(depthStencilRt->m_loadOperation);
 			vkDepthAttachment.storeOp = convertStoreOp(depthStencilRt->m_storeOperation);
 			vkDepthAttachment.clearValue.depthStencil.depth = depthStencilRt->m_clearValue.m_depthStencil.m_depth;
@@ -502,7 +502,7 @@ void CommandBuffer::beginRenderPass(ConstWeakArray<RenderTarget> colorRts, Rende
 			vkStencilAttachment = {};
 			vkStencilAttachment.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR;
 			vkStencilAttachment.imageView = tex.getImageView(view.getSubresource());
-			vkStencilAttachment.imageLayout = tex.computeLayout(depthStencilRt->m_usage, 0);
+			vkStencilAttachment.imageLayout = tex.computeLayout(depthStencilRt->m_usage);
 			vkStencilAttachment.loadOp = convertLoadOp(depthStencilRt->m_stencilLoadOperation);
 			vkStencilAttachment.storeOp = convertStoreOp(depthStencilRt->m_stencilStoreOperation);
 			vkStencilAttachment.clearValue.depthStencil.depth = depthStencilRt->m_clearValue.m_depthStencil.m_depth;
@@ -807,94 +807,6 @@ void CommandBuffer::traceRays(const BufferView& sbtBuffer, U32 sbtRecordSize32,
 	vkCmdTraceRaysKHR(self.m_handle, &regions[0], &regions[1], &regions[2], &regions[3], width, height, depth);
 }
 
-void CommandBuffer::generateMipmaps2d(const TextureView& texView)
-{
-	ANKI_VK_SELF(CommandBufferImpl);
-	self.commandCommon();
-
-	const TextureImpl& tex = static_cast<const TextureImpl&>(texView.getTexture());
-	ANKI_ASSERT(tex.getTextureType() != TextureType::k3D && "Not for 3D");
-	ANKI_ASSERT(texView.getFirstMipmap() == 0 && texView.getMipmapCount() == 1);
-
-	const U32 blitCount = tex.getMipmapCount() - 1u;
-	if(blitCount == 0)
-	{
-		// Nothing to be done, flush the previous commands though because you may batch (and sort) things you shouldn't
-		return;
-	}
-
-	const DepthStencilAspectBit aspect = texView.getDepthStencilAspect();
-	const U32 face = texView.getFirstFace();
-	const U32 layer = texView.getFirstLayer();
-
-	for(U32 i = 0; i < blitCount; ++i)
-	{
-		// Transition source
-		// OPT: Combine the 2 barriers
-		if(i > 0)
-		{
-			const VkImageSubresourceRange range = tex.computeVkImageSubresourceRange(TextureSubresourceDescriptor::surface(i, face, layer, aspect));
-
-			self.setImageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
-								 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, tex.m_imageHandle,
-								 range);
-		}
-
-		// Transition destination
-		{
-			const VkImageSubresourceRange range =
-				tex.computeVkImageSubresourceRange(TextureSubresourceDescriptor::surface(i + 1, face, layer, aspect));
-
-			self.setImageBarrier(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, VK_IMAGE_LAYOUT_UNDEFINED, VK_PIPELINE_STAGE_TRANSFER_BIT,
-								 VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, tex.m_imageHandle, range);
-		}
-
-		// Setup the blit struct
-		I32 srcWidth = tex.getWidth() >> i;
-		I32 srcHeight = tex.getHeight() >> i;
-
-		I32 dstWidth = tex.getWidth() >> (i + 1);
-		I32 dstHeight = tex.getHeight() >> (i + 1);
-
-		ANKI_ASSERT(srcWidth > 0 && srcHeight > 0 && dstWidth > 0 && dstHeight > 0);
-
-		U32 vkLayer = 0;
-		switch(tex.getTextureType())
-		{
-		case TextureType::k2D:
-		case TextureType::k2DArray:
-			break;
-		case TextureType::kCube:
-			vkLayer = face;
-			break;
-		case TextureType::kCubeArray:
-			vkLayer = layer * 6 + face;
-			break;
-		default:
-			ANKI_ASSERT(0);
-			break;
-		}
-
-		VkImageBlit blit;
-		blit.srcSubresource.aspectMask = convertImageAspect(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 = convertImageAspect(aspect);
-		blit.dstSubresource.baseArrayLayer = vkLayer;
-		blit.dstSubresource.layerCount = 1;
-		blit.dstSubresource.mipLevel = i + 1;
-		blit.dstOffsets[0] = {0, 0, 0};
-		blit.dstOffsets[1] = {dstWidth, dstHeight, 1};
-
-		vkCmdBlitImage(self.m_handle, tex.m_imageHandle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, tex.m_imageHandle,
-					   VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, (!!aspect) ? VK_FILTER_NEAREST : VK_FILTER_LINEAR);
-	}
-}
-
 void CommandBuffer::blitTexture([[maybe_unused]] const TextureView& srcView, [[maybe_unused]] const TextureView& destView)
 {
 	ANKI_ASSERT(!"TODO");
@@ -1145,80 +1057,27 @@ void CommandBuffer::setPipelineBarrier(ConstWeakArray<TextureBarrierInfo> textur
 	for(const TextureBarrierInfo& barrier : textures)
 	{
 		const TextureImpl& impl = static_cast<const TextureImpl&>(barrier.m_textureView.getTexture());
-		const TextureUsageBit nextUsage = barrier.m_nextUsage;
-		const TextureUsageBit prevUsage = barrier.m_previousUsage;
-
-		ANKI_ASSERT(impl.usageValid(prevUsage));
-		ANKI_ASSERT(impl.usageValid(nextUsage));
-		ANKI_ASSERT(((nextUsage & TextureUsageBit::kGenerateMipmaps) == TextureUsageBit::kGenerateMipmaps
-					 || (nextUsage & TextureUsageBit::kGenerateMipmaps) == TextureUsageBit::kNone)
-					&& "GENERATE_MIPMAPS should be alone");
-
-		if(barrier.m_textureView.getFirstMipmap() > 0 && nextUsage == TextureUsageBit::kGenerateMipmaps) [[unlikely]]
-		{
-			// This transition happens inside CommandBufferImpl::generateMipmapsX. No need to do something
-			continue;
-		}
-
-		if(nextUsage == TextureUsageBit::kGenerateMipmaps) [[unlikely]]
-		{
-			// The transition of the non zero mip levels happens inside CommandBufferImpl::generateMipmapsX so limit the subresource
-
-			ANKI_ASSERT(barrier.m_textureView.getFirstMipmap() == 0 && barrier.m_textureView.getMipmapCount() == 1);
-		}
 
-		VkImageMemoryBarrier& inf = *imageBarriers.emplaceBack();
-		inf = {};
-		inf.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
-		inf.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-		inf.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-		inf.image = impl.m_imageHandle;
-		inf.subresourceRange = impl.computeVkImageSubresourceRange(barrier.m_textureView.getSubresource());
-
-		VkPipelineStageFlags srcStage;
-		VkPipelineStageFlags dstStage;
-		impl.computeBarrierInfo(prevUsage, nextUsage, inf.subresourceRange.baseMipLevel, srcStage, inf.srcAccessMask, dstStage, inf.dstAccessMask);
-		inf.oldLayout = impl.computeLayout(prevUsage, inf.subresourceRange.baseMipLevel);
-		inf.newLayout = impl.computeLayout(nextUsage, inf.subresourceRange.baseMipLevel);
-
-		srcStageMask |= srcStage;
-		dstStageMask |= dstStage;
+		imageBarriers.emplaceBack(impl.computeBarrierInfo(barrier.m_previousUsage, barrier.m_nextUsage, barrier.m_textureView.getSubresource(),
+														  srcStageMask, dstStageMask));
 	}
 
 	for(const BufferBarrierInfo& barrier : buffers)
 	{
 		ANKI_ASSERT(barrier.m_bufferView.isValid());
 		const BufferImpl& impl = static_cast<const BufferImpl&>(barrier.m_bufferView.getBuffer());
+		const VkBufferMemoryBarrier akBarrier = impl.computeBarrierInfo(barrier.m_previousUsage, barrier.m_nextUsage, srcStageMask, dstStageMask);
 
-		const VkBuffer handle = impl.getHandle();
-		VkPipelineStageFlags srcStage;
-		VkPipelineStageFlags dstStage;
-		VkAccessFlags srcAccessMask;
-		VkAccessFlags dstAccessMask;
-		impl.computeBarrierInfo(barrier.m_previousUsage, barrier.m_nextUsage, srcStage, srcAccessMask, dstStage, dstAccessMask);
-
-		srcStageMask |= srcStage;
-		dstStageMask |= dstStage;
-
-		if(bufferBarriers.getSize() && bufferBarriers.getBack().buffer == handle)
+		if(bufferBarriers.getSize() && bufferBarriers.getBack().buffer == akBarrier.buffer)
 		{
 			// Merge barriers
-			bufferBarriers.getBack().srcAccessMask |= srcAccessMask;
-			bufferBarriers.getBack().dstAccessMask |= dstAccessMask;
+			bufferBarriers.getBack().srcAccessMask |= akBarrier.srcAccessMask;
+			bufferBarriers.getBack().dstAccessMask |= akBarrier.dstAccessMask;
 		}
 		else
 		{
 			// Create a new buffer barrier
-			VkBufferMemoryBarrier& inf = *bufferBarriers.emplaceBack();
-			inf = {};
-			inf.buffer = handle;
-			inf.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
-			inf.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-			inf.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
-			inf.srcAccessMask = srcAccessMask;
-			inf.dstAccessMask = dstAccessMask;
-			inf.offset = 0;
-			inf.size = VK_WHOLE_SIZE; // All size because we don't care
+			bufferBarriers.emplaceBack(akBarrier);
 		}
 	}
 
@@ -1226,18 +1085,8 @@ void CommandBuffer::setPipelineBarrier(ConstWeakArray<TextureBarrierInfo> textur
 	{
 		ANKI_ASSERT(barrier.m_as);
 
-		VkMemoryBarrier& inf = *genericBarriers.emplaceBack();
-		inf = {};
-		inf.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
-
-		VkPipelineStageFlags srcStage;
-		VkPipelineStageFlags dstStage;
-		AccelerationStructureImpl::computeBarrierInfo(barrier.m_previousUsage, barrier.m_nextUsage, srcStage, inf.srcAccessMask, dstStage,
-													  inf.dstAccessMask);
-
-		srcStageMask |= srcStage;
-		dstStageMask |= dstStage;
-
+		genericBarriers.emplaceBack(
+			AccelerationStructureImpl::computeBarrierInfo(barrier.m_previousUsage, barrier.m_nextUsage, srcStageMask, dstStageMask));
 		self.m_microCmdb->pushObjectRef(barrier.m_as);
 	}
 

+ 0 - 5
AnKi/Gr/Vulkan/VkCommon.cpp

@@ -436,11 +436,6 @@ VkImageUsageFlags convertTextureUsage(const TextureUsageBit ak, const Format for
 		out |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
 	}
 
-	if(!!(ak & TextureUsageBit::kGenerateMipmaps))
-	{
-		out |= VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
-	}
-
 	ANKI_ASSERT(out);
 	return out;
 }

+ 29 - 47
AnKi/Gr/Vulkan/VkTexture.cpp

@@ -298,9 +298,8 @@ Error TextureImpl::initImage(const TextureInitInfo& init)
 	return Error::kNone;
 }
 
-void TextureImpl::computeBarrierInfo(TextureUsageBit usage, Bool src, U32 level, VkPipelineStageFlags& stages, VkAccessFlags& accesses) const
+void TextureImpl::computeBarrierInfo(TextureUsageBit usage, VkPipelineStageFlags& stages, VkAccessFlags& accesses) const
 {
-	ANKI_ASSERT(level < m_mipCount);
 	ANKI_ASSERT(usageValid(usage));
 	stages = 0;
 	accesses = 0;
@@ -391,30 +390,6 @@ void TextureImpl::computeBarrierInfo(TextureUsageBit usage, Bool src, U32 level,
 		accesses |= VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR;
 	}
 
-	if(!!(usage & TextureUsageBit::kGenerateMipmaps))
-	{
-		stages |= VK_PIPELINE_STAGE_TRANSFER_BIT;
-		if(src)
-		{
-			const Bool lastLevel = level == m_mipCount - 1;
-			if(lastLevel)
-			{
-				accesses |= VK_ACCESS_TRANSFER_WRITE_BIT;
-			}
-			else
-			{
-				accesses |= VK_ACCESS_TRANSFER_READ_BIT;
-			}
-		}
-		else
-		{
-			ANKI_ASSERT(level == 0
-						&& "The upper layers should not allow others levels to transition to gen mips state. This "
-						   "happens elsewhere");
-			accesses |= VK_ACCESS_TRANSFER_READ_BIT;
-		}
-	}
-
 	if(!!(usage & TextureUsageBit::kTransferDestination))
 	{
 		stages |= VK_PIPELINE_STAGE_TRANSFER_BIT;
@@ -428,27 +403,45 @@ void TextureImpl::computeBarrierInfo(TextureUsageBit usage, Bool src, U32 level,
 	}
 }
 
-void TextureImpl::computeBarrierInfo(TextureUsageBit before, TextureUsageBit after, U32 level, VkPipelineStageFlags& srcStages,
-									 VkAccessFlags& srcAccesses, VkPipelineStageFlags& dstStages, VkAccessFlags& dstAccesses) const
+VkImageMemoryBarrier TextureImpl::computeBarrierInfo(TextureUsageBit before, TextureUsageBit after, const TextureSubresourceDescriptor& subresource,
+													 VkPipelineStageFlags& srcStages, VkPipelineStageFlags& dstStages) const
 {
-	computeBarrierInfo(before, true, level, srcStages, srcAccesses);
-	computeBarrierInfo(after, false, level, dstStages, dstAccesses);
+	ANKI_ASSERT(usageValid(before));
+	ANKI_ASSERT(usageValid(after));
 
-	if(srcStages == 0)
+	VkImageMemoryBarrier barrier = {};
+
+	barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+	barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+	barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+	barrier.image = m_imageHandle;
+	barrier.subresourceRange = computeVkImageSubresourceRange(subresource);
+
+	barrier.oldLayout = computeLayout(before);
+	barrier.newLayout = computeLayout(after);
+
+	VkPipelineStageFlags srcStages2, dstStages2;
+	computeBarrierInfo(before, srcStages2, barrier.srcAccessMask);
+	computeBarrierInfo(after, dstStages2, barrier.dstAccessMask);
+
+	if(srcStages2 == 0)
 	{
-		srcStages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
+		srcStages2 = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
 	}
 
-	ANKI_ASSERT(dstStages);
+	ANKI_ASSERT(dstStages2);
+
+	srcStages |= srcStages2;
+	dstStages |= dstStages2;
+
+	return barrier;
 }
 
-VkImageLayout TextureImpl::computeLayout(TextureUsageBit usage, U level) const
+VkImageLayout TextureImpl::computeLayout(TextureUsageBit usage) const
 {
-	ANKI_ASSERT(level < m_mipCount);
 	ANKI_ASSERT(usageValid(usage));
 
 	VkImageLayout out = VK_IMAGE_LAYOUT_MAX_ENUM;
-	const Bool lastLevel = level == m_mipCount - 1u;
 	const Bool depthStencil = !!m_aspect;
 
 	if(usage == TextureUsageBit::kNone)
@@ -489,17 +482,6 @@ VkImageLayout TextureImpl::computeLayout(TextureUsageBit usage, U level) const
 		// Only sampled
 		out = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
 	}
-	else if(usage == TextureUsageBit::kGenerateMipmaps)
-	{
-		if(!lastLevel)
-		{
-			out = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
-		}
-		else
-		{
-			out = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
-		}
-	}
 	else if(usage == TextureUsageBit::kTransferDestination)
 	{
 		out = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;

+ 4 - 4
AnKi/Gr/Vulkan/VkTexture.h

@@ -60,11 +60,11 @@ public:
 	}
 
 	/// By knowing the previous and new texture usage calculate the relavant info for a ppline barrier.
-	void computeBarrierInfo(TextureUsageBit before, TextureUsageBit after, U32 level, VkPipelineStageFlags& srcStages, VkAccessFlags& srcAccesses,
-							VkPipelineStageFlags& dstStages, VkAccessFlags& dstAccesses) const;
+	VkImageMemoryBarrier computeBarrierInfo(TextureUsageBit before, TextureUsageBit after, const TextureSubresourceDescriptor& subresource,
+											VkPipelineStageFlags& srcStages, VkPipelineStageFlags& dstStages) const;
 
 	/// Predict the image layout.
-	VkImageLayout computeLayout(TextureUsageBit usage, U level) const;
+	VkImageLayout computeLayout(TextureUsageBit usage) const;
 
 	VkImageSubresourceRange computeVkImageSubresourceRange(const TextureSubresourceDescriptor& subresource) const
 	{
@@ -124,7 +124,7 @@ private:
 
 	Error initInternal(VkImage externalImage, const TextureInitInfo& init);
 
-	void computeBarrierInfo(TextureUsageBit usage, Bool src, U32 level, VkPipelineStageFlags& stages, VkAccessFlags& accesses) const;
+	void computeBarrierInfo(TextureUsageBit usage, VkPipelineStageFlags& stages, VkAccessFlags& accesses) const;
 
 	U32 translateSurfaceOrVolume(U32 layer, U32 face, U32 mip) const
 	{

+ 1 - 0
AnKi/Renderer/AccelerationStructureBuilder.cpp

@@ -5,6 +5,7 @@
 
 #include <AnKi/Renderer/AccelerationStructureBuilder.h>
 #include <AnKi/Renderer/Renderer.h>
+#include <AnKi/Renderer/Utils/GpuVisibility.h>
 #include <AnKi/Util/Tracer.h>
 #include <AnKi/Core/App.h>
 #include <AnKi/Core/GpuMemory/GpuVisibleTransientMemoryPool.h>

+ 2 - 1
AnKi/Renderer/ForwardShading.cpp

@@ -15,6 +15,7 @@
 #include <AnKi/Renderer/GBuffer.h>
 #include <AnKi/Renderer/Dbg.h>
 #include <AnKi/Renderer/VolumetricLightingAccumulation.h>
+#include <AnKi/Renderer/Utils/Drawer.h>
 #include <AnKi/Shaders/Include/MaterialTypes.h>
 #include <AnKi/Core/App.h>
 #include <AnKi/Util/Tracer.h>
@@ -105,7 +106,7 @@ void ForwardShading::run(const RenderingContext& ctx, RenderPassWorkContext& rgr
 			args.fill(m_runCtx.m_meshVisOut);
 		}
 
-		getRenderer().getSceneDrawer().drawMdi(args, cmdb);
+		getRenderer().getRenderableDrawer().drawMdi(args, cmdb);
 
 		// Restore state
 		cmdb.setDepthWrite(true);

+ 3 - 1
AnKi/Renderer/GBuffer.cpp

@@ -8,6 +8,8 @@
 #include <AnKi/Renderer/VrsSriGeneration.h>
 #include <AnKi/Renderer/Scale.h>
 #include <AnKi/Renderer/Dbg.h>
+#include <AnKi/Renderer/Utils/Drawer.h>
+#include <AnKi/Renderer/Utils/HzbGenerator.h>
 #include <AnKi/Util/Logger.h>
 #include <AnKi/Util/Tracer.h>
 #include <AnKi/Core/CVarSet.h>
@@ -219,7 +221,7 @@ void GBuffer::populateRenderGraph(RenderingContext& ctx)
 		}
 
 		cmdb.setDepthCompareOperation(CompareOperation::kLessEqual);
-		getRenderer().getSceneDrawer().drawMdi(args, cmdb);
+		getRenderer().getRenderableDrawer().drawMdi(args, cmdb);
 	});
 
 	for(U i = 0; i < kGBufferColorRenderTargetCount; ++i)

+ 11 - 9
AnKi/Renderer/IndirectDiffuseProbes.cpp

@@ -7,6 +7,7 @@
 #include <AnKi/Renderer/Renderer.h>
 #include <AnKi/Renderer/PrimaryNonRenderableVisibility.h>
 #include <AnKi/Renderer/Sky.h>
+#include <AnKi/Renderer/Utils/Drawer.h>
 #include <AnKi/Scene/SceneGraph.h>
 #include <AnKi/Scene/Components/GlobalIlluminationProbeComponent.h>
 #include <AnKi/Scene/Components/LightComponent.h>
@@ -207,7 +208,7 @@ void IndirectDiffuseProbes::populateRenderGraph(RenderingContext& rctx)
 				Array<F32, kMaxLodCount - 1> lodDistances = {g_lod0MaxDistanceCVar.get(), g_lod1MaxDistanceCVar.get()};
 
 				FrustumGpuVisibilityInput visIn;
-				visIn.m_passesName = generateTempPassName("GI: GBuffer", cellIdx, "face", f);
+				visIn.m_passesName = generateTempPassName("GI: GBuffer cell:%u face:%u", cellIdx, f);
 				visIn.m_technique = RenderingTechnique::kGBuffer;
 				visIn.m_viewProjectionMatrix = frustum.getViewProjectionMatrix();
 				visIn.m_lodReferencePoint = cellCenter;
@@ -234,7 +235,7 @@ void IndirectDiffuseProbes::populateRenderGraph(RenderingContext& rctx)
 
 			// GBuffer
 			{
-				GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(generateTempPassName("GI: GBuffer", cellIdx, "face", f));
+				GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(generateTempPassName("GI: GBuffer cell:%u face:%u", cellIdx, f));
 
 				Array<RenderTargetInfo, kGBufferColorRenderTargetCount> colorRtis;
 				for(U j = 0; j < kGBufferColorRenderTargetCount; ++j)
@@ -282,7 +283,7 @@ void IndirectDiffuseProbes::populateRenderGraph(RenderingContext& rctx)
 						args.fill(meshletVisOut);
 					}
 
-					getRenderer().getSceneDrawer().drawMdi(args, cmdb);
+					getRenderer().getRenderableDrawer().drawMdi(args, cmdb);
 
 					// It's secondary, no need to restore any state
 				});
@@ -305,7 +306,7 @@ void IndirectDiffuseProbes::populateRenderGraph(RenderingContext& rctx)
 				Array<F32, kMaxLodCount - 1> lodDistances = {g_lod0MaxDistanceCVar.get(), g_lod1MaxDistanceCVar.get()};
 
 				FrustumGpuVisibilityInput visIn;
-				visIn.m_passesName = generateTempPassName("GI: Shadows", cellIdx, "face", f);
+				visIn.m_passesName = generateTempPassName("GI: Shadows cell:%u face:%u", cellIdx, f);
 				visIn.m_technique = RenderingTechnique::kDepth;
 				visIn.m_viewProjectionMatrix = cascadeViewProjMat;
 				visIn.m_lodReferencePoint = cellCenter;
@@ -334,7 +335,7 @@ void IndirectDiffuseProbes::populateRenderGraph(RenderingContext& rctx)
 			if(doShadows)
 			{
 				// Create the pass
-				GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(generateTempPassName("GI: Shadows", cellIdx, "face", f));
+				GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(generateTempPassName("GI: Shadows cell:%u face:%u", cellIdx, f));
 
 				RenderTargetInfo depthRti(shadowsRt);
 				depthRti.m_loadOperation = RenderTargetLoadOperation::kClear;
@@ -371,7 +372,7 @@ void IndirectDiffuseProbes::populateRenderGraph(RenderingContext& rctx)
 						args.fill(shadowMeshletVisOut);
 					}
 
-					getRenderer().getSceneDrawer().drawMdi(args, cmdb);
+					getRenderer().getRenderableDrawer().drawMdi(args, cmdb);
 
 					// It's secondary, no need to restore the state
 				});
@@ -381,7 +382,7 @@ void IndirectDiffuseProbes::populateRenderGraph(RenderingContext& rctx)
 			GpuVisibilityNonRenderablesOutput lightVis;
 			{
 				GpuVisibilityNonRenderablesInput in;
-				in.m_passesName = generateTempPassName("GI: Light visibility", cellIdx, "face", f);
+				in.m_passesName = generateTempPassName("GI: Light visibility cell:%u face:%u", cellIdx, f);
 				in.m_objectType = GpuSceneNonRenderableObjectType::kLight;
 				in.m_viewProjectionMat = frustum.getViewProjectionMatrix();
 				in.m_rgraph = &rgraph;
@@ -390,7 +391,8 @@ void IndirectDiffuseProbes::populateRenderGraph(RenderingContext& rctx)
 
 			// Light shading pass
 			{
-				GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(generateTempPassName("GI: Light shading", cellIdx, "face", f));
+				GraphicsRenderPassDescription& pass =
+					rgraph.newGraphicsRenderPass(generateTempPassName("GI: Light shading cell:%u face:%u", cellIdx, f));
 
 				RenderTargetInfo colorRti(lightShadingRt);
 				colorRti.m_loadOperation = RenderTargetLoadOperation::kClear;
@@ -470,7 +472,7 @@ void IndirectDiffuseProbes::populateRenderGraph(RenderingContext& rctx)
 
 		// Irradiance pass. First & 2nd bounce
 		{
-			ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass(generateTempPassName("GI: Irradiance", cellIdx));
+			ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass(generateTempPassName("GI: Irradiance cell:%u", cellIdx));
 
 			pass.newTextureDependency(lightShadingRt, TextureUsageBit::kSampledCompute);
 			pass.newTextureDependency(irradianceVolume, TextureUsageBit::kStorageComputeWrite);

+ 5 - 0
AnKi/Renderer/LightShading.cpp

@@ -297,6 +297,11 @@ void LightShading::populateRenderGraph(RenderingContext& ctx)
 	pass.newTextureDependency(getRenderer().getSsao().getRt(), readUsage);
 	pass.newTextureDependency(getRenderer().getSsr().getRt(), readUsage);
 
+	if(getRenderer().getProbeReflections().getHasCurrentlyRefreshedReflectionRt())
+	{
+		pass.newTextureDependency(getRenderer().getProbeReflections().getCurrentlyRefreshedReflectionRt(), readUsage);
+	}
+
 	// Fog
 	pass.newTextureDependency(getRenderer().getVolumetricFog().getRt(), readUsage);
 

+ 1 - 0
AnKi/Renderer/PrimaryNonRenderableVisibility.cpp

@@ -6,6 +6,7 @@
 #include <AnKi/Renderer/PrimaryNonRenderableVisibility.h>
 #include <AnKi/Renderer/Renderer.h>
 #include <AnKi/Renderer/GBuffer.h>
+#include <AnKi/Renderer/Utils/GpuVisibility.h>
 #include <AnKi/Shaders/Include/GpuSceneFunctions.h>
 #include <AnKi/Scene/GpuSceneArray.h>
 #include <AnKi/Scene/Components/LightComponent.h>

+ 19 - 26
AnKi/Renderer/ProbeReflections.cpp

@@ -10,6 +10,8 @@
 #include <AnKi/Renderer/GBuffer.h>
 #include <AnKi/Renderer/Sky.h>
 #include <AnKi/Renderer/PrimaryNonRenderableVisibility.h>
+#include <AnKi/Renderer/Utils/MipmapGenerator.h>
+#include <AnKi/Renderer/Utils/Drawer.h>
 #include <AnKi/Core/CVarSet.h>
 #include <AnKi/Util/Tracer.h>
 #include <AnKi/Core/StatsSet.h>
@@ -95,7 +97,7 @@ Error ProbeReflections::initGBuffer()
 Error ProbeReflections::initLightShading()
 {
 	m_lightShading.m_tileSize = g_reflectionProbeResolutionCVar.get();
-	m_lightShading.m_mipCount = computeMaxMipmapCount2d(m_lightShading.m_tileSize, m_lightShading.m_tileSize, 8);
+	m_lightShading.m_mipCount = U8(computeMaxMipmapCount2d(m_lightShading.m_tileSize, m_lightShading.m_tileSize, 8));
 
 	// Init deferred
 	ANKI_CHECK(m_lightShading.m_deferred.init());
@@ -206,7 +208,7 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 			Array<F32, kMaxLodCount - 1> lodDistances = {g_lod0MaxDistanceCVar.get(), g_lod1MaxDistanceCVar.get()};
 
 			FrustumGpuVisibilityInput visIn;
-			visIn.m_passesName = generateTempPassName("Cube refl: GBuffer", f);
+			visIn.m_passesName = generateTempPassName("Cube refl: GBuffer face:%u", f);
 			visIn.m_technique = RenderingTechnique::kGBuffer;
 			visIn.m_viewProjectionMatrix = frustum.getViewProjectionMatrix();
 			visIn.m_lodReferencePoint = probeToRefresh->getWorldPosition();
@@ -234,7 +236,7 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 		// GBuffer pass
 		{
 			// Create pass
-			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(generateTempPassName("Cube refl: GBuffer", f));
+			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(generateTempPassName("Cube refl: GBuffer face:%u", f));
 
 			Array<RenderTargetInfo, kGBufferColorRenderTargetCount> colorRtis;
 			for(U j = 0; j < kGBufferColorRenderTargetCount; ++j)
@@ -280,7 +282,7 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 					args.fill(meshletVisOut);
 				}
 
-				getRenderer().getSceneDrawer().drawMdi(args, cmdb);
+				getRenderer().getRenderableDrawer().drawMdi(args, cmdb);
 			});
 		}
 
@@ -301,7 +303,7 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 			Array<F32, kMaxLodCount - 1> lodDistances = {g_lod0MaxDistanceCVar.get(), g_lod1MaxDistanceCVar.get()};
 
 			FrustumGpuVisibilityInput visIn;
-			visIn.m_passesName = generateTempPassName("Cube refl: Shadows", f);
+			visIn.m_passesName = generateTempPassName("Cube refl: Shadows face:%u", f);
 			visIn.m_technique = RenderingTechnique::kDepth;
 			visIn.m_viewProjectionMatrix = cascadeViewProjMat;
 			visIn.m_lodReferencePoint = probeToRefresh->getWorldPosition();
@@ -330,7 +332,7 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 		if(doShadows)
 		{
 			// Pass
-			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(generateTempPassName("Cube refl: Shadows", f));
+			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(generateTempPassName("Cube refl: Shadows face:%u", f));
 
 			RenderTargetInfo depthRti(shadowMapRt);
 			depthRti.m_loadOperation = RenderTargetLoadOperation::kClear;
@@ -367,7 +369,7 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 					args.fill(shadowMeshletVisOut);
 				}
 
-				getRenderer().getSceneDrawer().drawMdi(args, cmdb);
+				getRenderer().getRenderableDrawer().drawMdi(args, cmdb);
 			});
 		}
 
@@ -375,7 +377,7 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 		GpuVisibilityNonRenderablesOutput lightVis;
 		{
 			GpuVisibilityNonRenderablesInput in;
-			in.m_passesName = generateTempPassName("Cube refl: Light visibility", f);
+			in.m_passesName = generateTempPassName("Cube refl: Light visibility face:%u", f);
 			in.m_objectType = GpuSceneNonRenderableObjectType::kLight;
 			in.m_viewProjectionMat = frustum.getViewProjectionMatrix();
 			in.m_rgraph = &rgraph;
@@ -384,7 +386,7 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 
 		// Light shading pass
 		{
-			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(generateTempPassName("Cube refl: light shading", f));
+			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(generateTempPassName("Cube refl: light shading face:%u", f));
 
 			RenderTargetInfo colorRti(probeTexture);
 			colorRti.m_subresource.m_face = f;
@@ -512,23 +514,14 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 
 	// Mipmapping "passes"
 	{
-		for(U32 faceIdx = 0; faceIdx < 6; ++faceIdx)
-		{
-			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(generateTempPassName("Cube refl: Gen mips", faceIdx));
-
-			for(U32 mip = 0; mip < m_lightShading.m_mipCount; ++mip)
-			{
-				const TextureSubresourceDescriptor subresource = TextureSubresourceDescriptor::surface(mip, faceIdx, 0);
-				pass.newTextureDependency(probeTexture, TextureUsageBit::kGenerateMipmaps, subresource);
-			}
-
-			pass.setWork([this, faceIdx, probeTexture](RenderPassWorkContext& rgraphCtx) {
-				ANKI_TRACE_SCOPED_EVENT(ProbeReflections);
-
-				const TextureSubresourceDescriptor subresource = TextureSubresourceDescriptor::surface(0, faceIdx, 0);
-				rgraphCtx.m_commandBuffer->generateMipmaps2d(rgraphCtx.createTextureView(probeTexture, subresource));
-			});
-		}
+		const MipmapGeneratorTargetArguments desc = {
+			.m_handle = probeTexture,
+			.m_targetSize = UVec2(probeToRefresh->getReflectionTexture().getWidth(), probeToRefresh->getReflectionTexture().getHeight()),
+			.m_layerCount = 1,
+			.m_mipmapCount = m_lightShading.m_mipCount,
+			.m_isCubeTexture = true};
+
+		getRenderer().getMipmapGenerator().populateRenderGraph(desc, rgraph, "Cube refl: Gen mips");
 	}
 }
 

+ 1 - 1
AnKi/Renderer/ProbeReflections.h

@@ -67,7 +67,7 @@ private:
 	{
 	public:
 		U32 m_tileSize = 0;
-		U32 m_mipCount = 0;
+		U8 m_mipCount = 0;
 		TraditionalDeferredLightShading m_deferred;
 	} m_lightShading; ///< Light shading.
 

+ 7 - 8
AnKi/Renderer/Renderer.cpp

@@ -14,6 +14,7 @@
 #include <AnKi/Core/GpuMemory/GpuSceneBuffer.h>
 #include <AnKi/Scene/Components/CameraComponent.h>
 #include <AnKi/Scene/Components/LightComponent.h>
+#include <AnKi/Core/StatsSet.h>
 
 #include <AnKi/Renderer/ProbeReflections.h>
 #include <AnKi/Renderer/GBuffer.h>
@@ -44,7 +45,11 @@
 #include <AnKi/Renderer/Ssao.h>
 #include <AnKi/Renderer/Ssr.h>
 #include <AnKi/Renderer/Sky.h>
-#include <AnKi/Core/StatsSet.h>
+#include <AnKi/Renderer/Utils/Drawer.h>
+#include <AnKi/Renderer/Utils/GpuVisibility.h>
+#include <AnKi/Renderer/Utils/MipmapGenerator.h>
+#include <AnKi/Renderer/Utils/Readback.h>
+#include <AnKi/Renderer/Utils/HzbGenerator.h>
 
 namespace anki {
 
@@ -240,12 +245,6 @@ Error Renderer::initInternal(UVec2 swapchainResolution)
 		m_jitterOffsets[i] = generateJitter(i);
 	}
 
-	ANKI_CHECK(m_visibility.init());
-	ANKI_CHECK(m_nonRenderablesVisibility.init());
-	ANKI_CHECK(m_asVisibility.init());
-	ANKI_CHECK(m_hzbGenerator.init());
-	ANKI_CHECK(m_sceneDrawer.init());
-
 	return Error::kNone;
 }
 
@@ -401,7 +400,7 @@ void Renderer::finalize(const RenderingContext& ctx, Fence* fence)
 	++m_frameCount;
 
 	m_prevMatrices = ctx.m_matrices;
-	m_readbaks.endFrame(fence);
+	m_readbackManager->endFrame(fence);
 }
 
 TextureInitInfo Renderer::create2DRenderTargetInitInfo(U32 w, U32 h, Format format, TextureUsageBit usage, CString name)

+ 0 - 46
AnKi/Renderer/Renderer.h

@@ -6,14 +6,10 @@
 #pragma once
 
 #include <AnKi/Renderer/Common.h>
-#include <AnKi/Renderer/Utils/Drawer.h>
-#include <AnKi/Renderer/Utils/GpuVisibility.h>
-#include <AnKi/Renderer/Utils/HzbGenerator.h>
 #include <AnKi/Math.h>
 #include <AnKi/Gr.h>
 #include <AnKi/Resource/Forward.h>
 #include <AnKi/Collision/Forward.h>
-#include <AnKi/Renderer/Utils/Readback.h>
 
 namespace anki {
 
@@ -95,46 +91,11 @@ public:
 		return m_frameCount;
 	}
 
-	const RenderableDrawer& getSceneDrawer() const
-	{
-		return m_sceneDrawer;
-	}
-
-	RenderableDrawer& getSceneDrawer()
-	{
-		return m_sceneDrawer;
-	}
-
-	GpuVisibility& getGpuVisibility()
-	{
-		return m_visibility;
-	}
-
 	Bool runSoftwareMeshletRendering() const
 	{
 		return g_meshletRenderingCVar.get() && !GrManager::getSingleton().getDeviceCapabilities().m_meshShaders;
 	}
 
-	GpuVisibilityNonRenderables& getGpuVisibilityNonRenderables()
-	{
-		return m_nonRenderablesVisibility;
-	}
-
-	GpuVisibilityAccelerationStructures& getGpuVisibilityAccelerationStructures()
-	{
-		return m_asVisibility;
-	}
-
-	const HzbGenerator& getHzbGenerator() const
-	{
-		return m_hzbGenerator;
-	}
-
-	ReadbackManager& getReadbackManager()
-	{
-		return m_readbaks;
-	}
-
 	/// Create the init info for a 2D texture that will be used as a render target.
 	[[nodiscard]] TextureInitInfo create2DRenderTargetInitInfo(U32 w, U32 h, Format format, TextureUsageBit usage, CString name = {});
 
@@ -229,13 +190,6 @@ private:
 	UVec2 m_internalResolution = UVec2(0u); ///< The resolution of all passes up until TAA.
 	UVec2 m_postProcessResolution = UVec2(0u); ///< The resolution of post processing and following passes.
 
-	RenderableDrawer m_sceneDrawer;
-	GpuVisibility m_visibility;
-	GpuVisibilityNonRenderables m_nonRenderablesVisibility;
-	GpuVisibilityAccelerationStructures m_asVisibility;
-	HzbGenerator m_hzbGenerator;
-	ReadbackManager m_readbaks;
-
 	U64 m_frameCount; ///< Frame number
 
 	CommonMatrices m_prevMatrices;

+ 18 - 10
AnKi/Renderer/RendererObject.cpp

@@ -110,18 +110,26 @@ void RendererObject::zeroBuffer(Buffer* buff)
 	fence->clientWait(16.0_sec);
 }
 
-CString RendererObject::generateTempPassName(CString name, U32 index)
+CString RendererObject::generateTempPassName(const Char* fmt, ...)
 {
-	Char* str = static_cast<Char*>(getRenderer().getFrameMemoryPool().allocate(128, 1));
-	snprintf(str, 128, "%s #%u", name.cstr(), index);
-	return str;
-}
+	Array<Char, 128> buffer;
 
-CString RendererObject::generateTempPassName(CString name, U32 index, CString name2, U32 index2)
-{
-	Char* str = static_cast<Char*>(getRenderer().getFrameMemoryPool().allocate(128, 1));
-	snprintf(str, 128, "%s #%u %s #%u", name.cstr(), index, name2.cstr(), index2);
-	return str;
+	va_list args;
+	va_start(args, fmt);
+	const I len = vsnprintf(&buffer[0], sizeof(buffer), fmt, args);
+	va_end(args);
+
+	if(len > 0 && len < I(sizeof(buffer)))
+	{
+		Char* str = static_cast<Char*>(getRenderer().getFrameMemoryPool().allocate(len + 1, 1));
+		memcpy(str, buffer.getBegin(), len + 1);
+		return str;
+	}
+	else
+	{
+		ANKI_R_LOGE("generateTempPassName() failed. Ignoring error");
+		return "**failed**";
+	}
 }
 
 } // end namespace anki

+ 9 - 0
AnKi/Renderer/RendererObject.def.h

@@ -36,4 +36,13 @@ ANKI_RENDERER_OBJECT_DEF(Ssao, ssao, 1)
 ANKI_RENDERER_OBJECT_DEF(Ssr, ssr, 1)
 ANKI_RENDERER_OBJECT_DEF(Sky, sky, 1)
 
+// Util objects
+ANKI_RENDERER_OBJECT_DEF(RenderableDrawer, drawer, 1)
+ANKI_RENDERER_OBJECT_DEF(GpuVisibility, gpuVisibility, 1)
+ANKI_RENDERER_OBJECT_DEF(GpuVisibilityNonRenderables, gpuVisibilityNonRenderables, 1)
+ANKI_RENDERER_OBJECT_DEF(GpuVisibilityAccelerationStructures, gpuVisibilityAccelerationStructures, 1)
+ANKI_RENDERER_OBJECT_DEF(HzbGenerator, hzbGenerator, 1)
+ANKI_RENDERER_OBJECT_DEF(ReadbackManager, readbackManager, 1)
+ANKI_RENDERER_OBJECT_DEF(MipmapGenerator, mipmapGenerator, 1)
+
 #undef ANKI_RENDERER_OBJECT_DEF

+ 1 - 3
AnKi/Renderer/RendererObject.h

@@ -102,9 +102,7 @@ protected:
 	static void zeroBuffer(Buffer* buff);
 
 	/// Temp pass name.
-	static CString generateTempPassName(CString name, U32 index);
-
-	static CString generateTempPassName(CString name, U32 index, CString name2, U32 index2);
+	static CString generateTempPassName(const Char* fmt, ...);
 };
 /// @}
 

+ 18 - 12
AnKi/Renderer/ShadowMapping.cpp

@@ -7,6 +7,9 @@
 #include <AnKi/Renderer/Renderer.h>
 #include <AnKi/Renderer/GBuffer.h>
 #include <AnKi/Renderer/PrimaryNonRenderableVisibility.h>
+#include <AnKi/Renderer/Utils/GpuVisibility.h>
+#include <AnKi/Renderer/Utils/Drawer.h>
+#include <AnKi/Renderer/Utils/HzbGenerator.h>
 #include <AnKi/Core/App.h>
 #include <AnKi/Core/StatsSet.h>
 #include <AnKi/Core/GpuMemory/GpuVisibleTransientMemoryPool.h>
@@ -351,7 +354,7 @@ void ShadowMapping::processLights(RenderingContext& ctx)
 			// Vis testing
 			const Array<F32, kMaxLodCount - 1> lodDistances = {g_lod0MaxDistanceCVar.get(), g_lod1MaxDistanceCVar.get()};
 			DistanceGpuVisibilityInput visIn;
-			visIn.m_passesName = generateTempPassName("Shadows point light", lightIdx);
+			visIn.m_passesName = generateTempPassName("Shadows point light lightIdx:%u", lightIdx);
 			visIn.m_technique = RenderingTechnique::kDepth;
 			visIn.m_lodReferencePoint = ctx.m_matrices.m_cameraTransform.getTranslationPart().xyz();
 			visIn.m_lodDistances = lodDistances;
@@ -368,7 +371,8 @@ void ShadowMapping::processLights(RenderingContext& ctx)
 			BufferView clearTileIndirectArgs;
 			if(!renderAllways)
 			{
-				clearTileIndirectArgs = createVetVisibilityPass(generateTempPassName("Shadows: Vet point light", lightIdx), *lightc, visOut, rgraph);
+				clearTileIndirectArgs =
+					createVetVisibilityPass(generateTempPassName("Shadows: Vet point light lightIdx:%u", lightIdx), *lightc, visOut, rgraph);
 			}
 
 			// Additional visibility
@@ -376,7 +380,7 @@ void ShadowMapping::processLights(RenderingContext& ctx)
 			if(getRenderer().runSoftwareMeshletRendering())
 			{
 				PassthroughGpuMeshletVisibilityInput meshIn;
-				meshIn.m_passesName = generateTempPassName("Shadows point light", lightIdx);
+				meshIn.m_passesName = generateTempPassName("Shadows point light lightIdx:%u", lightIdx);
 				meshIn.m_technique = RenderingTechnique::kDepth;
 				meshIn.m_rgraph = &rgraph;
 				meshIn.fillBuffers(visOut);
@@ -401,7 +405,7 @@ void ShadowMapping::processLights(RenderingContext& ctx)
 				subpasses[face].m_viewProjMat = frustum.getViewProjectionMatrix();
 			}
 
-			createDrawShadowsPass(subpasses, visOut, meshletVisOut, generateTempPassName("Shadows: Point light", lightIdx), rgraph);
+			createDrawShadowsPass(subpasses, visOut, meshletVisOut, generateTempPassName("Shadows: Point light lightIdx:%u", lightIdx), rgraph);
 		}
 		else
 		{
@@ -441,7 +445,7 @@ void ShadowMapping::processLights(RenderingContext& ctx)
 			// Vis testing
 			const Array<F32, kMaxLodCount - 1> lodDistances = {g_lod0MaxDistanceCVar.get(), g_lod1MaxDistanceCVar.get()};
 			FrustumGpuVisibilityInput visIn;
-			visIn.m_passesName = generateTempPassName("Shadows spot light", lightIdx);
+			visIn.m_passesName = generateTempPassName("Shadows spot light lightIdx:%u", lightIdx);
 			visIn.m_technique = RenderingTechnique::kDepth;
 			visIn.m_lodReferencePoint = cameraOrigin;
 			visIn.m_lodDistances = lodDistances;
@@ -458,7 +462,8 @@ void ShadowMapping::processLights(RenderingContext& ctx)
 			BufferView clearTileIndirectArgs;
 			if(!renderAllways)
 			{
-				clearTileIndirectArgs = createVetVisibilityPass(generateTempPassName("Shadows: Vet spot light", lightIdx), *lightc, visOut, rgraph);
+				clearTileIndirectArgs =
+					createVetVisibilityPass(generateTempPassName("Shadows: Vet spot light lightIdx:%u", lightIdx), *lightc, visOut, rgraph);
 			}
 
 			// Additional visibility
@@ -466,7 +471,7 @@ void ShadowMapping::processLights(RenderingContext& ctx)
 			if(getRenderer().runSoftwareMeshletRendering())
 			{
 				GpuMeshletVisibilityInput meshIn;
-				meshIn.m_passesName = generateTempPassName("Shadows spot light", lightIdx);
+				meshIn.m_passesName = generateTempPassName("Shadows spot light lightIdx:%u", lightIdx);
 				meshIn.m_technique = RenderingTechnique::kDepth;
 				meshIn.m_viewProjectionMatrix = lightc->getSpotLightViewProjectionMatrix();
 				meshIn.m_cameraTransform = lightc->getSpotLightViewMatrix().getInverseTransformation();
@@ -479,7 +484,7 @@ void ShadowMapping::processLights(RenderingContext& ctx)
 
 			// Add draw pass
 			createDrawShadowsPass(atlasViewport, lightc->getSpotLightViewProjectionMatrix(), lightc->getSpotLightViewMatrix(), visOut, meshletVisOut,
-								  clearTileIndirectArgs, {}, generateTempPassName("Shadows: Spot light", lightIdx), rgraph);
+								  clearTileIndirectArgs, {}, generateTempPassName("Shadows: Spot light lightIdx:%u", lightIdx), rgraph);
 		}
 		else
 		{
@@ -535,7 +540,7 @@ void ShadowMapping::processLights(RenderingContext& ctx)
 			// Vis testing
 			const Array<F32, kMaxLodCount - 1> lodDistances = {g_lod0MaxDistanceCVar.get(), g_lod1MaxDistanceCVar.get()};
 			FrustumGpuVisibilityInput visIn;
-			visIn.m_passesName = generateTempPassName("Shadows: Dir light cascade", cascade);
+			visIn.m_passesName = generateTempPassName("Shadows: Dir light cascade lightIdx:%u cascade:%u", lightIdx, cascade);
 			visIn.m_technique = RenderingTechnique::kDepth;
 			visIn.m_viewProjectionMatrix = cascadeViewProjMats[cascade];
 			visIn.m_lodReferencePoint = ctx.m_matrices.m_cameraTransform.getTranslationPart().xyz();
@@ -552,7 +557,7 @@ void ShadowMapping::processLights(RenderingContext& ctx)
 			if(getRenderer().runSoftwareMeshletRendering())
 			{
 				GpuMeshletVisibilityInput meshIn;
-				meshIn.m_passesName = generateTempPassName("Shadows: Dir light cascade", lightIdx);
+				meshIn.m_passesName = generateTempPassName("Shadows: Dir light cascade lightIdx:%u cascade:%u", lightIdx, cascade);
 				meshIn.m_technique = RenderingTechnique::kDepth;
 				meshIn.m_viewProjectionMatrix = cascadeViewProjMats[cascade];
 				meshIn.m_cameraTransform = cascadeViewMats[cascade].getInverseTransformation();
@@ -565,7 +570,8 @@ void ShadowMapping::processLights(RenderingContext& ctx)
 
 			// Draw
 			createDrawShadowsPass(dirLightAtlasViewports[cascade], cascadeViewProjMats[cascade], cascadeViewMats[cascade], visOut, meshletVisOut, {},
-								  hzbGenIn.m_cascades[cascade].m_hzbRt, generateTempPassName("Shadows: Dir light cascade", cascade), rgraph);
+								  hzbGenIn.m_cascades[cascade].m_hzbRt,
+								  generateTempPassName("Shadows: Dir light lightIdx:%u cascade:%u", lightIdx, cascade), rgraph);
 
 			// Update the texture matrix to point to the correct region in the atlas
 			ctx.m_dirLightTextureMatrices[cascade] = createSpotLightTextureMatrix(dirLightAtlasViewports[cascade]) * cascadeViewProjMats[cascade];
@@ -715,7 +721,7 @@ void ShadowMapping::createDrawShadowsPass(ConstWeakArray<ShadowSubpassInfo> subp
 				args.fill(meshletVisOut);
 			}
 
-			getRenderer().getSceneDrawer().drawMdi(args, cmdb);
+			getRenderer().getRenderableDrawer().drawMdi(args, cmdb);
 		}
 	});
 }

+ 9 - 19
AnKi/Renderer/Utils/GpuVisibility.cpp

@@ -361,10 +361,7 @@ void GpuVisibility::populateRenderGraphInternal(Bool distanceBased, BaseGpuVisib
 	out.m_dependency = mem.m_bufferDepedency;
 
 	// Create the renderpass
-	Array<Char, 128> passName;
-	snprintf(passName.getBegin(), passName.getSizeInBytes(), "GPU vis: %s", in.m_passesName.cstr());
-
-	ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass(passName.getBegin());
+	ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass(generateTempPassName("GPU vis: %s", in.m_passesName.cstr()));
 
 	pass.newBufferDependency(getRenderer().getGpuSceneBufferHandle(), BufferUsageBit::kStorageComputeRead);
 	pass.newBufferDependency(zeroStuffDependency, BufferUsageBit::kStorageComputeWrite);
@@ -567,10 +564,7 @@ void GpuVisibility::populateRenderGraphMeshletInternal(Bool passthrough, BaseGpu
 	// Zero some stuff
 	const BufferHandle indirectArgsDep = rgraph.importBuffer(out.m_drawIndirectArgsBuffer, BufferUsageBit::kNone);
 	{
-		Array<Char, 128> passName;
-		snprintf(passName.getBegin(), passName.getSizeInBytes(), "GPU meshlet vis zero: %s", in.m_passesName.cstr());
-
-		ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass(passName.getBegin());
+		ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass(generateTempPassName("GPU meshlet vis zero: %s", in.m_passesName.cstr()));
 		pass.newBufferDependency(indirectArgsDep, BufferUsageBit::kTransferDestination);
 
 		pass.setWork([drawIndirectArgsBuffer = out.m_drawIndirectArgsBuffer](RenderPassWorkContext& rpass) {
@@ -585,10 +579,7 @@ void GpuVisibility::populateRenderGraphMeshletInternal(Bool passthrough, BaseGpu
 	out.m_dependency = mem.m_bufferDepedency;
 
 	// Create the renderpass
-	Array<Char, 128> passName;
-	snprintf(passName.getBegin(), passName.getSizeInBytes(), "GPU meshlet vis: %s", in.m_passesName.cstr());
-
-	ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass(passName.getBegin());
+	ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass(generateTempPassName("GPU meshlet vis: %s", in.m_passesName.cstr()));
 
 	pass.newBufferDependency(indirectArgsDep, BufferUsageBit::kStorageComputeWrite);
 	pass.newBufferDependency(mem.m_bufferDepedency, BufferUsageBit::kStorageComputeWrite);
@@ -744,7 +735,8 @@ void GpuVisibilityNonRenderables::populateRenderGraph(GpuVisibilityNonRenderable
 
 		m_counterBufferZeroingHandle = rgraph.importBuffer(BufferView(m_counterBuffer.get()), buffInit.m_usage);
 
-		ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass("GpuVisibilityNonRenderablesClearCounterBuffer");
+		ComputeRenderPassDescription& pass =
+			rgraph.newComputeRenderPass(generateTempPassName("Non-renderables vis: Clear counter buff: %s", in.m_passesName.cstr()));
 
 		pass.newBufferDependency(m_counterBufferZeroingHandle, BufferUsageBit::kTransferDestination);
 
@@ -764,7 +756,7 @@ void GpuVisibilityNonRenderables::populateRenderGraph(GpuVisibilityNonRenderable
 	out.m_visiblesBufferHandle = rgraph.importBuffer(out.m_visiblesBuffer, BufferUsageBit::kNone);
 
 	// Create the renderpass
-	ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass(in.m_passesName);
+	ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass(generateTempPassName("Non-renderables vis: %s", in.m_passesName.cstr()));
 
 	pass.newBufferDependency(getRenderer().getGpuSceneBufferHandle(), BufferUsageBit::kStorageComputeRead);
 	pass.newBufferDependency(out.m_visiblesBufferHandle, BufferUsageBit::kStorageComputeWrite);
@@ -871,7 +863,7 @@ void GpuVisibilityAccelerationStructures::pupulateRenderGraph(GpuVisibilityAccel
 
 	// Create vis pass
 	{
-		ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass(in.m_passesName);
+		ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass(generateTempPassName("Accel vis: %s", in.m_passesName.cstr()));
 
 		pass.newBufferDependency(getRenderer().getGpuSceneBufferHandle(), BufferUsageBit::kStorageComputeRead);
 		pass.newBufferDependency(out.m_someBufferHandle, BufferUsageBit::kStorageComputeWrite);
@@ -918,10 +910,8 @@ void GpuVisibilityAccelerationStructures::pupulateRenderGraph(GpuVisibilityAccel
 
 	// Zero remaining instances
 	{
-		Array<Char, 64> passName;
-		snprintf(passName.getBegin(), sizeof(passName), "%s: Zero remaining instances", in.m_passesName.cstr());
-
-		ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass(passName.getBegin());
+		ComputeRenderPassDescription& pass =
+			rgraph.newComputeRenderPass(generateTempPassName("Accel vis zero remaining instances: %s", in.m_passesName.cstr()));
 
 		pass.newBufferDependency(out.m_someBufferHandle, BufferUsageBit::kStorageComputeWrite);
 

+ 1 - 1
AnKi/Renderer/Utils/HzbGenerator.cpp

@@ -256,7 +256,7 @@ void HzbGenerator::populateRenderGraphDirectionalLight(const HzbDirectionalLight
 			ANKI_ASSERT(cascadeMinDepth <= cascadeMaxDepth);
 		}
 
-		RenderTargetDescription depthRtDescr(generateTempPassName("HZB boxes depth", i));
+		RenderTargetDescription depthRtDescr(generateTempPassName("HZB boxes depth cascade:%u", i));
 		depthRtDescr.m_width = cascade.m_hzbRtSize.x() * 2;
 		depthRtDescr.m_height = cascade.m_hzbRtSize.y() * 2;
 		depthRtDescr.m_format = Format::kD16_Unorm;

+ 60 - 0
AnKi/Renderer/Utils/MipmapGenerator.cpp

@@ -0,0 +1,60 @@
+// Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <AnKi/Renderer/Utils/MipmapGenerator.h>
+#include <AnKi/Renderer/Renderer.h>
+#include <AnKi/Util/Tracer.h>
+
+namespace anki {
+
+Error MipmapGenerator::init()
+{
+	ANKI_CHECK(loadShaderProgram("ShaderBinaries/MipmapGenerator.ankiprogbin", m_genMipsProg, m_genMipsGrProg));
+
+	return Error::kNone;
+}
+
+void MipmapGenerator::populateRenderGraph(const MipmapGeneratorTargetArguments& target, RenderGraphDescription& rgraph, CString passesName)
+{
+	for(U32 readMip = 0; readMip < target.m_mipmapCount - 1u; ++readMip)
+	{
+		const U8 faceCount = (target.m_isCubeTexture) ? 6 : 1;
+		for(U32 face = 0; face < faceCount; ++face)
+		{
+			for(U32 layer = 0; layer < target.m_layerCount; ++layer)
+			{
+				GraphicsRenderPassDescription& rpass =
+					rgraph.newGraphicsRenderPass(generateTempPassName("%s: mip #%u face #%u layer #%u", passesName.cstr(), readMip, face, layer));
+
+				rpass.newTextureDependency(target.m_handle, TextureUsageBit::kSampledFragment,
+										   TextureSubresourceDescriptor::surface(readMip, face, layer));
+				rpass.newTextureDependency(target.m_handle, TextureUsageBit::kFramebufferWrite,
+										   TextureSubresourceDescriptor::surface(readMip + 1, face, layer));
+
+				RenderTargetInfo rtInfo;
+				rtInfo.m_handle = target.m_handle;
+				rtInfo.m_subresource = TextureSubresourceDescriptor::surface(readMip + 1, face, layer);
+				rpass.setRenderpassInfo({rtInfo});
+
+				rpass.setWork([this, rt = target.m_handle, readMip, face, layer,
+							   viewport = target.m_targetSize >> (readMip + 1)](RenderPassWorkContext& rgraphCtx) {
+					ANKI_TRACE_SCOPED_EVENT(MipmapGenerator);
+
+					CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
+
+					cmdb.bindShaderProgram(m_genMipsGrProg.get());
+					cmdb.setViewport(0, 0, viewport.x(), viewport.y());
+
+					rgraphCtx.bindTexture(ANKI_REG(t0), rt, TextureSubresourceDescriptor::surface(readMip, face, layer));
+					cmdb.bindSampler(ANKI_REG(s0), getRenderer().getSamplers().m_trilinearClamp.get());
+
+					drawQuad(cmdb);
+				});
+			}
+		}
+	}
+}
+
+} // end namespace anki

+ 40 - 0
AnKi/Renderer/Utils/MipmapGenerator.h

@@ -0,0 +1,40 @@
+// Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <AnKi/Renderer/RendererObject.h>
+
+namespace anki {
+
+/// @addtogroup renderer
+/// @{
+
+/// @memberof MipmapGenerator
+class MipmapGeneratorTargetArguments
+{
+public:
+	RenderTargetHandle m_handle;
+	UVec2 m_targetSize = UVec2(0u); ///< Size of the 1st mip
+	U32 m_layerCount = 1;
+	U8 m_mipmapCount = 0;
+	Bool m_isCubeTexture = false;
+};
+
+/// Generates a mipmap chain.
+class MipmapGenerator : public RendererObject
+{
+public:
+	Error init();
+
+	void populateRenderGraph(const MipmapGeneratorTargetArguments& target, RenderGraphDescription& rgraph, CString passesName = {});
+
+private:
+	ShaderProgramResourcePtr m_genMipsProg;
+	ShaderProgramPtr m_genMipsGrProg;
+};
+/// @}
+
+} // end namespace anki

+ 6 - 0
AnKi/Renderer/Utils/Readback.h

@@ -28,6 +28,12 @@ private:
 class ReadbackManager
 {
 public:
+	Error init()
+	{
+		// Just for the interface
+		return Error::kNone;
+	}
+
 	/// Read the most up to date data from the GPU. 1st thing to call in a frame.
 	void readMostRecentData(const MultiframeReadbackToken& token, void* data, PtrSize dataSize, PtrSize& dataOut) const;
 

+ 1 - 1
AnKi/Scene/Components/ReflectionProbeComponent.cpp

@@ -29,7 +29,7 @@ ReflectionProbeComponent::ReflectionProbeComponent(SceneNode* node)
 	texInit.m_mipmapCount = U8(computeMaxMipmapCount2d(texInit.m_width, texInit.m_height, 8));
 	texInit.m_type = TextureType::kCube;
 	texInit.m_usage = TextureUsageBit::kAllSampled | TextureUsageBit::kStorageComputeWrite | TextureUsageBit::kStorageComputeRead
-					  | TextureUsageBit::kAllFramebuffer | TextureUsageBit::kGenerateMipmaps;
+					  | TextureUsageBit::kAllFramebuffer;
 
 	m_reflectionTex = GrManager::getSingleton().newTexture(texInit);
 

+ 6 - 6
AnKi/Shaders/Intellisense.hlsl

@@ -30,12 +30,12 @@
 #define ANKI_END_NAMESPACE
 #define ANKI_HLSL 1
 
-#define ANKI_TASK_SHADER
-#define ANKI_VERTEX_SHADER
-#define ANKI_FRAGMENT_SHADER
-#define ANKI_MESH_SHADER
-#define ANKI_COMPUTE_SHADER
-#define ANKI_CLOSEST_HIT_SHADER
+#define ANKI_TASK_SHADER 1
+#define ANKI_VERTEX_SHADER 1
+#define ANKI_FRAGMENT_SHADER 1
+#define ANKI_MESH_SHADER 1
+#define ANKI_COMPUTE_SHADER 1
+#define ANKI_CLOSEST_HIT_SHADER 1
 
 using I8 = int;
 using I16 = int;

+ 20 - 0
AnKi/Shaders/MipmapGenerator.ankiprog

@@ -0,0 +1,20 @@
+// Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma anki technique_start vert
+#include <AnKi/Shaders/QuadVert.hlsl>
+#pragma anki technique_end vert
+
+#pragma anki technique_start frag
+#include <AnKi/Shaders/Common.hlsl>
+
+Texture2D<Vec4> g_inputTex : register(t0);
+SamplerState g_linearAnyClampSampler : register(s0);
+
+Vec4 main(Vec2 uv : TEXCOORD) : SV_TARGET0
+{
+	return g_inputTex.SampleLevel(g_linearAnyClampSampler, uv, 0.0f);
+}
+#pragma anki technique_end frag

+ 2 - 0
AnKi/Shaders/MotionVectors.ankiprog

@@ -5,6 +5,8 @@
 
 // Calculates the motion vectors that will be used to sample from the previous frame
 
+#include <AnKi/Shaders/Common.hlsl>
+
 #if ANKI_COMPUTE_SHADER || ANKI_FRAGMENT_SHADER
 #	include <AnKi/Shaders/Functions.hlsl>
 

+ 1 - 8
AnKi/Ui/Font.cpp

@@ -74,7 +74,7 @@ void Font::createTexture(const void* data, U32 width, U32 height)
 	texInit.m_width = width;
 	texInit.m_height = height;
 	texInit.m_format = Format::kR8G8B8A8_Unorm;
-	texInit.m_usage = TextureUsageBit::kTransferDestination | TextureUsageBit::kSampledFragment | TextureUsageBit::kGenerateMipmaps;
+	texInit.m_usage = TextureUsageBit::kTransferDestination | TextureUsageBit::kSampledFragment;
 	texInit.m_mipmapCount = 1; // No mips because it will appear blurry with trilinear filtering
 
 	m_tex = GrManager::getSingleton().newTexture(texInit);
@@ -96,13 +96,6 @@ void Font::createTexture(const void* data, U32 width, U32 height)
 	cmdb->copyBufferToTexture(BufferView(buff.get()), firstMipView);
 
 	barrier.m_previousUsage = TextureUsageBit::kTransferDestination;
-	barrier.m_nextUsage = TextureUsageBit::kGenerateMipmaps;
-	cmdb->setPipelineBarrier({&barrier, 1}, {}, {});
-
-	// Gen mips
-	cmdb->generateMipmaps2d(firstMipView);
-
-	barrier.m_previousUsage = TextureUsageBit::kGenerateMipmaps;
 	barrier.m_nextUsage = TextureUsageBit::kSampledFragment;
 	cmdb->setPipelineBarrier({&barrier, 1}, {}, {});