Browse Source

Complete the work on the RT shader compiling

Panagiotis Christopoulos Charitos 5 years ago
parent
commit
93092e91cb

+ 0 - 1
docs/code_style.md

@@ -68,7 +68,6 @@ In GLSL there are more exceptions:
 - All output globals the `out_` prefix.
 - All output globals the `out_` prefix.
 - All shared storage the `s_` prefix.
 - All shared storage the `s_` prefix.
 - All blocks (storage or uniform) block names the  `b_` prefix.
 - All blocks (storage or uniform) block names the  `b_` prefix.
-- All payloads the `p_` prefix.
 
 
 **Variables that act as a measure for quantity** should have the `count` suffix. Not `num` or `numberOf` or similar.
 **Variables that act as a measure for quantity** should have the `count` suffix. Not `num` or `numberOf` or similar.
 
 

+ 0 - 69
shaders/RtShadows.ankiprog

@@ -1,69 +0,0 @@
-// Copyright (C) 2009-2020, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#pragma anki library RtShadows
-#pragma anki sub_library Main
-
-#pragma anki mutator ALPHA_TEXTURE 0 1
-
-#include <shaders/Common.glsl>
-#include <shaders/glsl_cpp_common/Model.h>
-
-struct Payload
-{
-	F32 m_shadowFactor;
-};
-
-#if ALPHA_TEXTURE == 1
-layout(set = 0, binding = 0, scalar) buffer b_ankiModelInstances
-{
-	ModelInstance u_ankiModelInstances[];
-};
-
-layout(set = 0, binding = 1) uniform texture2D u_diffTex;
-layout(set = 0, binding = 2) uniform sampler u_ankiGlobalSampler;
-
-ANKI_BINDLESS_SET(1);
-#endif
-
-#pragma anki start ahit
-
-layout(location = 0) rayPayloadInEXT Payload p_payload;
-
-hitAttributeEXT vec2 g_attribs;
-
-ANKI_REF(U16Vec3, 2);
-ANKI_REF(Vertex, 4);
-
-void main()
-{
-#if ALPHA_TEXTURE == 1
-	const Mesh mesh = u_ankiModelInstances[nonuniformEXT(gl_InstanceID)].m_mesh;
-
-	const U32 offset = gl_PrimitiveID * ANKI_SIZEOF(U16Vec3);
-	const U16Vec3 indices = U16Vec3Ref(nonuniformEXT(mesh.m_indexBufferPtr + offset)).m_value;
-
-	const Vertex vert0 = VertexRef(mesh.m_vertexBufferPtr + indices[0] * SIZEOF_VERTEX).m_value;
-	const Vertex vert1 = VertexRef(mesh.m_vertexBufferPtr + indices[1] * SIZEOF_VERTEX).m_value;
-	const Vertex vert2 = VertexRef(mesh.m_vertexBufferPtr + indices[2] * SIZEOF_VERTEX).m_value;
-
-	const Vec3 barycentrics = Vec3(1.0f - g_attribs.x - g_attribs.y, g_attribs.x, g_attribs.y);
-
-	const Vec2 uv = vert0.m_uvs[0] * barycentrics.x + vert1.m_uvs[0] * barycentrics.y + vert2.m_uvs[0] * barycentrics.z;
-
-	const F32 alpha = textureLod(u_diffTex, u_ankiGlobalSampler, uv, 2).a;
-
-	p_payload.m_shadowFactor += alpha;
-
-	if(p_payload.m_shadowFactor >= 1.0)
-	{
-		terminateRayEXT();
-	}
-#else
-	p_payload.m_shadowFactor = 1.0;
-	terminateRayEXT();
-#endif
-}
-#pragma anki end

+ 15 - 5
shaders/glsl_cpp_common/Model.h

@@ -9,7 +9,8 @@
 
 
 ANKI_BEGIN_NAMESPACE
 ANKI_BEGIN_NAMESPACE
 
 
-const U32 UV_CHANNEL_COUNT = 2;
+const U32 UV_CHANNEL_0 = 0;
+const U32 UV_CHANNEL_COUNT = 1;
 
 
 struct Vertex
 struct Vertex
 {
 {
@@ -18,7 +19,7 @@ struct Vertex
 	HVec2 m_uvs[UV_CHANNEL_COUNT];
 	HVec2 m_uvs[UV_CHANNEL_COUNT];
 };
 };
 
 
-const U32 SIZEOF_VERTEX = 4 * 4;
+const U32 SIZEOF_VERTEX = 4 * 3;
 
 
 struct Mesh
 struct Mesh
 {
 {
@@ -29,16 +30,25 @@ struct Mesh
 	U32 m_vertexCount;
 	U32 m_vertexCount;
 };
 };
 
 
+const U32 TEXTURE_CHANNEL_DIFFUSE = 0;
+const U32 TEXTURE_CHANNEL_NORMAL = 1;
+const U32 TEXTURE_CHANNEL_ROUGHNESS_METALNESS = 2;
+const U32 TEXTURE_CHANNEL_EMISSION = 3;
+const U32 TEXTURE_CHANNEL_HEIGHT = 4;
+const U32 TEXTURE_CHANNEL_AUX_0 = 5;
+const U32 TEXTURE_CHANNEL_AUX_1 = 6;
+const U32 TEXTURE_CHANNEL_AUX_2 = 7;
+
 const U32 TEXTURE_CHANNEL_COUNT = 8;
 const U32 TEXTURE_CHANNEL_COUNT = 8;
 
 
 struct Material
 struct Material
 {
 {
-	U32 m_textureIds[TEXTURE_CHANNEL_COUNT];
+	U16 m_textureIds[TEXTURE_CHANNEL_COUNT];
 	Vec3 m_diffuseColor;
 	Vec3 m_diffuseColor;
 	Vec3 m_specularColor;
 	Vec3 m_specularColor;
 	Vec3 m_emissiveColor;
 	Vec3 m_emissiveColor;
-	F32 m_roughness;
-	F32 m_metallines;
+	F16 m_roughness;
+	F16 m_metalness;
 };
 };
 
 
 struct ModelInstance
 struct ModelInstance

+ 227 - 19
src/anki/resource/ShaderProgramResourceSystem.cpp

@@ -15,10 +15,47 @@
 namespace anki
 namespace anki
 {
 {
 
 
+void ShaderProgramRaytracingLibrary::getShaderGroupHandle(U32 groupIndex, WeakArray<U8>& handle) const
+{
+	const U32 shaderGroupHandleSize = m_program->getManager().getDeviceCapabilities().m_shaderGroupHandleSize;
+	ANKI_ASSERT(handle.getSizeInBytes() == shaderGroupHandleSize);
+
+	const U32 begin = shaderGroupHandleSize * groupIndex;
+	ConstWeakArray<U8> handles = m_program->getShaderGroupHandles();
+	ANKI_ASSERT(begin + shaderGroupHandleSize <= handles.getSizeInBytes());
+	memcpy(&handle[0], &handles[begin], shaderGroupHandleSize);
+}
+
+ShaderProgramResourceSystem::~ShaderProgramResourceSystem()
+{
+	m_cacheDir.destroy(m_alloc);
+
+	for(ShaderProgramRaytracingLibrary& lib : m_rtLibraries)
+	{
+		lib.m_libraryName.destroy(m_alloc);
+		lib.m_groupHashToGroupIndex.destroy(m_alloc);
+	}
+
+	m_rtLibraries.destroy(m_alloc);
+}
+
+Error ShaderProgramResourceSystem::init()
+{
+	ANKI_TRACE_SCOPED_EVENT(COMPILE_SHADERS);
+
+	ANKI_CHECK(compileAllShaders(m_cacheDir, *m_gr, *m_fs, m_alloc));
+
+	if(m_gr->getDeviceCapabilities().m_rayTracingEnabled)
+	{
+		ANKI_CHECK(createRayTracingPrograms(m_cacheDir, *m_gr, *m_fs, m_alloc, m_rtLibraries));
+	}
+
+	return Error::NONE;
+}
+
 Error ShaderProgramResourceSystem::compileAllShaders(CString cacheDir, GrManager& gr, ResourceFilesystem& fs,
 Error ShaderProgramResourceSystem::compileAllShaders(CString cacheDir, GrManager& gr, ResourceFilesystem& fs,
 													 GenericMemoryPoolAllocator<U8>& alloc)
 													 GenericMemoryPoolAllocator<U8>& alloc)
 {
 {
-	ANKI_TRACE_SCOPED_EVENT(COMPILE_SHADERS);
 	ANKI_RESOURCE_LOGI("Compiling shader programs");
 	ANKI_RESOURCE_LOGI("Compiling shader programs");
 	U32 shadersCompileCount = 0;
 	U32 shadersCompileCount = 0;
 
 
@@ -181,10 +218,10 @@ Error ShaderProgramResourceSystem::compileAllShaders(CString cacheDir, GrManager
 	return Error::NONE;
 	return Error::NONE;
 }
 }
 
 
-Error ShaderProgramResourceSystem::createRtPrograms(CString cacheDir, GrManager& gr, ResourceFilesystem& fs,
-													GenericMemoryPoolAllocator<U8>& alloc)
+Error ShaderProgramResourceSystem::createRayTracingPrograms(CString cacheDir, GrManager& gr, ResourceFilesystem& fs,
+															GenericMemoryPoolAllocator<U8>& alloc,
+															DynamicArray<ShaderProgramRaytracingLibrary>& outLibs)
 {
 {
-	ANKI_TRACE_SCOPED_EVENT(COMPILE_SHADERS);
 	ANKI_RESOURCE_LOGI("Creating ray tracing programs");
 	ANKI_RESOURCE_LOGI("Creating ray tracing programs");
 
 
 	// Gather the RT program fnames
 	// Gather the RT program fnames
@@ -222,20 +259,19 @@ Error ShaderProgramResourceSystem::createRtPrograms(CString cacheDir, GrManager&
 	public:
 	public:
 		U32 m_chit = MAX_U32;
 		U32 m_chit = MAX_U32;
 		U32 m_ahit = MAX_U32;
 		U32 m_ahit = MAX_U32;
-		U64 m_mutationHash = 0;
+		U64 m_hitGroupHash = 0;
 	};
 	};
 
 
 	class RayType
 	class RayType
 	{
 	{
 	public:
 	public:
 		RayType(GenericMemoryPoolAllocator<U8> alloc)
 		RayType(GenericMemoryPoolAllocator<U8> alloc)
-			: m_name(alloc)
-			, m_hitGroups(alloc)
+			: m_hitGroups(alloc)
 		{
 		{
 		}
 		}
 
 
 		U32 m_miss = MAX_U32;
 		U32 m_miss = MAX_U32;
-		StringAuto m_name;
+		U32 m_typeIndex = MAX_U32;
 		DynamicArrayAuto<HitGroup> m_hitGroups;
 		DynamicArrayAuto<HitGroup> m_hitGroups;
 	};
 	};
 
 
@@ -252,6 +288,7 @@ Error ShaderProgramResourceSystem::createRtPrograms(CString cacheDir, GrManager&
 		ShaderPtr m_rayGenShader;
 		ShaderPtr m_rayGenShader;
 		DynamicArrayAuto<Shader> m_shaders{m_alloc};
 		DynamicArrayAuto<Shader> m_shaders{m_alloc};
 		DynamicArrayAuto<RayType> m_rayTypes{m_alloc};
 		DynamicArrayAuto<RayType> m_rayTypes{m_alloc};
+		ShaderTypeBit m_presentStages = ShaderTypeBit::NONE;
 	};
 	};
 
 
 	DynamicArrayAuto<Lib> libs(alloc);
 	DynamicArrayAuto<Lib> libs(alloc);
@@ -274,11 +311,7 @@ Error ShaderProgramResourceSystem::createRtPrograms(CString cacheDir, GrManager&
 			return Error::USER_DATA;
 			return Error::USER_DATA;
 		}
 		}
 
 
-		CString subLibrary;
-		if(binary.m_subLibraryName[0] != '\0')
-		{
-			subLibrary = &binary.m_subLibraryName[0];
-		}
+		const U32 rayTypeNumber = binary.m_rayType;
 
 
 		// Create the program name
 		// Create the program name
 		StringAuto progName(alloc);
 		StringAuto progName(alloc);
@@ -312,7 +345,7 @@ Error ShaderProgramResourceSystem::createRtPrograms(CString cacheDir, GrManager&
 		// Ray gen
 		// Ray gen
 		if(!!(binary.m_presentShaderTypes & ShaderTypeBit::RAY_GEN))
 		if(!!(binary.m_presentShaderTypes & ShaderTypeBit::RAY_GEN))
 		{
 		{
-			if(lib->m_rayGenShader.get())
+			if(lib->m_rayGenShader.isCreated())
 			{
 			{
 				ANKI_RESOURCE_LOGE("The library already has a ray gen shader: %s", filename.cstr());
 				ANKI_RESOURCE_LOGE("The library already has a ray gen shader: %s", filename.cstr());
 				return Error::USER_DATA;
 				return Error::USER_DATA;
@@ -334,6 +367,8 @@ Error ShaderProgramResourceSystem::createRtPrograms(CString cacheDir, GrManager&
 			inf.m_shaderType = ShaderType::RAY_GEN;
 			inf.m_shaderType = ShaderType::RAY_GEN;
 			inf.m_binary = binary.m_codeBlocks[0].m_binary;
 			inf.m_binary = binary.m_codeBlocks[0].m_binary;
 			lib->m_rayGenShader = gr.newShader(inf);
 			lib->m_rayGenShader = gr.newShader(inf);
+
+			lib->m_presentStages |= ShaderTypeBit::RAY_GEN;
 		}
 		}
 
 
 		// Miss shaders
 		// Miss shaders
@@ -351,17 +386,16 @@ Error ShaderProgramResourceSystem::createRtPrograms(CString cacheDir, GrManager&
 				return Error::USER_DATA;
 				return Error::USER_DATA;
 			}
 			}
 
 
-			if(subLibrary.getLength() == 0)
+			if(rayTypeNumber == MAX_U32)
 			{
 			{
-				ANKI_RESOURCE_LOGE("Miss shader should have set the sub-library to be used as ray type: %s",
-								   filename.cstr());
+				ANKI_RESOURCE_LOGE("Miss shader should have set the ray type: %s", filename.cstr());
 				return Error::USER_DATA;
 				return Error::USER_DATA;
 			}
 			}
 
 
 			RayType* rayType = nullptr;
 			RayType* rayType = nullptr;
 			for(RayType& rt : lib->m_rayTypes)
 			for(RayType& rt : lib->m_rayTypes)
 			{
 			{
-				if(rt.m_name == subLibrary)
+				if(rt.m_typeIndex == rayTypeNumber)
 				{
 				{
 					rayType = &rt;
 					rayType = &rt;
 					break;
 					break;
@@ -372,7 +406,7 @@ Error ShaderProgramResourceSystem::createRtPrograms(CString cacheDir, GrManager&
 			{
 			{
 				lib->m_rayTypes.emplaceBack(alloc);
 				lib->m_rayTypes.emplaceBack(alloc);
 				rayType = &lib->m_rayTypes.getBack();
 				rayType = &lib->m_rayTypes.getBack();
-				rayType->m_name.create(subLibrary);
+				rayType->m_typeIndex = rayTypeNumber;
 			}
 			}
 
 
 			if(rayType->m_miss != MAX_U32)
 			if(rayType->m_miss != MAX_U32)
@@ -405,6 +439,8 @@ Error ShaderProgramResourceSystem::createRtPrograms(CString cacheDir, GrManager&
 			}
 			}
 
 
 			rayType->m_miss = U32(shader - &lib->m_shaders[0]);
 			rayType->m_miss = U32(shader - &lib->m_shaders[0]);
+
+			lib->m_presentStages |= ShaderTypeBit::MISS;
 		}
 		}
 
 
 		// Hit shaders
 		// Hit shaders
@@ -416,11 +452,183 @@ Error ShaderProgramResourceSystem::createRtPrograms(CString cacheDir, GrManager&
 				return Error::USER_DATA;
 				return Error::USER_DATA;
 			}
 			}
 
 
+			if(rayTypeNumber == MAX_U32)
+			{
+				ANKI_RESOURCE_LOGE("Hit shaders should have set the ray type: %s", filename.cstr());
+				return Error::USER_DATA;
+			}
+
 			// Iterate all mutations
 			// Iterate all mutations
 			for(U32 m = 0; m < binary.m_mutations.getSize(); ++m)
 			for(U32 m = 0; m < binary.m_mutations.getSize(); ++m)
 			{
 			{
+				const ShaderProgramBinaryMutation& mutation = binary.m_mutations[m];
+				const ShaderProgramBinaryVariant& variant = binary.m_variants[mutation.m_variantIndex];
+
+				// Generate the hash
+				const U64 hitGroupHash =
+					ShaderProgramRaytracingLibrary::generateHitGroupHash(filename, mutation.m_values);
+
+				HitGroup hitGroup;
+				hitGroup.m_hitGroupHash = hitGroupHash;
+
+				for(ShaderType shaderType : EnumIterable<ShaderType>())
+				{
+					const U32 codeBlockIndex = variant.m_codeBlockIndices[shaderType];
+					if(codeBlockIndex == MAX_U32)
+					{
+						continue;
+					}
+
+					ANKI_ASSERT(shaderType == ShaderType::ANY_HIT || shaderType == ShaderType::CLOSEST_HIT);
+
+					// Find the shader
+					Shader* shader = nullptr;
+					for(Shader& s : lib->m_shaders)
+					{
+						if(s.m_hash == binary.m_codeBlocks[codeBlockIndex].m_hash)
+						{
+							shader = &s;
+							break;
+						}
+					}
+
+					// Crete the shader
+					if(shader == nullptr)
+					{
+						shader = lib->m_shaders.emplaceBack();
+
+						ShaderInitInfo inf(cprogName);
+						inf.m_shaderType = shaderType;
+						inf.m_binary = binary.m_codeBlocks[codeBlockIndex].m_binary;
+						shader->m_shader = gr.newShader(inf);
+						shader->m_hash = binary.m_codeBlocks[codeBlockIndex].m_hash;
+					}
+
+					const U32 shaderIndex = U32(shader - &lib->m_shaders[0]);
+
+					if(shaderType == ShaderType::ANY_HIT)
+					{
+						hitGroup.m_ahit = shaderIndex;
+						lib->m_presentStages |= ShaderTypeBit::ANY_HIT;
+					}
+					else
+					{
+						hitGroup.m_chit = shaderIndex;
+						lib->m_presentStages |= ShaderTypeBit::CLOSEST_HIT;
+					}
+				}
+
+				// Get or create the ray type
+				RayType* rayType = nullptr;
+				for(RayType& rt : lib->m_rayTypes)
+				{
+					if(rt.m_typeIndex == rayTypeNumber)
+					{
+						rayType = &rt;
+						break;
+					}
+				}
+
+				if(rayType == nullptr)
+				{
+					lib->m_rayTypes.emplaceBack(alloc);
+					rayType = &lib->m_rayTypes.getBack();
+					rayType->m_typeIndex = rayTypeNumber;
+				}
+
+				// Try to find if the hit group aleady exists. If it does then something is wrong
+				for(const HitGroup& hg : rayType->m_hitGroups)
+				{
+					if(hg.m_hitGroupHash == hitGroup.m_hitGroupHash)
+					{
+						ANKI_ASSERT(!"Found a hitgroup with the same hash. Something is wrong");
+					}
+				}
+
+				// Create the hitgroup
+				rayType->m_hitGroups.emplaceBack(hitGroup);
+			}
+		}
+	}
+
+	// Create the libraries
+	if(libs.getSize() == 0)
+	{
+		return Error::NONE;
+	}
+
+	outLibs.resize(alloc, libs.getSize());
+
+	for(U32 libIdx = 0; libIdx < libs.getSize(); ++libIdx)
+	{
+		ShaderProgramRaytracingLibrary& outLib = outLibs[libIdx];
+		Lib& inLib = libs[libIdx];
+
+		if(inLib.m_presentStages
+		   != (ShaderTypeBit::RAY_GEN | ShaderTypeBit::MISS | ShaderTypeBit::CLOSEST_HIT | ShaderTypeBit::ANY_HIT))
+		{
+			ANKI_RESOURCE_LOGE("The libray is missing shader shader types: %s", inLib.m_name.cstr());
+			return Error::USER_DATA;
+		}
+
+		// Sort because the expectation is that the miss shaders are organized based on ray type
+		std::sort(inLib.m_rayTypes.getBegin(), inLib.m_rayTypes.getEnd(),
+				  [](const RayType& a, const RayType& b) { return a.m_typeIndex < b.m_typeIndex; });
+
+		outLib.m_libraryName.create(alloc, inLib.m_name);
+		outLib.m_rayTypeCount = inLib.m_rayTypes.getSize();
+
+		DynamicArrayAuto<RayTracingHitGroup> initInfoHitGroups(alloc);
+		DynamicArrayAuto<ShaderPtr> missShaders(alloc);
+
+		for(U32 rayTypeIdx = 0; rayTypeIdx < inLib.m_rayTypes.getSize(); ++rayTypeIdx)
+		{
+			const RayType& inRayType = inLib.m_rayTypes[rayTypeIdx];
+
+			if(inRayType.m_typeIndex != rayTypeIdx)
+			{
+				ANKI_RESOURCE_LOGE("Ray types are not contiguous for library: %s", inLib.m_name.cstr());
+				return Error::USER_DATA;
 			}
 			}
+
+			// Add the hitgroups to the init info
+			for(U32 hitGroupIdx = 0; hitGroupIdx < inRayType.m_hitGroups.getSize(); ++hitGroupIdx)
+			{
+				const HitGroup& inHitGroup = inRayType.m_hitGroups[hitGroupIdx];
+
+				outLib.m_groupHashToGroupIndex.emplace(alloc, inHitGroup.m_hitGroupHash, initInfoHitGroups.getSize());
+
+				RayTracingHitGroup* infoHitGroup = initInfoHitGroups.emplaceBack();
+				if(inHitGroup.m_ahit != MAX_U32)
+				{
+					infoHitGroup->m_anyHitShader = inLib.m_shaders[inHitGroup.m_ahit].m_shader;
+				}
+
+				if(inHitGroup.m_chit != MAX_U32)
+				{
+					infoHitGroup->m_closestHitShader = inLib.m_shaders[inHitGroup.m_chit].m_shader;
+				}
+			}
+
+			// Add the miss shader
+			ANKI_ASSERT(inRayType.m_miss != MAX_U32);
+			missShaders.emplaceBack(inLib.m_shaders[inRayType.m_miss].m_shader);
+		}
+
+		// Program name
+		StringAuto progName(alloc, inLib.m_name);
+		char* cprogName = const_cast<char*>(progName.cstr());
+		if(progName.getLength() > MAX_GR_OBJECT_NAME_LENGTH)
+		{
+			cprogName[MAX_GR_OBJECT_NAME_LENGTH] = '\0';
 		}
 		}
+
+		// Create the program
+		ShaderProgramInitInfo inf(cprogName);
+		inf.m_rayTracingShaders.m_rayGenShader = inLib.m_rayGenShader;
+		inf.m_rayTracingShaders.m_missShaders = missShaders;
+		inf.m_rayTracingShaders.m_hitGroups = initInfoHitGroups;
+		outLib.m_program = gr.newShaderProgram(inf);
 	}
 	}
 
 
 	return Error::NONE;
 	return Error::NONE;

+ 56 - 14
src/anki/resource/ShaderProgramResourceSystem.h

@@ -16,16 +16,58 @@ namespace anki
 /// @addtogroup resource
 /// @addtogroup resource
 /// @{
 /// @{
 
 
-/// XXX
+/// This is a ray tracing library. Essentially a shader program with some functionality on how to get group indices.
 class ShaderProgramRaytracingLibrary
 class ShaderProgramRaytracingLibrary
 {
 {
+	friend class ShaderProgramResourceSystem;
+
 public:
 public:
+	CString getLibraryName() const
+	{
+		return m_libraryName;
+	}
+
+	U32 getRayTypeCount() const
+	{
+		ANKI_ASSERT(m_rayTypeCount < MAX_U32);
+		return m_rayTypeCount;
+	}
+
+	const ShaderProgramPtr& getShaderProgram() const
+	{
+		return m_program;
+	}
+
+	/// Given the filename of a program (that contains hit shaders) and a specific mutation get the group handle.
+	void getHitShaderGroupHandle(CString resourceFilename, ConstWeakArray<MutatorValue> mutation,
+								 WeakArray<U8>& handle) const
+	{
+		const U32 hitGroupIndex = getHitGroupIndex(generateHitGroupHash(resourceFilename, mutation));
+		getShaderGroupHandle(hitGroupIndex, handle);
+	}
+
+	void getMissShaderGroupHandle(U32 rayType, WeakArray<U8>& handle) const
+	{
+		ANKI_ASSERT(rayType < getRayTypeCount());
+		getShaderGroupHandle(rayType + 1, handle);
+	}
+
+private:
 	String m_libraryName;
 	String m_libraryName;
-	DynamicArray<String> m_rayTypes;
+	U32 m_rayTypeCount = MAX_U32;
 	ShaderProgramPtr m_program;
 	ShaderProgramPtr m_program;
+	HashMap<U64, U32> m_groupHashToGroupIndex;
 
 
-	static U64 generateHitGroupHash(CString resourceFilename, ConstWeakArray<MutatorValue> mutation);
+	/// Given the filename of a program (that contains hit shaders) and a specific mutation get a hash back.
+	static U64 generateHitGroupHash(CString resourceFilename, ConstWeakArray<MutatorValue> mutation)
+	{
+		ANKI_ASSERT(resourceFilename.getLength() > 0);
+		U64 hash = computeHash(resourceFilename.cstr(), resourceFilename.getLength());
+		hash = appendHash(mutation.getBegin(), mutation.getSizeInBytes(), hash);
+		return hash;
+	}
 
 
+	/// The hash generated by generateHitGroupHash() can be used to retrieve the hit group position in the m_program.
 	U32 getHitGroupIndex(U64 groupHash) const
 	U32 getHitGroupIndex(U64 groupHash) const
 	{
 	{
 		auto it = m_groupHashToGroupIndex.find(groupHash);
 		auto it = m_groupHashToGroupIndex.find(groupHash);
@@ -33,11 +75,10 @@ public:
 		return *it;
 		return *it;
 	}
 	}
 
 
-private:
-	HashMap<U64, U32> m_groupHashToGroupIndex;
+	void getShaderGroupHandle(U32 groupIndex, WeakArray<U8>& handle) const;
 };
 };
 
 
-/// A system that does some work with shader programs.
+/// A system that does some work on shader programs before resources start loading.
 class ShaderProgramResourceSystem
 class ShaderProgramResourceSystem
 {
 {
 public:
 public:
@@ -50,14 +91,13 @@ public:
 		m_cacheDir.create(alloc, cacheDir);
 		m_cacheDir.create(alloc, cacheDir);
 	}
 	}
 
 
-	~ShaderProgramResourceSystem()
-	{
-		m_cacheDir.destroy(m_alloc);
-	}
+	~ShaderProgramResourceSystem();
+
+	ANKI_USE_RESULT Error init();
 
 
-	ANKI_USE_RESULT Error init()
+	ConstWeakArray<ShaderProgramRaytracingLibrary> getRayTracingLibraries() const
 	{
 	{
-		return compileAllShaders(m_cacheDir, *m_gr, *m_fs, m_alloc);
+		return m_rtLibraries;
 	}
 	}
 
 
 private:
 private:
@@ -65,13 +105,15 @@ private:
 	String m_cacheDir;
 	String m_cacheDir;
 	GrManager* m_gr;
 	GrManager* m_gr;
 	ResourceFilesystem* m_fs;
 	ResourceFilesystem* m_fs;
+	DynamicArray<ShaderProgramRaytracingLibrary> m_rtLibraries;
 
 
 	/// Iterate all programs in the filesystem and compile them to AnKi's binary format.
 	/// Iterate all programs in the filesystem and compile them to AnKi's binary format.
 	static Error compileAllShaders(CString cacheDir, GrManager& gr, ResourceFilesystem& fs,
 	static Error compileAllShaders(CString cacheDir, GrManager& gr, ResourceFilesystem& fs,
 								   GenericMemoryPoolAllocator<U8>& alloc);
 								   GenericMemoryPoolAllocator<U8>& alloc);
 
 
-	static Error createRtPrograms(CString cacheDir, GrManager& gr, ResourceFilesystem& fs,
-								  GenericMemoryPoolAllocator<U8>& alloc);
+	static Error createRayTracingPrograms(CString cacheDir, GrManager& gr, ResourceFilesystem& fs,
+										  GenericMemoryPoolAllocator<U8>& alloc,
+										  DynamicArray<ShaderProgramRaytracingLibrary>& libs);
 };
 };
 /// @}
 /// @}
 
 

+ 2 - 3
src/anki/shader_compiler/ShaderProgramBinary.h

@@ -384,7 +384,7 @@ public:
 	WeakArray<ShaderProgramBinaryConstant> m_constants;
 	WeakArray<ShaderProgramBinaryConstant> m_constants;
 	ShaderTypeBit m_presentShaderTypes = ShaderTypeBit::NONE;
 	ShaderTypeBit m_presentShaderTypes = ShaderTypeBit::NONE;
 	Array<char, 64> m_libraryName = {}; ///< The name of the shader library. Mainly for RT shaders.
 	Array<char, 64> m_libraryName = {}; ///< The name of the shader library. Mainly for RT shaders.
-	Array<char, 64> m_subLibraryName = {}; ///< The name of the sub shader library. Mainly the ray type.
+	U32 m_rayType = MAX_U32; ///< An arbitary number indicating the type of the ray.
 
 
 	template<typename TSerializer, typename TClass>
 	template<typename TSerializer, typename TClass>
 	static void serializeCommon(TSerializer& s, TClass self)
 	static void serializeCommon(TSerializer& s, TClass self)
@@ -404,8 +404,7 @@ public:
 				  self.m_presentShaderTypes);
 				  self.m_presentShaderTypes);
 		s.doArray("m_libraryName", offsetof(ShaderProgramBinary, m_libraryName), &self.m_libraryName[0],
 		s.doArray("m_libraryName", offsetof(ShaderProgramBinary, m_libraryName), &self.m_libraryName[0],
 				  self.m_libraryName.getSize());
 				  self.m_libraryName.getSize());
-		s.doArray("m_subLibraryName", offsetof(ShaderProgramBinary, m_subLibraryName), &self.m_subLibraryName[0],
-				  self.m_subLibraryName.getSize());
+		s.doValue("m_rayType", offsetof(ShaderProgramBinary, m_rayType), self.m_rayType);
 	}
 	}
 
 
 	template<typename TDeserializer>
 	template<typename TDeserializer>

+ 1 - 1
src/anki/shader_compiler/ShaderProgramBinary.xml

@@ -116,7 +116,7 @@
 				<member name="m_constants" type="WeakArray&lt;ShaderProgramBinaryConstant&gt;" />
 				<member name="m_constants" type="WeakArray&lt;ShaderProgramBinaryConstant&gt;" />
 				<member name="m_presentShaderTypes" type="ShaderTypeBit" constructor="= ShaderTypeBit::NONE" />
 				<member name="m_presentShaderTypes" type="ShaderTypeBit" constructor="= ShaderTypeBit::NONE" />
 				<member name="m_libraryName" type="char" array_size="64" constructor="= {}" comment="The name of the shader library. Mainly for RT shaders" />
 				<member name="m_libraryName" type="char" array_size="64" constructor="= {}" comment="The name of the shader library. Mainly for RT shaders" />
-				<member name="m_subLibraryName" type="char" array_size="64" constructor="= {}" comment="The name of the sub shader library. Mainly the ray type" />
+				<member name="m_rayType" type="U32" constructor="= MAX_U32" comment="An arbitary number indicating the type of the ray" />
 			</members>
 			</members>
 		</class>
 		</class>
 	</classes>
 	</classes>

+ 3 - 12
src/anki/shader_compiler/ShaderProgramCompiler.cpp

@@ -13,8 +13,8 @@
 namespace anki
 namespace anki
 {
 {
 
 
-static const char* SHADER_BINARY_MAGIC = "ANKISDR3";
-const U32 SHADER_BINARY_VERSION = 1;
+static const char* SHADER_BINARY_MAGIC = "ANKISDR4"; ///< @warning If changed change SHADER_BINARY_VERSION
+const U32 SHADER_BINARY_VERSION = 4;
 
 
 Error ShaderProgramBinaryWrapper::serializeToFile(CString fname) const
 Error ShaderProgramBinaryWrapper::serializeToFile(CString fname) const
 {
 {
@@ -995,16 +995,7 @@ Error compileShaderProgramInternal(CString fname, ShaderProgramFilesystemInterfa
 		memcpy(&binary.m_libraryName[0], &parser.getLibraryName()[0], parser.getLibraryName().getLength());
 		memcpy(&binary.m_libraryName[0], &parser.getLibraryName()[0], parser.getLibraryName().getLength());
 	}
 	}
 
 
-	if(parser.getSubLibraryName().getLength() > 0)
-	{
-		if(parser.getSubLibraryName().getLength() >= sizeof(binary.m_subLibraryName))
-		{
-			ANKI_SHADER_COMPILER_LOGE("Sub library name too long: %s", parser.getSubLibraryName().cstr());
-			return Error::USER_DATA;
-		}
-
-		memcpy(&binary.m_subLibraryName[0], &parser.getSubLibraryName()[0], parser.getSubLibraryName().getLength());
-	}
+	binary.m_rayType = parser.getRayType();
 
 
 	// Misc
 	// Misc
 	binary.m_presentShaderTypes = parser.getShaderTypes();
 	binary.m_presentShaderTypes = parser.getShaderTypes();

+ 6 - 7
src/anki/shader_compiler/ShaderProgramDump.cpp

@@ -39,14 +39,13 @@ void dumpShaderProgramBinary(const ShaderProgramBinary& binary, StringAuto& huma
 	if(binary.m_libraryName[0])
 	if(binary.m_libraryName[0])
 	{
 	{
 		lines.pushBack("**LIBRARY**\n");
 		lines.pushBack("**LIBRARY**\n");
-		lines.pushBackSprintf(ANKI_TAB "%s\n", &binary.m_libraryName[0]);
-
-		if(binary.m_subLibraryName[0])
-		{
-			lines.pushBackSprintf(ANKI_TAB "%s (sublibrary)\n", &binary.m_subLibraryName[0]);
-		}
+		lines.pushBackSprintf(ANKI_TAB "%s\n\n", &binary.m_libraryName[0]);
+	}
 
 
-		lines.pushBack("\n");
+	if(binary.m_rayType != MAX_U32)
+	{
+		lines.pushBack("**RAY TYPE**\n");
+		lines.pushBackSprintf(ANKI_TAB "%u\n\n", binary.m_rayType);
 	}
 	}
 
 
 	lines.pushBack("**MUTATORS**\n");
 	lines.pushBack("**MUTATORS**\n");

+ 13 - 11
src/anki/shader_compiler/ShaderProgramParser.cpp

@@ -496,8 +496,8 @@ Error ShaderProgramParser::parsePragmaLibraryName(const StringAuto* begin, const
 	return Error::NONE;
 	return Error::NONE;
 }
 }
 
 
-Error ShaderProgramParser::parsePragmaSubLibraryName(const StringAuto* begin, const StringAuto* end, CString line,
-													 CString fname)
+Error ShaderProgramParser::parsePragmaRayType(const StringAuto* begin, const StringAuto* end, CString line,
+											  CString fname)
 {
 {
 	ANKI_ASSERT(begin && end);
 	ANKI_ASSERT(begin && end);
 
 
@@ -506,12 +506,17 @@ Error ShaderProgramParser::parsePragmaSubLibraryName(const StringAuto* begin, co
 		ANKI_PP_ERROR_MALFORMED();
 		ANKI_PP_ERROR_MALFORMED();
 	}
 	}
 
 
-	if(m_sublibName.getLength() > 0)
+	if(m_rayType != MAX_U32)
 	{
 	{
-		ANKI_PP_ERROR_MALFORMED_MSG("Sub library name already set");
+		ANKI_PP_ERROR_MALFORMED_MSG("Ray type already set");
 	}
 	}
 
 
-	m_sublibName = *begin;
+	ANKI_CHECK(begin->toNumber(m_rayType));
+
+	if(m_rayType > 128)
+	{
+		ANKI_PP_ERROR_MALFORMED_MSG("Ray type has a very large value");
+	}
 
 
 	return Error::NONE;
 	return Error::NONE;
 }
 }
@@ -769,9 +774,9 @@ Error ShaderProgramParser::parseLine(CString line, CString fname, Bool& foundPra
 			{
 			{
 				ANKI_CHECK(parsePragmaLibraryName(token + 1, end, line, fname));
 				ANKI_CHECK(parsePragmaLibraryName(token + 1, end, line, fname));
 			}
 			}
-			else if(*token == "sub_library")
+			else if(*token == "ray_type")
 			{
 			{
-				ANKI_CHECK(parsePragmaSubLibraryName(token + 1, end, line, fname));
+				ANKI_CHECK(parsePragmaRayType(token + 1, end, line, fname));
 			}
 			}
 			else
 			else
 			{
 			{
@@ -903,10 +908,7 @@ Error ShaderProgramParser::parse()
 			m_codeSourceHash = appendHash(m_libName.getBegin(), m_libName.getLength(), m_codeSourceHash);
 			m_codeSourceHash = appendHash(m_libName.getBegin(), m_libName.getLength(), m_codeSourceHash);
 		}
 		}
 
 
-		if(m_sublibName.getLength() > 0)
-		{
-			m_codeSourceHash = appendHash(m_sublibName.getBegin(), m_sublibName.getLength(), m_codeSourceHash);
-		}
+		m_codeSourceHash = appendHash(&m_rayType, sizeof(m_rayType), m_codeSourceHash);
 	}
 	}
 
 
 	return Error::NONE;
 	return Error::NONE;

+ 6 - 6
src/anki/shader_compiler/ShaderProgramParser.h

@@ -84,7 +84,7 @@ private:
 /// #pragma anki start {vert | tessc | tesse | geom | frag | comp | rgen | ahit | chit | miss | int | call}
 /// #pragma anki start {vert | tessc | tesse | geom | frag | comp | rgen | ahit | chit | miss | int | call}
 /// #pragma anki end
 /// #pragma anki end
 /// #pragma anki library "name"
 /// #pragma anki library "name"
-/// #pragma anki sub_library "name"
+/// #pragma anki ray_type NUMBER
 ///
 ///
 /// Only the "anki input" should be in an ifdef-like guard. For everything else it's ignored.
 /// Only the "anki input" should be in an ifdef-like guard. For everything else it's ignored.
 class ShaderProgramParser : public NonCopyable
 class ShaderProgramParser : public NonCopyable
@@ -127,9 +127,9 @@ public:
 		return m_libName;
 		return m_libName;
 	}
 	}
 
 
-	CString getSubLibraryName() const
+	U32 getRayType() const
 	{
 	{
-		return m_sublibName;
+		return m_rayType;
 	}
 	}
 
 
 	/// Generates the common header that will be used by all AnKi shaders.
 	/// Generates the common header that will be used by all AnKi shaders.
@@ -183,7 +183,7 @@ private:
 	BindlessLimits m_bindlessLimits;
 	BindlessLimits m_bindlessLimits;
 
 
 	StringAuto m_libName = {m_alloc};
 	StringAuto m_libName = {m_alloc};
-	StringAuto m_sublibName = {m_alloc};
+	U32 m_rayType = MAX_U32;
 
 
 	ANKI_USE_RESULT Error parseFile(CString fname, U32 depth);
 	ANKI_USE_RESULT Error parseFile(CString fname, U32 depth);
 	ANKI_USE_RESULT Error parseLine(CString line, CString fname, Bool& foundPragmaOnce, U32 depth);
 	ANKI_USE_RESULT Error parseLine(CString line, CString fname, Bool& foundPragmaOnce, U32 depth);
@@ -197,8 +197,8 @@ private:
 													 CString fname);
 													 CString fname);
 	ANKI_USE_RESULT Error parsePragmaLibraryName(const StringAuto* begin, const StringAuto* end, CString line,
 	ANKI_USE_RESULT Error parsePragmaLibraryName(const StringAuto* begin, const StringAuto* end, CString line,
 												 CString fname);
 												 CString fname);
-	ANKI_USE_RESULT Error parsePragmaSubLibraryName(const StringAuto* begin, const StringAuto* end, CString line,
-													CString fname);
+	ANKI_USE_RESULT Error parsePragmaRayType(const StringAuto* begin, const StringAuto* end, CString line,
+											 CString fname);
 
 
 	void tokenizeLine(CString line, DynamicArrayAuto<StringAuto>& tokens) const;
 	void tokenizeLine(CString line, DynamicArrayAuto<StringAuto>& tokens) const;
 
 

+ 71 - 6
src/anki/util/WeakArray.h

@@ -41,9 +41,9 @@ public:
 	{
 	{
 	}
 	}
 
 
-	template<PtrSize S>
-	WeakArray(Array<T, S>& arr)
-		: WeakArray(&arr[0], S)
+	template<PtrSize TSIZE>
+	WeakArray(Array<T, TSIZE>& arr)
+		: WeakArray(&arr[0], arr.getSize())
 	{
 	{
 	}
 	}
 
 
@@ -57,6 +57,16 @@ public:
 		}
 		}
 	}
 	}
 
 
+	explicit WeakArray(DynamicArrayAuto<T>& arr)
+		: WeakArray()
+	{
+		if(arr.getSize())
+		{
+			m_data = &arr[0];
+			m_size = arr.getSize();
+		}
+	}
+
 	/// Copy.
 	/// Copy.
 	WeakArray(const WeakArray& b)
 	WeakArray(const WeakArray& b)
 		: WeakArray(b.m_data, b.m_size)
 		: WeakArray(b.m_data, b.m_size)
@@ -88,6 +98,28 @@ public:
 		return *this;
 		return *this;
 	}
 	}
 
 
+	template<PtrSize TSIZE>
+	WeakArray& operator=(Array<T, TSIZE>& arr)
+	{
+		m_data = &arr[0];
+		m_size = arr.getSize();
+		return *this;
+	}
+
+	WeakArray& operator=(DynamicArray<T>& arr)
+	{
+		m_data = (arr.getSize()) ? &arr[0] : nullptr;
+		m_size = arr.getSize();
+		return *this;
+	}
+
+	WeakArray& operator=(DynamicArrayAuto<T>& arr)
+	{
+		m_data = (arr.getSize()) ? &arr[0] : nullptr;
+		m_size = arr.getSize();
+		return *this;
+	}
+
 	Reference operator[](const Size n)
 	Reference operator[](const Size n)
 	{
 	{
 		ANKI_ASSERT(n < m_size);
 		ANKI_ASSERT(n < m_size);
@@ -232,9 +264,9 @@ public:
 	}
 	}
 
 
 	/// Construct from Array.
 	/// Construct from Array.
-	template<PtrSize S>
-	ConstWeakArray(const Array<T, S>& arr)
-		: ConstWeakArray(&arr[0], S)
+	template<PtrSize TSIZE>
+	ConstWeakArray(const Array<T, TSIZE>& arr)
+		: ConstWeakArray(&arr[0], arr.getSize())
 	{
 	{
 	}
 	}
 
 
@@ -249,6 +281,17 @@ public:
 		}
 		}
 	}
 	}
 
 
+	/// Construct from DynamicArrayAuto.
+	ConstWeakArray(const DynamicArrayAuto<T>& arr)
+		: ConstWeakArray()
+	{
+		if(arr.getSize())
+		{
+			m_data = &arr[0];
+			m_size = arr.getSize();
+		}
+	}
+
 	/// Copy.
 	/// Copy.
 	ConstWeakArray(const ConstWeakArray& b)
 	ConstWeakArray(const ConstWeakArray& b)
 		: ConstWeakArray(b.m_data, b.m_size)
 		: ConstWeakArray(b.m_data, b.m_size)
@@ -289,6 +332,28 @@ public:
 		return *this;
 		return *this;
 	}
 	}
 
 
+	template<PtrSize TSIZE>
+	ConstWeakArray& operator=(const Array<T, TSIZE>& arr)
+	{
+		m_data = &arr[0];
+		m_size = arr.getSize();
+		return *this;
+	}
+
+	ConstWeakArray& operator=(const DynamicArray<T>& arr)
+	{
+		m_data = (arr.getSize()) ? &arr[0] : nullptr;
+		m_size = arr.getSize();
+		return *this;
+	}
+
+	ConstWeakArray& operator=(const DynamicArrayAuto<T>& arr)
+	{
+		m_data = (arr.getSize()) ? &arr[0] : nullptr;
+		m_size = arr.getSize();
+		return *this;
+	}
+
 	ConstReference operator[](const Size n) const
 	ConstReference operator[](const Size n) const
 	{
 	{
 		ANKI_ASSERT(n < m_size);
 		ANKI_ASSERT(n < m_size);