Browse Source

Some work on the RT shader compilation

Panagiotis Christopoulos Charitos 5 years ago
parent
commit
de36a07d6d

+ 246 - 0
src/anki/resource/ShaderProgramResourceSystem.cpp

@@ -42,6 +42,7 @@ Error ShaderProgramResourceSystem::compileAllShaders(CString cacheDir, GrManager
 
 		if(fname.find("/Rt") != CString::NPOS && !gr.getDeviceCapabilities().m_rayTracingEnabled)
 		{
+			// Skip RT programs
 			return Error::NONE;
 		}
 
@@ -180,4 +181,249 @@ Error ShaderProgramResourceSystem::compileAllShaders(CString cacheDir, GrManager
 	return Error::NONE;
 }
 
+Error ShaderProgramResourceSystem::createRtPrograms(CString cacheDir, GrManager& gr, ResourceFilesystem& fs,
+													GenericMemoryPoolAllocator<U8>& alloc)
+{
+	ANKI_TRACE_SCOPED_EVENT(COMPILE_SHADERS);
+	ANKI_RESOURCE_LOGI("Creating ray tracing programs");
+
+	// Gather the RT program fnames
+	StringListAuto rtPrograms(alloc);
+	ANKI_CHECK(fs.iterateAllFilenames([&](CString fname) -> Error {
+		// Check file extension
+		StringAuto extension(alloc);
+		getFilepathExtension(fname, extension);
+		if(extension.getLength() != 8 || extension != "ankiprog")
+		{
+			return Error::NONE;
+		}
+
+		if(fname.find("/Rt") == CString::NPOS)
+		{
+			// Skip non-RT programs
+			return Error::NONE;
+		}
+
+		rtPrograms.pushBack(fname);
+
+		return Error::NONE;
+	}));
+
+	// Group things together
+	class Shader
+	{
+	public:
+		ShaderPtr m_shader;
+		U64 m_hash = 0;
+	};
+
+	class HitGroup
+	{
+	public:
+		U32 m_chit = MAX_U32;
+		U32 m_ahit = MAX_U32;
+		U64 m_mutationHash = 0;
+	};
+
+	class RayType
+	{
+	public:
+		RayType(GenericMemoryPoolAllocator<U8> alloc)
+			: m_name(alloc)
+			, m_hitGroups(alloc)
+		{
+		}
+
+		U32 m_miss = MAX_U32;
+		StringAuto m_name;
+		DynamicArrayAuto<HitGroup> m_hitGroups;
+	};
+
+	class Lib
+	{
+	public:
+		Lib(GenericMemoryPoolAllocator<U8> alloc)
+			: m_alloc(alloc)
+		{
+		}
+
+		GenericMemoryPoolAllocator<U8> m_alloc;
+		StringAuto m_name{m_alloc};
+		ShaderPtr m_rayGenShader;
+		DynamicArrayAuto<Shader> m_shaders{m_alloc};
+		DynamicArrayAuto<RayType> m_rayTypes{m_alloc};
+	};
+
+	DynamicArrayAuto<Lib> libs(alloc);
+
+	for(const String& filename : rtPrograms)
+	{
+		// Get the binary
+		StringAuto baseFilename(alloc);
+		getFilepathFilename(filename, baseFilename);
+		StringAuto binaryFilename(alloc);
+		binaryFilename.sprintf("%s/%sbin", cacheDir.cstr(), baseFilename.cstr());
+		ShaderProgramBinaryWrapper binaryw(alloc);
+		ANKI_CHECK(binaryw.deserializeFromFile(binaryFilename));
+		const ShaderProgramBinary& binary = binaryw.getBinary();
+
+		// Checks
+		if(binary.m_libraryName[0] == '\0')
+		{
+			ANKI_RESOURCE_LOGE("Library is missing from program: %s", filename.cstr());
+			return Error::USER_DATA;
+		}
+
+		CString subLibrary;
+		if(binary.m_subLibraryName[0] != '\0')
+		{
+			subLibrary = &binary.m_subLibraryName[0];
+		}
+
+		// Create the program name
+		StringAuto progName(alloc);
+		getFilepathFilename(filename, progName);
+		char* cprogName = const_cast<char*>(progName.cstr());
+		if(progName.getLength() > MAX_GR_OBJECT_NAME_LENGTH)
+		{
+			cprogName[MAX_GR_OBJECT_NAME_LENGTH] = '\0';
+		}
+
+		// Find or create the lib
+		Lib* lib = nullptr;
+		{
+			for(Lib& l : libs)
+			{
+				if(l.m_name == CString(&binary.m_libraryName[0]))
+				{
+					lib = &l;
+					break;
+				}
+			}
+
+			if(lib == nullptr)
+			{
+				libs.emplaceBack(alloc);
+				lib = &libs.getBack();
+				lib->m_name.create(CString(&binary.m_libraryName[0]));
+			}
+		}
+
+		// Ray gen
+		if(!!(binary.m_presentShaderTypes & ShaderTypeBit::RAY_GEN))
+		{
+			if(lib->m_rayGenShader.get())
+			{
+				ANKI_RESOURCE_LOGE("The library already has a ray gen shader: %s", filename.cstr());
+				return Error::USER_DATA;
+			}
+
+			if(!!(binary.m_presentShaderTypes & ~ShaderTypeBit::RAY_GEN))
+			{
+				ANKI_RESOURCE_LOGE("Ray gen can't co-exist with other types: %s", filename.cstr());
+				return Error::USER_DATA;
+			}
+
+			if(binary.m_constants.getSize() || binary.m_mutators.getSize())
+			{
+				ANKI_RESOURCE_LOGE("Ray gen can't have spec constants or mutators ATM: %s", filename.cstr());
+				return Error::USER_DATA;
+			}
+
+			ShaderInitInfo inf(cprogName);
+			inf.m_shaderType = ShaderType::RAY_GEN;
+			inf.m_binary = binary.m_codeBlocks[0].m_binary;
+			lib->m_rayGenShader = gr.newShader(inf);
+		}
+
+		// Miss shaders
+		if(!!(binary.m_presentShaderTypes & ShaderTypeBit::MISS))
+		{
+			if(!!(binary.m_presentShaderTypes & ~ShaderTypeBit::MISS))
+			{
+				ANKI_RESOURCE_LOGE("Miss shaders can't co-exist with other types: %s", filename.cstr());
+				return Error::USER_DATA;
+			}
+
+			if(binary.m_constants.getSize() || binary.m_mutators.getSize())
+			{
+				ANKI_RESOURCE_LOGE("Miss can't have spec constants or mutators ATM: %s", filename.cstr());
+				return Error::USER_DATA;
+			}
+
+			if(subLibrary.getLength() == 0)
+			{
+				ANKI_RESOURCE_LOGE("Miss shader should have set the sub-library to be used as ray type: %s",
+								   filename.cstr());
+				return Error::USER_DATA;
+			}
+
+			RayType* rayType = nullptr;
+			for(RayType& rt : lib->m_rayTypes)
+			{
+				if(rt.m_name == subLibrary)
+				{
+					rayType = &rt;
+					break;
+				}
+			}
+
+			if(rayType == nullptr)
+			{
+				lib->m_rayTypes.emplaceBack(alloc);
+				rayType = &lib->m_rayTypes.getBack();
+				rayType->m_name.create(subLibrary);
+			}
+
+			if(rayType->m_miss != MAX_U32)
+			{
+				ANKI_RESOURCE_LOGE(
+					"There is another miss program with the same library and sub-library names with this: %s",
+					filename.cstr());
+				return Error::USER_DATA;
+			}
+
+			Shader* shader = nullptr;
+			for(Shader& s : lib->m_shaders)
+			{
+				if(s.m_hash == binary.m_codeBlocks[0].m_hash)
+				{
+					shader = &s;
+					break;
+				}
+			}
+
+			if(shader == nullptr)
+			{
+				shader = lib->m_shaders.emplaceBack();
+
+				ShaderInitInfo inf(cprogName);
+				inf.m_shaderType = ShaderType::MISS;
+				inf.m_binary = binary.m_codeBlocks[0].m_binary;
+				shader->m_shader = gr.newShader(inf);
+				shader->m_hash = binary.m_codeBlocks[0].m_hash;
+			}
+
+			rayType->m_miss = U32(shader - &lib->m_shaders[0]);
+		}
+
+		// Hit shaders
+		if(!!(binary.m_presentShaderTypes & (ShaderTypeBit::ANY_HIT | ShaderTypeBit::CLOSEST_HIT)))
+		{
+			if(!!(binary.m_presentShaderTypes & ~(ShaderTypeBit::ANY_HIT | ShaderTypeBit::CLOSEST_HIT)))
+			{
+				ANKI_RESOURCE_LOGE("Hit shaders can't co-exist with other types: %s", filename.cstr());
+				return Error::USER_DATA;
+			}
+
+			// Iterate all mutations
+			for(U32 m = 0; m < binary.m_mutations.getSize(); ++m)
+			{
+			}
+		}
+	}
+
+	return Error::NONE;
+}
+
 } // end namespace anki

+ 27 - 0
src/anki/resource/ShaderProgramResourceSystem.h

@@ -6,6 +6,9 @@
 #pragma once
 
 #include <anki/resource/Common.h>
+#include <anki/gr/ShaderProgram.h>
+#include <anki/util/HashMap.h>
+#include <anki/shader_compiler/ShaderProgramBinary.h>
 
 namespace anki
 {
@@ -13,6 +16,27 @@ namespace anki
 /// @addtogroup resource
 /// @{
 
+/// XXX
+class ShaderProgramRaytracingLibrary
+{
+public:
+	String m_libraryName;
+	DynamicArray<String> m_rayTypes;
+	ShaderProgramPtr m_program;
+
+	static U64 generateHitGroupHash(CString resourceFilename, ConstWeakArray<MutatorValue> mutation);
+
+	U32 getHitGroupIndex(U64 groupHash) const
+	{
+		auto it = m_groupHashToGroupIndex.find(groupHash);
+		ANKI_ASSERT(it != m_groupHashToGroupIndex.getEnd());
+		return *it;
+	}
+
+private:
+	HashMap<U64, U32> m_groupHashToGroupIndex;
+};
+
 /// A system that does some work with shader programs.
 class ShaderProgramResourceSystem
 {
@@ -45,6 +69,9 @@ private:
 	/// Iterate all programs in the filesystem and compile them to AnKi's binary format.
 	static Error compileAllShaders(CString cacheDir, GrManager& gr, ResourceFilesystem& fs,
 								   GenericMemoryPoolAllocator<U8>& alloc);
+
+	static Error createRtPrograms(CString cacheDir, GrManager& gr, ResourceFilesystem& fs,
+								  GenericMemoryPoolAllocator<U8>& alloc);
 };
 /// @}
 

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

@@ -317,11 +317,13 @@ class ShaderProgramBinaryCodeBlock
 {
 public:
 	WeakArray<U8> m_binary;
+	U64 m_hash = 0;
 
 	template<typename TSerializer, typename TClass>
 	static void serializeCommon(TSerializer& s, TClass self)
 	{
 		s.doValue("m_binary", offsetof(ShaderProgramBinaryCodeBlock, m_binary), self.m_binary);
+		s.doValue("m_hash", offsetof(ShaderProgramBinaryCodeBlock, m_hash), self.m_hash);
 	}
 
 	template<typename TDeserializer>

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

@@ -90,6 +90,7 @@
 		<class name="ShaderProgramBinaryCodeBlock" comment="Contains the IR (SPIR-V)">
 			<members>
 				<member name="m_binary" type="WeakArray&lt;U8&gt;" />
+				<member name="m_hash" type="U64" constructor="= 0" />
 			</members>
 		</class>
 

+ 1 - 0
src/anki/shader_compiler/ShaderProgramCompiler.cpp

@@ -295,6 +295,7 @@ static void compileVariantAsync(ConstWeakArray<MutatorValue> mutation, const Sha
 
 					ShaderProgramBinaryCodeBlock block;
 					block.m_binary.setArray(code, U32(spirv.getSizeInBytes()));
+					block.m_hash = newHash;
 
 					ctx.m_codeBlocks->emplaceBack(block);
 					ctx.m_codeBlockHashes->emplaceBack(newHash);