Browse Source

Some new render graph features. Some vulkan validation fixes

Panagiotis Christopoulos Charitos 6 years ago
parent
commit
d33190d4d2

+ 13 - 1
shaders/ClearTextureCompute.glslp

@@ -10,7 +10,7 @@
 #pragma anki start comp
 #include <shaders/Common.glsl>
 
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+layout(local_size_x = 8, local_size_y = 8, local_size_z = (IS_2D == 1) ? 1 : 8) in;
 
 layout(push_constant) uniform pc_
 {
@@ -26,8 +26,20 @@ layout(set = 0, binding = 0) uniform writeonly image3D u_img;
 void main()
 {
 #if IS_2D
+	const UVec2 size = UVec2(imageSize(u_img));
+	if(gl_GlobalInvocationID.x >= size.x || gl_GlobalInvocationID.y >= size.y)
+	{
+		return;
+	}
+
 	imageStore(u_img, IVec2(gl_GlobalInvocationID.xy), u_clearColor);
 #else
+	const UVec3 size = UVec3(imageSize(u_img));
+	if(gl_GlobalInvocationID.x >= size.x || gl_GlobalInvocationID.y >= size.y || gl_GlobalInvocationID.z >= size.z)
+	{
+		return;
+	}
+
 	imageStore(u_img, IVec3(gl_GlobalInvocationID), u_clearColor);
 #endif
 }

+ 4 - 4
shaders/IrradianceDice.glslp

@@ -24,7 +24,7 @@ layout(set = 0, binding = 0) uniform sampler u_nearestAnyClampSampler;
 #if LIGHT_SHADING_TEX == 0
 layout(set = 0, binding = 1) uniform texture2D u_lightShadingTex;
 #else
-layout(set = 0, binding = 1) uniform textureCubeArray u_lightShadingTex;
+layout(set = 0, binding = 1) uniform textureCube u_lightShadingTex;
 #endif
 
 #if SECOND_BOUNCE == 1
@@ -66,9 +66,8 @@ Vec3 sampleLightShadingTexture(const U32 face)
 	const Vec2 uv = (Vec2(gl_LocalInvocationID.x, gl_LocalInvocationID.y) + 0.5) / F32(WORKGROUP_SIZE);
 	const Vec2 ndc = UV_TO_NDC(uv);
 	const Vec3 cubeUvw = getCubemapDirection(ndc, face);
-	const F32 layerIdx = 0.0; // The C++ code sets the right layer in the view.
 
-	return textureLod(u_lightShadingTex, u_nearestAnyClampSampler, Vec4(cubeUvw, 0.0), 0.0).rgb;
+	return textureLod(u_lightShadingTex, u_nearestAnyClampSampler, cubeUvw, 0.0).rgb;
 #endif
 }
 
@@ -142,7 +141,8 @@ void main()
 		gbufferUv.x *= 1.0 / 6.0;
 		gbufferUv.x += (1.0 / 6.0) * F32(f);
 		GbufferInfo gbuffer;
-		readGBuffer(u_gbufferTex[0u], u_gbufferTex[1u], u_gbufferTex[2u], u_nearestAnyClampSampler, gbufferUv, 0.0, gbuffer);
+		readGBuffer(
+			u_gbufferTex[0u], u_gbufferTex[1u], u_gbufferTex[2u], u_nearestAnyClampSampler, gbufferUv, 0.0, gbuffer);
 
 		// Sample irradiance
 		Vec3 firstBounceIrradiance = sampleAmbientDice(s_diceIrradiance[0],

+ 1 - 1
shaders/Pack.glsl

@@ -189,5 +189,5 @@ void readGBuffer(texture2D rt0, texture2D rt1, texture2D rt2, sampler sampl, Vec
 	g.m_specular = mix(g.m_specular, g.m_diffuse, g.m_metallic);
 
 	// Compute diffuse
-	g.m_diffuse = g.m_diffuse - g.m_diffuse * g.m_metallic;
+	g.m_diffuse *= 1.0 - g.m_metallic;
 }

+ 7 - 1
src/anki/Config.h.cmake

@@ -156,7 +156,9 @@
 #	define ANKI_UNUSED __attribute__((__unused__))
 #	define ANKI_COLD __attribute__((cold, optimize("Os")))
 #	define ANKI_HOT __attribute__ ((hot))
-#else
+#	define ANKI_UNREACHABLE() __builtin_unreachable()
+#	define ANKI_PREFETCH_MEMORY(addr) __builtin_prefetch(addr)
+#elif defined(_MSC_VER)
 #	define ANKI_LIKELY(x) ((x) == 1)
 #	define ANKI_UNLIKELY(x) ((x) == 1)
 #	define ANKI_RESTRICT
@@ -166,6 +168,10 @@
 #	define ANKI_UNUSED
 #	define ANKI_COLD
 #	define ANKI_HOT
+#	define ANKI_UNREACHABLE() __assume(false)
+#	define ANKI_PREFETCH_MEMORY(addr) (void)(addr)
+#else
+#	error Unsupported compiler
 #endif
 
 // Pack structs

+ 72 - 14
src/anki/gr/RenderGraph.cpp

@@ -19,6 +19,11 @@ namespace anki
 
 #define ANKI_DBG_RENDER_GRAPH 0
 
+static inline U getTextureSurfOrVolCount(const TexturePtr& tex)
+{
+	return tex->getMipmapCount() * tex->getLayerCount() * (textureTypeIsCube(tex->getTextureType()) ? 6 : 1);
+}
+
 /// Contains some extra things for render targets.
 class RenderGraph::RT
 {
@@ -26,6 +31,7 @@ public:
 	DynamicArray<TextureUsageBit> m_surfOrVolUsages;
 	DynamicArray<U16> m_lastBatchThatTransitionedIt;
 	TexturePtr m_texture; ///< Hold a reference.
+	Bool m_imported;
 };
 
 /// Same as RT but for buffers.
@@ -259,8 +265,38 @@ void RenderGraph::reset()
 		periodicCleanup();
 	}
 
+	// Extract the final usage of the imported RTs and clean all RTs
 	for(RT& rt : m_ctx->m_rts)
 	{
+		if(rt.m_imported)
+		{
+			const U surfOrVolumeCount = getTextureSurfOrVolCount(rt.m_texture);
+
+			// Create a new hash because our hash map dislikes concurent keys.
+			const U64 uuid = rt.m_texture->getUuid();
+			const U64 hash = computeHash(&uuid, sizeof(uuid));
+
+			auto it = m_importedRenderTargets.find(hash);
+			if(it != m_importedRenderTargets.getEnd())
+			{
+				// Found
+				ANKI_ASSERT(it->m_surfOrVolLastUsages.getSize() == surfOrVolumeCount);
+				ANKI_ASSERT(rt.m_surfOrVolUsages.getSize() == surfOrVolumeCount);
+			}
+			else
+			{
+				// Not found, create
+				it = m_importedRenderTargets.emplace(getAllocator(), hash);
+				it->m_surfOrVolLastUsages.create(getAllocator(), surfOrVolumeCount);
+			}
+
+			// Update the usage
+			for(U surfOrVolIdx = 0; surfOrVolIdx < surfOrVolumeCount; ++surfOrVolIdx)
+			{
+				it->m_surfOrVolLastUsages[surfOrVolIdx] = rt.m_surfOrVolUsages[surfOrVolIdx];
+			}
+		}
+
 		rt.m_texture.reset(nullptr);
 	}
 
@@ -564,39 +600,61 @@ RenderGraph::BakeContext* RenderGraph::newContext(const RenderGraphDescription&
 	for(U rtIdx = 0; rtIdx < ctx->m_rts.getSize(); ++rtIdx)
 	{
 		RT& outRt = ctx->m_rts[rtIdx];
+		const RenderGraphDescription::RT& inRt = descr.m_renderTargets[rtIdx];
 
-		TexturePtr tex;
-		Bool imported = descr.m_renderTargets[rtIdx].m_importedTex.isCreated();
+		const Bool imported = inRt.m_importedTex.isCreated();
 		if(imported)
 		{
 			// It's imported
-			tex = descr.m_renderTargets[rtIdx].m_importedTex;
+			outRt.m_texture = inRt.m_importedTex;
 		}
 		else
 		{
 			// Need to create new
 
 			// Create a new TextureInitInfo with the derived usage
-			TextureInitInfo initInf = descr.m_renderTargets[rtIdx].m_initInfo;
-			initInf.m_usage = descr.m_renderTargets[rtIdx].m_usageDerivedByDeps;
+			TextureInitInfo initInf = inRt.m_initInfo;
+			initInf.m_usage = inRt.m_usageDerivedByDeps;
 			ANKI_ASSERT(initInf.m_usage != TextureUsageBit::NONE);
 
 			// Create the new hash
-			const U64 hash = appendHash(&initInf.m_usage, sizeof(initInf.m_usage), descr.m_renderTargets[rtIdx].m_hash);
+			const U64 hash = appendHash(&initInf.m_usage, sizeof(initInf.m_usage), inRt.m_hash);
 
 			// Get or create the texture
-			tex = getOrCreateRenderTarget(initInf, hash);
+			outRt.m_texture = getOrCreateRenderTarget(initInf, hash);
 		}
 
-		outRt.m_texture = tex;
+		// Init the usage
+		const U surfOrVolumeCount = getTextureSurfOrVolCount(outRt.m_texture);
+		outRt.m_surfOrVolUsages.create(alloc, surfOrVolumeCount, TextureUsageBit::NONE);
+		if(imported && inRt.m_importedAndUndefinedUsage)
+		{
+			// Get the usage from previous frames
+
+			// Create a new hash because our hash map dislikes concurent keys.
+			const U64 uuid = outRt.m_texture->getUuid();
+			const U64 hash = computeHash(&uuid, sizeof(uuid));
+
+			auto it = m_importedRenderTargets.find(hash);
+			ANKI_ASSERT(it != m_importedRenderTargets.getEnd() && "Can't find the imported RT");
+
+			ANKI_ASSERT(it->m_surfOrVolLastUsages.getSize() == surfOrVolumeCount);
+			for(U surfOrVolIdx = 0; surfOrVolIdx < surfOrVolumeCount; ++surfOrVolIdx)
+			{
+				outRt.m_surfOrVolUsages[surfOrVolIdx] = it->m_surfOrVolLastUsages[surfOrVolIdx];
+			}
+		}
+		else if(imported)
+		{
+			// Set the usage that was given by the user
+			for(U surfOrVolIdx = 0; surfOrVolIdx < surfOrVolumeCount; ++surfOrVolIdx)
+			{
+				outRt.m_surfOrVolUsages[surfOrVolIdx] = inRt.m_importedLastKnownUsage;
+			}
+		}
 
-		// Init the surfs or volumes
-		const U surfOrVolumeCount =
-			tex->getMipmapCount() * tex->getLayerCount() * (textureTypeIsCube(tex->getTextureType()) ? 6 : 1);
-		outRt.m_surfOrVolUsages.create(alloc,
-			surfOrVolumeCount,
-			(imported) ? descr.m_renderTargets[rtIdx].m_importedLastKnownUsage : TextureUsageBit::NONE);
 		outRt.m_lastBatchThatTransitionedIt.create(alloc, surfOrVolumeCount, MAX_U16);
+		outRt.m_imported = imported;
 	}
 
 	// Buffers

+ 33 - 110
src/anki/gr/RenderGraph.h

@@ -404,40 +404,10 @@ public:
 	void setFramebufferInfo(const FramebufferDescription& fbInfo,
 		const Array<RenderTargetHandle, MAX_COLOR_ATTACHMENTS>& colorRenderTargetHandles,
 		RenderTargetHandle depthStencilRenderTargetHandle,
-		U32 minx = 0,
-		U32 miny = 0,
-		U32 maxx = MAX_U32,
-		U32 maxy = MAX_U32)
-	{
-#if ANKI_EXTRA_CHECKS
-		ANKI_ASSERT(fbInfo.isBacked() && "Forgot call GraphicsRenderPassFramebufferInfo::bake");
-		for(U i = 0; i < colorRenderTargetHandles.getSize(); ++i)
-		{
-			if(i >= fbInfo.m_colorAttachmentCount)
-			{
-				ANKI_ASSERT(!colorRenderTargetHandles[i].isValid());
-			}
-			else
-			{
-				ANKI_ASSERT(colorRenderTargetHandles[i].isValid());
-			}
-		}
-
-		if(!fbInfo.m_depthStencilAttachment.m_aspect)
-		{
-			ANKI_ASSERT(!depthStencilRenderTargetHandle.isValid());
-		}
-		else
-		{
-			ANKI_ASSERT(depthStencilRenderTargetHandle.isValid());
-		}
-#endif
-
-		m_fbDescr = fbInfo;
-		memcpy(&m_rtHandles[0], &colorRenderTargetHandles[0], sizeof(colorRenderTargetHandles));
-		m_rtHandles[MAX_COLOR_ATTACHMENTS] = depthStencilRenderTargetHandle;
-		m_fbRenderArea = {{minx, miny, maxx, maxy}};
-	}
+		U32 minx,
+		U32 miny,
+		U32 maxx,
+		U32 maxy);
 
 private:
 	Array<RenderTargetHandle, MAX_COLOR_ATTACHMENTS + 1> m_rtHandles;
@@ -482,81 +452,26 @@ public:
 	{
 	}
 
-	~RenderGraphDescription()
-	{
-		for(RenderPassDescriptionBase* pass : m_passes)
-		{
-			m_alloc.deleteInstance(pass);
-		}
-		m_passes.destroy(m_alloc);
-		m_renderTargets.destroy(m_alloc);
-		m_buffers.destroy(m_alloc);
-	}
+	~RenderGraphDescription();
 
 	/// Create a new graphics render pass.
-	GraphicsRenderPassDescription& newGraphicsRenderPass(CString name)
-	{
-		GraphicsRenderPassDescription* pass = m_alloc.newInstance<GraphicsRenderPassDescription>(this);
-		pass->m_alloc = m_alloc;
-		pass->setName(name);
-		m_passes.emplaceBack(m_alloc, pass);
-		return *pass;
-	}
+	GraphicsRenderPassDescription& newGraphicsRenderPass(CString name);
 
 	/// Create a new compute render pass.
-	ComputeRenderPassDescription& newComputeRenderPass(CString name)
-	{
-		ComputeRenderPassDescription* pass = m_alloc.newInstance<ComputeRenderPassDescription>(this);
-		pass->m_alloc = m_alloc;
-		pass->setName(name);
-		m_passes.emplaceBack(m_alloc, pass);
-		return *pass;
-	}
+	ComputeRenderPassDescription& newComputeRenderPass(CString name);
 
-	/// Import an existing render target.
-	RenderTargetHandle importRenderTarget(TexturePtr tex, TextureUsageBit usage)
-	{
-		RT& rt = *m_renderTargets.emplaceBack(m_alloc);
-		rt.m_importedTex = tex;
-		rt.m_importedLastKnownUsage = usage;
-		rt.m_usageDerivedByDeps = TextureUsageBit::NONE;
-		rt.setName(tex->getName());
+	/// Import an existing render target and let the render graph know about it's up-to-date usage.
+	RenderTargetHandle importRenderTarget(TexturePtr tex, TextureUsageBit usage);
 
-		RenderTargetHandle out;
-		out.m_idx = m_renderTargets.getSize() - 1;
-		return out;
-	}
+	/// Import an existing render target and let the render graph find it's current usage by looking at the previous
+	/// frame.
+	RenderTargetHandle importRenderTarget(TexturePtr tex);
 
 	/// Get or create a new render target.
-	RenderTargetHandle newRenderTarget(const RenderTargetDescription& initInf)
-	{
-		ANKI_ASSERT(initInf.m_hash && "Forgot to call RenderTargetDescription::bake");
-		ANKI_ASSERT(
-			initInf.m_usage == TextureUsageBit::NONE && "Don't need to supply the usage. Render grap will find it");
-		RT& rt = *m_renderTargets.emplaceBack(m_alloc);
-		rt.m_initInfo = initInf;
-		rt.m_hash = initInf.m_hash;
-		rt.m_importedLastKnownUsage = TextureUsageBit::NONE;
-		rt.m_usageDerivedByDeps = TextureUsageBit::NONE;
-		rt.setName(initInf.getName());
-
-		RenderTargetHandle out;
-		out.m_idx = m_renderTargets.getSize() - 1;
-		return out;
-	}
+	RenderTargetHandle newRenderTarget(const RenderTargetDescription& initInf);
 
 	/// Import a buffer.
-	RenderPassBufferHandle importBuffer(BufferPtr buff, BufferUsageBit usage)
-	{
-		Buffer& b = *m_buffers.emplaceBack(m_alloc);
-		b.setName(buff->getName());
-		b.m_usage = usage;
-		b.m_importedBuff = buff;
-
-		RenderPassBufferHandle out;
-		out.m_idx = m_buffers.getSize() - 1;
-		return out;
-	}
+	RenderPassBufferHandle importBuffer(BufferPtr buff, BufferUsageBit usage);
 
 private:
 	class Resource
@@ -579,7 +494,8 @@ private:
 		U64 m_hash = 0;
 		TexturePtr m_importedTex;
 		TextureUsageBit m_importedLastKnownUsage;
-		TextureUsageBit m_usageDerivedByDeps; ///< XXX
+		TextureUsageBit m_usageDerivedByDeps; ///< Derived by the deps of this RT and will be used to set its usage.
+		Bool m_importedAndUndefinedUsage = false;
 	};
 
 	class Buffer : public Resource
@@ -646,7 +562,15 @@ public:
 	/// @}
 
 private:
-	static constexpr U PERIODIC_CLEANUP_EVERY = 60; ///< How many frames between cleanups
+	static constexpr U PERIODIC_CLEANUP_EVERY = 60; ///< How many frames between cleanups.
+
+	// Forward declarations of internal classes.
+	class BakeContext;
+	class Pass;
+	class Batch;
+	class RT;
+	class Buffer;
+	class Barrier;
 
 	/// Render targets of the same type+size+format.
 	class RenderTargetCacheEntry
@@ -656,17 +580,16 @@ private:
 		U32 m_texturesInUse = 0;
 	};
 
-	HashMap<U64, RenderTargetCacheEntry> m_renderTargetCache; ///< Non-imported render targets.
+	/// Info on imported render targets that are kept between runs.
+	class ImportedRenderTargetInfo
+	{
+	public:
+		DynamicArray<TextureUsageBit> m_surfOrVolLastUsages; ///< Last TextureUsageBit of the imported RT.
+	};
 
+	HashMap<U64, RenderTargetCacheEntry> m_renderTargetCache; ///< Non-imported render targets.
 	HashMap<U64, FramebufferPtr> m_fbCache; ///< Framebuffer cache.
-
-	// Forward declarations
-	class BakeContext;
-	class Pass;
-	class Batch;
-	class RT;
-	class Buffer;
-	class Barrier;
+	HashMap<U64, ImportedRenderTargetInfo> m_importedRenderTargets;
 
 	BakeContext* m_ctx = nullptr;
 	U64 m_version = 0;

+ 127 - 0
src/anki/gr/RenderGraph.inl.h

@@ -128,4 +128,131 @@ inline void RenderPassDescriptionBase::newDependency(const RenderPassDependency&
 	}
 }
 
+inline void GraphicsRenderPassDescription::setFramebufferInfo(const FramebufferDescription& fbInfo,
+	const Array<RenderTargetHandle, MAX_COLOR_ATTACHMENTS>& colorRenderTargetHandles,
+	RenderTargetHandle depthStencilRenderTargetHandle,
+	U32 minx = 0,
+	U32 miny = 0,
+	U32 maxx = MAX_U32,
+	U32 maxy = MAX_U32)
+{
+#if ANKI_ASSERTS_ENABLED
+	ANKI_ASSERT(fbInfo.isBacked() && "Forgot call GraphicsRenderPassFramebufferInfo::bake");
+	for(U i = 0; i < colorRenderTargetHandles.getSize(); ++i)
+	{
+		if(i >= fbInfo.m_colorAttachmentCount)
+		{
+			ANKI_ASSERT(!colorRenderTargetHandles[i].isValid());
+		}
+		else
+		{
+			ANKI_ASSERT(colorRenderTargetHandles[i].isValid());
+		}
+	}
+
+	if(!fbInfo.m_depthStencilAttachment.m_aspect)
+	{
+		ANKI_ASSERT(!depthStencilRenderTargetHandle.isValid());
+	}
+	else
+	{
+		ANKI_ASSERT(depthStencilRenderTargetHandle.isValid());
+	}
+#endif
+
+	m_fbDescr = fbInfo;
+	memcpy(&m_rtHandles[0], &colorRenderTargetHandles[0], sizeof(colorRenderTargetHandles));
+	m_rtHandles[MAX_COLOR_ATTACHMENTS] = depthStencilRenderTargetHandle;
+	m_fbRenderArea = {{minx, miny, maxx, maxy}};
+}
+
+inline RenderGraphDescription::~RenderGraphDescription()
+{
+	for(RenderPassDescriptionBase* pass : m_passes)
+	{
+		m_alloc.deleteInstance(pass);
+	}
+	m_passes.destroy(m_alloc);
+	m_renderTargets.destroy(m_alloc);
+	m_buffers.destroy(m_alloc);
+}
+
+inline GraphicsRenderPassDescription& RenderGraphDescription::newGraphicsRenderPass(CString name)
+{
+	GraphicsRenderPassDescription* pass = m_alloc.newInstance<GraphicsRenderPassDescription>(this);
+	pass->m_alloc = m_alloc;
+	pass->setName(name);
+	m_passes.emplaceBack(m_alloc, pass);
+	return *pass;
+}
+
+inline ComputeRenderPassDescription& RenderGraphDescription::newComputeRenderPass(CString name)
+{
+	ComputeRenderPassDescription* pass = m_alloc.newInstance<ComputeRenderPassDescription>(this);
+	pass->m_alloc = m_alloc;
+	pass->setName(name);
+	m_passes.emplaceBack(m_alloc, pass);
+	return *pass;
+}
+
+inline RenderTargetHandle RenderGraphDescription::importRenderTarget(TexturePtr tex, TextureUsageBit usage)
+{
+	for(const RT& rt : m_renderTargets)
+	{
+		(void)rt;
+		ANKI_ASSERT(rt.m_importedTex != tex && "Already imported");
+	}
+
+	RT& rt = *m_renderTargets.emplaceBack(m_alloc);
+	rt.m_importedTex = tex;
+	rt.m_importedLastKnownUsage = usage;
+	rt.m_usageDerivedByDeps = TextureUsageBit::NONE;
+	rt.setName(tex->getName());
+
+	RenderTargetHandle out;
+	out.m_idx = m_renderTargets.getSize() - 1;
+	return out;
+}
+
+inline RenderTargetHandle RenderGraphDescription::importRenderTarget(TexturePtr tex)
+{
+	RenderTargetHandle out = importRenderTarget(tex, TextureUsageBit::NONE);
+	m_renderTargets.getBack().m_importedAndUndefinedUsage = true;
+	return out;
+}
+
+inline RenderTargetHandle RenderGraphDescription::newRenderTarget(const RenderTargetDescription& initInf)
+{
+	ANKI_ASSERT(initInf.m_hash && "Forgot to call RenderTargetDescription::bake");
+	ANKI_ASSERT(initInf.m_usage == TextureUsageBit::NONE && "Don't need to supply the usage. Render grap will find it");
+	RT& rt = *m_renderTargets.emplaceBack(m_alloc);
+	rt.m_initInfo = initInf;
+	rt.m_hash = initInf.m_hash;
+	rt.m_importedLastKnownUsage = TextureUsageBit::NONE;
+	rt.m_usageDerivedByDeps = TextureUsageBit::NONE;
+	rt.setName(initInf.getName());
+
+	RenderTargetHandle out;
+	out.m_idx = m_renderTargets.getSize() - 1;
+	return out;
+}
+
+inline RenderPassBufferHandle RenderGraphDescription::importBuffer(BufferPtr buff, BufferUsageBit usage)
+{
+	for(const Buffer& bb : m_buffers)
+	{
+		(void)bb;
+		ANKI_ASSERT(bb.m_importedBuff != buff && "Already imported");
+	}
+
+	Buffer& b = *m_buffers.emplaceBack(m_alloc);
+	b.setName(buff->getName());
+	b.m_usage = usage;
+	b.m_importedBuff = buff;
+
+	RenderPassBufferHandle out;
+	out.m_idx = m_buffers.getSize() - 1;
+	return out;
+}
+
 } // end namespace anki

+ 1 - 7
src/anki/gr/vulkan/GrManagerImpl.cpp

@@ -232,13 +232,7 @@ Error GrManagerImpl::initInstance(const GrManagerInitInfo& init)
 	ci.pApplicationInfo = &app;
 
 	// Layers
-	static Array<const char*, 7> LAYERS = {{"VK_LAYER_LUNARG_core_validation",
-		"VK_LAYER_LUNARG_swapchain",
-		"VK_LAYER_GOOGLE_threading",
-		"VK_LAYER_LUNARG_parameter_validation",
-		"VK_LAYER_LUNARG_object_tracker",
-		"VK_LAYER_LUNARG_standard_validation",
-		"VK_LAYER_GOOGLE_unique_objects"}};
+	static Array<const char*, 1> LAYERS = {{"VK_LAYER_KHRONOS_validation"}};
 	Array<const char*, LAYERS.getSize()> layersToEnable; // Keep it alive in the stack
 	if(init.m_config->getNumber("window.debugContext"))
 	{

+ 6 - 2
src/anki/renderer/Renderer.cpp

@@ -525,8 +525,12 @@ TexturePtr Renderer::createAndClearRenderTarget(const TextureInitInfo& inf, cons
 					cmdb->setTextureSurfaceBarrier(
 						tex, TextureUsageBit::NONE, TextureUsageBit::IMAGE_COMPUTE_WRITE, surf);
 
-					const U wgSizeZ = (inf.m_type == TextureType::_3D) ? (tex->getDepth() >> mip) : 1;
-					cmdb->dispatchCompute(tex->getWidth() >> mip, tex->getHeight() >> mip, wgSizeZ);
+					UVec3 wgSize;
+					wgSize.x() = (8 - 1 + (tex->getWidth() >> mip)) / 8;
+					wgSize.y() = (8 - 1 + (tex->getHeight() >> mip)) / 8;
+					wgSize.z() = (inf.m_type == TextureType::_3D) ? ((8 - 1 + (tex->getDepth() >> mip)) / 8) : 1;
+
+					cmdb->dispatchCompute(wgSize.x(), wgSize.y(), wgSize.z());
 
 					if(!!inf.m_initialUsage)
 					{

+ 1 - 0
src/anki/util/Assert.h

@@ -26,6 +26,7 @@ void akassert(const char* exprTxt, const char* file, int line, const char* func)
 			if(!(x)) \
 			{ \
 				anki::akassert(#x, ANKI_FILE, __LINE__, ANKI_FUNC); \
+				ANKI_UNREACHABLE(); \
 			} \
 		} while(0)
 #	define ANKI_ASSERTS_ENABLED 1