Browse Source

Add the ray tracing shader types

Panagiotis Christopoulos Charitos 5 years ago
parent
commit
6c52934cf0

+ 19 - 3
src/anki/gr/Enums.h

@@ -451,16 +451,24 @@ enum class ShaderType : U8
 	GEOMETRY,
 	GEOMETRY,
 	FRAGMENT,
 	FRAGMENT,
 	COMPUTE,
 	COMPUTE,
+	RAY_GEN,
+	ANY_HIT,
+	CLOSEST_HIT,
+	MISS,
+	INTERSECTION,
+	CALLABLE,
 
 
 	COUNT,
 	COUNT,
-	FIRST = VERTEX,
+	FIRST = 0,
 	LAST = COUNT - 1,
 	LAST = COUNT - 1,
 	FIRST_GRAPHICS = VERTEX,
 	FIRST_GRAPHICS = VERTEX,
 	LAST_GRAPHICS = FRAGMENT,
 	LAST_GRAPHICS = FRAGMENT,
+	FIRST_RAY_TRACING = RAY_GEN,
+	LAST_RAY_TRACING = CALLABLE,
 };
 };
 ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(ShaderType, inline)
 ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(ShaderType, inline)
 
 
-enum class ShaderTypeBit : U8
+enum class ShaderTypeBit : U16
 {
 {
 	VERTEX = 1 << 0,
 	VERTEX = 1 << 0,
 	TESSELLATION_CONTROL = 1 << 1,
 	TESSELLATION_CONTROL = 1 << 1,
@@ -468,9 +476,17 @@ enum class ShaderTypeBit : U8
 	GEOMETRY = 1 << 3,
 	GEOMETRY = 1 << 3,
 	FRAGMENT = 1 << 4,
 	FRAGMENT = 1 << 4,
 	COMPUTE = 1 << 5,
 	COMPUTE = 1 << 5,
+	RAY_GEN = 1 << 6,
+	ANY_HIT = 1 << 7,
+	CLOSEST_HIT = 1 << 8,
+	MISS = 1 << 9,
+	INTERSECTION = 1 << 10,
+	CALLABLE = 1 << 11,
 
 
 	NONE = 0,
 	NONE = 0,
-	ALL = VERTEX | TESSELLATION_CONTROL | TESSELLATION_EVALUATION | GEOMETRY | FRAGMENT | COMPUTE,
+	ALL_GRAPHICS = VERTEX | TESSELLATION_CONTROL | TESSELLATION_EVALUATION | GEOMETRY | FRAGMENT,
+	ALL_RAY_TRACING = RAY_GEN | ANY_HIT | CLOSEST_HIT | MISS | INTERSECTION | CALLABLE,
+	ALL = ALL_GRAPHICS | COMPUTE | ALL_RAY_TRACING,
 };
 };
 ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(ShaderTypeBit, inline)
 ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(ShaderTypeBit, inline)
 
 

+ 7 - 15
src/anki/gr/ShaderProgram.h

@@ -18,7 +18,7 @@ namespace anki
 class ShaderProgramInitInfo : public GrBaseInitInfo
 class ShaderProgramInitInfo : public GrBaseInitInfo
 {
 {
 public:
 public:
-	Array<ShaderPtr, U(ShaderType::COUNT)> m_shaders = {};
+	Array<ShaderPtr, U32(ShaderType::COUNT)> m_shaders = {};
 
 
 	ShaderProgramInitInfo(CString name = {})
 	ShaderProgramInitInfo(CString name = {})
 		: GrBaseInitInfo(name)
 		: GrBaseInitInfo(name)
@@ -40,23 +40,15 @@ public:
 
 
 	Bool isValid() const
 	Bool isValid() const
 	{
 	{
-		I32 invalid = 0;
-
-		if(m_shaders[ShaderType::COMPUTE])
-		{
-			invalid |= m_shaders[ShaderType::VERTEX] || m_shaders[ShaderType::TESSELLATION_CONTROL]
-					   || m_shaders[ShaderType::TESSELLATION_EVALUATION] || m_shaders[ShaderType::GEOMETRY]
-					   || m_shaders[ShaderType::FRAGMENT];
-		}
-		else
+		ShaderTypeBit mask = ShaderTypeBit::NONE;
+		for(ShaderType i : EnumIterable<ShaderType>())
 		{
 		{
-			invalid |= !m_shaders[ShaderType::VERTEX] || !m_shaders[ShaderType::FRAGMENT];
+			mask |= (m_shaders[i]) ? shaderTypeToBit(i) : ShaderTypeBit::NONE;
 		}
 		}
 
 
-		for(ShaderType type = ShaderType::FIRST; type < ShaderType::COUNT; ++type)
-		{
-			invalid |= m_shaders[type] && m_shaders[type]->getShaderType() != type;
-		}
+		U32 invalid = 0;
+		invalid |= !!(mask & ShaderTypeBit::ALL_GRAPHICS) && !!(mask & ~ShaderTypeBit::ALL_GRAPHICS);
+		invalid |= !!(mask & ShaderTypeBit::COMPUTE) && !!(mask & ~ShaderTypeBit::COMPUTE);
 
 
 		return invalid == 0;
 		return invalid == 0;
 	}
 	}

+ 4 - 3
src/anki/gr/vulkan/DescriptorSet.h

@@ -24,15 +24,16 @@ class DSLayoutCacheEntry;
 /// @addtogroup vulkan
 /// @addtogroup vulkan
 /// @{
 /// @{
 
 
-class alignas(4) DescriptorBinding
+class alignas(8) DescriptorBinding
 {
 {
 public:
 public:
-	DescriptorType m_type = DescriptorType::COUNT;
 	ShaderTypeBit m_stageMask = ShaderTypeBit::NONE;
 	ShaderTypeBit m_stageMask = ShaderTypeBit::NONE;
+	DescriptorType m_type = DescriptorType::COUNT;
 	U8 m_binding = MAX_U8;
 	U8 m_binding = MAX_U8;
 	U8 m_arraySizeMinusOne = 0;
 	U8 m_arraySizeMinusOne = 0;
+	Array<U8, 3> m_padding = {};
 };
 };
-static_assert(sizeof(DescriptorBinding) == 4, "Should be packed because it will be hashed");
+static_assert(sizeof(DescriptorBinding) == 8, "Should be packed because it will be hashed");
 
 
 class DescriptorSetLayoutInitInfo
 class DescriptorSetLayoutInitInfo
 {
 {

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

@@ -982,8 +982,7 @@ VkBool32 GrManagerImpl::debugReportCallbackEXT(VkDebugReportFlagsEXT flags, VkDe
 
 
 void GrManagerImpl::printPipelineShaderInfo(VkPipeline ppline, CString name, ShaderTypeBit stages, U64 hash) const
 void GrManagerImpl::printPipelineShaderInfo(VkPipeline ppline, CString name, ShaderTypeBit stages, U64 hash) const
 {
 {
-	Error err = printPipelineShaderInfoInternal(ppline, name, stages, hash);
-	if(err)
+	if(printPipelineShaderInfoInternal(ppline, name, stages, hash))
 	{
 	{
 		ANKI_VK_LOGE("Ignoring previous errors");
 		ANKI_VK_LOGE("Ignoring previous errors");
 	}
 	}

+ 1 - 3
src/anki/gr/vulkan/ShaderImpl.cpp

@@ -124,9 +124,7 @@ void ShaderImpl::doReflection(ConstWeakArray<U8> spirv, SpecConstsVector& specCo
 	spirv_cross::ShaderResources rsrc = spvc.get_shader_resources();
 	spirv_cross::ShaderResources rsrc = spvc.get_shader_resources();
 	spirv_cross::ShaderResources rsrcActive = spvc.get_shader_resources(spvc.get_active_interface_variables());
 	spirv_cross::ShaderResources rsrcActive = spvc.get_shader_resources(spvc.get_active_interface_variables());
 
 
-	Array<U32, MAX_DESCRIPTOR_SETS> counts = {{
-		0,
-	}};
+	Array<U32, MAX_DESCRIPTOR_SETS> counts = {};
 	Array2d<DescriptorBinding, MAX_DESCRIPTOR_SETS, MAX_BINDINGS_PER_DESCRIPTOR_SET> descriptors;
 	Array2d<DescriptorBinding, MAX_DESCRIPTOR_SETS, MAX_BINDINGS_PER_DESCRIPTOR_SET> descriptors;
 
 
 	auto func = [&](const spirv_cross::SmallVector<spirv_cross::Resource>& resources, DescriptorType type) -> void {
 	auto func = [&](const spirv_cross::SmallVector<spirv_cross::Resource>& resources, DescriptorType type) -> void {

+ 2 - 2
src/anki/gr/vulkan/ShaderProgramImpl.cpp

@@ -45,7 +45,7 @@ Error ShaderProgramImpl::init(const ShaderProgramInitInfo& inf)
 				continue;
 				continue;
 			}
 			}
 
 
-			m_stages |= static_cast<ShaderTypeBit>(1 << stype);
+			m_stages |= ShaderTypeBit(1 << stype);
 
 
 			const ShaderImpl& simpl = *static_cast<const ShaderImpl*>(m_shaders[stype].get());
 			const ShaderImpl& simpl = *static_cast<const ShaderImpl*>(m_shaders[stype].get());
 
 
@@ -118,7 +118,7 @@ Error ShaderProgramImpl::init(const ShaderProgramInitInfo& inf)
 
 
 	// Get some masks
 	// Get some masks
 	//
 	//
-	const Bool graphicsProg = !!(m_stages & ShaderTypeBit::VERTEX);
+	const Bool graphicsProg = !!(m_stages & ShaderTypeBit::ALL_GRAPHICS);
 	if(graphicsProg)
 	if(graphicsProg)
 	{
 	{
 		m_refl.m_attributeMask = static_cast<const ShaderImpl*>(m_shaders[ShaderType::VERTEX].get())->m_attributeMask;
 		m_refl.m_attributeMask = static_cast<const ShaderImpl*>(m_shaders[ShaderType::VERTEX].get())->m_attributeMask;

+ 2 - 2
src/anki/gr/vulkan/ShaderProgramImpl.h

@@ -89,10 +89,10 @@ public:
 	}
 	}
 
 
 private:
 private:
-	Array<ShaderPtr, U(ShaderType::COUNT)> m_shaders;
+	Array<ShaderPtr, U32(ShaderType::COUNT)> m_shaders;
 	ShaderTypeBit m_stages = ShaderTypeBit::NONE;
 	ShaderTypeBit m_stages = ShaderTypeBit::NONE;
 
 
-	Array<VkPipelineShaderStageCreateInfo, U(ShaderType::COUNT) - 1> m_shaderCreateInfos;
+	Array<VkPipelineShaderStageCreateInfo, U32(ShaderType::FRAGMENT - ShaderType::VERTEX) + 1> m_shaderCreateInfos;
 	U32 m_shaderCreateInfoCount = 0;
 	U32 m_shaderCreateInfoCount = 0;
 
 
 	PipelineLayout m_pplineLayout = {};
 	PipelineLayout m_pplineLayout = {};

+ 0 - 47
src/anki/resource/Common.cpp

@@ -27,51 +27,4 @@ void ResourcePtrDeleter<T>::operator()(T* ptr)
 #undef ANKI_INSTANTIATE_RESOURCE
 #undef ANKI_INSTANTIATE_RESOURCE
 #undef ANKI_INSTANSIATE_RESOURCE_DELIMITER
 #undef ANKI_INSTANSIATE_RESOURCE_DELIMITER
 
 
-const CString& shaderTypeToFileExtension(ShaderType type)
-{
-	static const Array<CString, U(ShaderType::COUNT)> mapping = {
-		{".vert.glsl", ".tc.glsl", ".te.glsl", ".geom.glsl", ".frag.glsl", ".comp.glsl"}};
-
-	return mapping[type];
-}
-
-Error fileExtensionToShaderType(const CString& filename, ShaderType& type)
-{
-	type = ShaderType::COUNT;
-	Error err = Error::NONE;
-
-	// Find the shader type
-	if(filename.find(".vert.glsl") != ResourceFilename::NPOS)
-	{
-		type = ShaderType::VERTEX;
-	}
-	else if(filename.find(".tc.glsl") != ResourceFilename::NPOS)
-	{
-		type = ShaderType::TESSELLATION_CONTROL;
-	}
-	else if(filename.find(".te.glsl") != ResourceFilename::NPOS)
-	{
-		type = ShaderType::TESSELLATION_EVALUATION;
-	}
-	else if(filename.find(".geom.glsl") != ResourceFilename::NPOS)
-	{
-		type = ShaderType::GEOMETRY;
-	}
-	else if(filename.find(".frag.glsl") != ResourceFilename::NPOS)
-	{
-		type = ShaderType::FRAGMENT;
-	}
-	else if(filename.find(".comp.glsl") != ResourceFilename::NPOS)
-	{
-		type = ShaderType::COMPUTE;
-	}
-	else
-	{
-		ANKI_RESOURCE_LOGE("Wrong shader file format: %s", &filename[0]);
-		err = Error::USER_DATA;
-	}
-
-	return err;
-}
-
 } // end namespace anki
 } // end namespace anki

+ 0 - 6
src/anki/resource/Common.h

@@ -86,12 +86,6 @@ using TempResourceAllocator = StackAllocator<T>;
 
 
 /// An alias that denotes a ResourceFilesystem path.
 /// An alias that denotes a ResourceFilesystem path.
 using ResourceFilename = CString;
 using ResourceFilename = CString;
-
-/// Given a shader type return the appropriate file extension.
-ANKI_USE_RESULT const CString& shaderTypeToFileExtension(ShaderType type);
-
-/// Given a filename return the shader type.
-ANKI_USE_RESULT Error fileExtensionToShaderType(const CString& filename, ShaderType& type);
 /// @}
 /// @}
 
 
 } // end namespace anki
 } // end namespace anki

+ 18 - 0
src/anki/shader_compiler/Glslang.cpp

@@ -164,6 +164,24 @@ static EShLanguage ankiToGlslangShaderType(ShaderType shaderType)
 	case ShaderType::COMPUTE:
 	case ShaderType::COMPUTE:
 		gslangShader = EShLangCompute;
 		gslangShader = EShLangCompute;
 		break;
 		break;
+	case ShaderType::RAY_GEN:
+		gslangShader = EShLangRayGen;
+		break;
+	case ShaderType::ANY_HIT:
+		gslangShader = EShLangAnyHit;
+		break;
+	case ShaderType::CLOSEST_HIT:
+		gslangShader = EShLangClosestHit;
+		break;
+	case ShaderType::MISS:
+		gslangShader = EShLangMiss;
+		break;
+	case ShaderType::INTERSECTION:
+		gslangShader = EShLangIntersect;
+		break;
+	case ShaderType::CALLABLE:
+		gslangShader = EShLangCallable;
+		break;
 	default:
 	default:
 		ANKI_ASSERT(0);
 		ANKI_ASSERT(0);
 		gslangShader = EShLangCount;
 		gslangShader = EShLangCount;

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

@@ -205,7 +205,7 @@ static void compileVariantAsync(ConstWeakArray<MutatorValue> mutation, const Sha
 	public:
 	public:
 		GenericMemoryPoolAllocator<U8> m_tmpAlloc;
 		GenericMemoryPoolAllocator<U8> m_tmpAlloc;
 		GenericMemoryPoolAllocator<U8> m_binaryAlloc;
 		GenericMemoryPoolAllocator<U8> m_binaryAlloc;
-		DynamicArrayAuto<MutatorValue> m_mutation{m_tmpAlloc};
+		DynamicArrayAuto<MutatorValue> m_mutation = {m_tmpAlloc};
 		const ShaderProgramParser* m_parser;
 		const ShaderProgramParser* m_parser;
 		ShaderProgramBinaryVariant* m_variant;
 		ShaderProgramBinaryVariant* m_variant;
 		DynamicArrayAuto<ShaderProgramBinaryCodeBlock>* m_codeBlocks;
 		DynamicArrayAuto<ShaderProgramBinaryCodeBlock>* m_codeBlocks;
@@ -242,8 +242,18 @@ static void compileVariantAsync(ConstWeakArray<MutatorValue> mutation, const Sha
 		}
 		}
 
 
 		// All good, compile the variant
 		// All good, compile the variant
-		Array<DynamicArrayAuto<U8>, U32(ShaderType::COUNT)> spirvs = {
-			{{tmpAlloc}, {tmpAlloc}, {tmpAlloc}, {tmpAlloc}, {tmpAlloc}, {tmpAlloc}}};
+		Array<DynamicArrayAuto<U8>, U32(ShaderType::COUNT)> spirvs = {{{tmpAlloc},
+																	   {tmpAlloc},
+																	   {tmpAlloc},
+																	   {tmpAlloc},
+																	   {tmpAlloc},
+																	   {tmpAlloc},
+																	   {tmpAlloc},
+																	   {tmpAlloc},
+																	   {tmpAlloc},
+																	   {tmpAlloc},
+																	   {tmpAlloc},
+																	   {tmpAlloc}}};
 		const Error err = compileSpirv(ctx.m_mutation, *ctx.m_parser, tmpAlloc, spirvs);
 		const Error err = compileSpirv(ctx.m_mutation, *ctx.m_parser, tmpAlloc, spirvs);
 
 
 		if(!err)
 		if(!err)

+ 32 - 4
src/anki/shader_compiler/ShaderProgramParser.cpp

@@ -17,9 +17,10 @@ namespace anki
 	return Error::USER_DATA
 	return Error::USER_DATA
 
 
 static const Array<CString, U32(ShaderType::COUNT)> SHADER_STAGE_NAMES = {
 static const Array<CString, U32(ShaderType::COUNT)> SHADER_STAGE_NAMES = {
-	{"VERTEX", "TESSELLATION_CONTROL", "TESSELLATION_EVALUATION", "GEOMETRY", "FRAGMENT", "COMPUTE"}};
+	{"VERTEX", "TESSELLATION_CONTROL", "TESSELLATION_EVALUATION", "GEOMETRY", "FRAGMENT", "COMPUTE", "RAY_GEN",
+	 "ANY_HIT", "CLOSEST_HIT", "MISS", "INTERSECTION", "CALLABLE"}};
 
 
-static const char* SHADER_HEADER = R"(#version 450 core
+static const char* SHADER_HEADER = R"(#version 460 core
 #define ANKI_BACKEND_MINOR %u
 #define ANKI_BACKEND_MINOR %u
 #define ANKI_BACKEND_MAJOR %u
 #define ANKI_BACKEND_MAJOR %u
 #define ANKI_VENDOR_%s 1
 #define ANKI_VENDOR_%s 1
@@ -45,6 +46,9 @@ static const char* SHADER_HEADER = R"(#version 450 core
 #extension GL_EXT_buffer_reference : enable
 #extension GL_EXT_buffer_reference : enable
 #extension GL_ARB_gpu_shader_int64 : enable
 #extension GL_ARB_gpu_shader_int64 : enable
 
 
+#extension GL_EXT_nonuniform_qualifier : enable
+#extension GL_EXT_scalar_block_layout : enable
+
 #define ANKI_MAX_BINDLESS_TEXTURES %u
 #define ANKI_MAX_BINDLESS_TEXTURES %u
 #define ANKI_MAX_BINDLESS_IMAGES %u
 #define ANKI_MAX_BINDLESS_IMAGES %u
 
 
@@ -216,6 +220,30 @@ Error ShaderProgramParser::parsePragmaStart(const StringAuto* begin, const Strin
 	{
 	{
 		shaderType = ShaderType::COMPUTE;
 		shaderType = ShaderType::COMPUTE;
 	}
 	}
+	else if(*begin == "rgen")
+	{
+		shaderType = ShaderType::RAY_GEN;
+	}
+	else if(*begin == "ahit")
+	{
+		shaderType = ShaderType::ANY_HIT;
+	}
+	else if(*begin == "chit")
+	{
+		shaderType = ShaderType::CLOSEST_HIT;
+	}
+	else if(*begin == "miss")
+	{
+		shaderType = ShaderType::MISS;
+	}
+	else if(*begin == "int")
+	{
+		shaderType = ShaderType::INTERSECTION;
+	}
+	else if(*begin == "call")
+	{
+		shaderType = ShaderType::CALLABLE;
+	}
 	else
 	else
 	{
 	{
 		ANKI_PP_ERROR_MALFORMED();
 		ANKI_PP_ERROR_MALFORMED();
@@ -757,9 +785,9 @@ Error ShaderProgramParser::generateVariant(ConstWeakArray<MutatorValue> mutation
 	generateAnkiShaderHeader(m_gpuCapabilities, m_bindlessLimits, header);
 	generateAnkiShaderHeader(m_gpuCapabilities, m_bindlessLimits, header);
 
 
 	// Generate souce per stage
 	// Generate souce per stage
-	for(ShaderType shaderType = ShaderType::FIRST; shaderType < ShaderType::COUNT; ++shaderType)
+	for(ShaderType shaderType : EnumIterable<ShaderType>())
 	{
 	{
-		if(!((1u << ShaderTypeBit(shaderType)) & m_shaderTypes))
+		if(!(ShaderTypeBit(1u << shaderType) & m_shaderTypes))
 		{
 		{
 			continue;
 			continue;
 		}
 		}

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

@@ -69,7 +69,7 @@ public:
 
 
 private:
 private:
 	GenericMemoryPoolAllocator<U8> m_alloc;
 	GenericMemoryPoolAllocator<U8> m_alloc;
-	Array<String, U(ShaderType::COUNT)> m_sources;
+	Array<String, U32(ShaderType::COUNT)> m_sources;
 };
 };
 
 
 /// This is a special preprocessor that run before the usual preprocessor. Its purpose is to add some meta information
 /// This is a special preprocessor that run before the usual preprocessor. Its purpose is to add some meta information
@@ -81,7 +81,7 @@ private:
 /// #pragma anki mutator NAME VALUE0 [VALUE1 [VALUE2] ...]
 /// #pragma anki mutator NAME VALUE0 [VALUE1 [VALUE2] ...]
 /// #pragma anki rewrite_mutation NAME_A VALUE0 NAME_B VALUE1 [NAME_C VALUE3...] to
 /// #pragma anki rewrite_mutation NAME_A VALUE0 NAME_B VALUE1 [NAME_C VALUE3...] to
 ///                               NAME_A VALUE4 NAME_B VALUE5 [NAME_C VALUE6...]
 ///                               NAME_A VALUE4 NAME_B VALUE5 [NAME_C VALUE6...]
-/// #pragma anki start {vert | tessc | tesse | geom | frag | comp}
+/// #pragma anki start {vert | tessc | tesse | geom | frag | comp | rgen | ahit | chit | miss | int | call}
 /// #pragma anki end
 /// #pragma anki end
 ///
 ///
 /// 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.

+ 1 - 1
src/anki/util/Allocator.h

@@ -82,7 +82,7 @@ public:
 
 
 	/// Constuctor that creates a pool
 	/// Constuctor that creates a pool
 	template<typename... TArgs>
 	template<typename... TArgs>
-	explicit GenericPoolAllocator(AllocAlignedCallback allocCb, void* allocCbUserData, TArgs&&... args)
+	GenericPoolAllocator(AllocAlignedCallback allocCb, void* allocCbUserData, TArgs&&... args)
 	{
 	{
 		m_pool = static_cast<TPool*>(allocCb(allocCbUserData, nullptr, sizeof(TPool), alignof(TPool)));
 		m_pool = static_cast<TPool*>(allocCb(allocCbUserData, nullptr, sizeof(TPool), alignof(TPool)));
 		if(ANKI_UNLIKELY(!m_pool))
 		if(ANKI_UNLIKELY(!m_pool))

+ 35 - 0
tests/gr/Gr.cpp

@@ -2622,4 +2622,39 @@ void main()
 	COMMON_END();
 	COMMON_END();
 }
 }
 
 
+ANKI_TEST(Gr, RayGen)
+{
+	COMMON_BEGIN();
+
+	HeapAllocator<U8> alloc = {allocAligned, nullptr};
+
+	const CString commonSrc = R"(
+layout(set = 0, binding = 0, std430) readonly buffer b_s00
+{
+	U32 u_indices[];
+};
+
+layout(set = 0, binding = 1, scalar) readonly buffer b_s01
+{
+	Vec3 u_vertPositions[];
+};
+)";
+
+	// Ahit & chit shaders
+	{
+		const CString src = R"(
+void main()
+{
+
+}
+)";
+
+		StringAuto fullSrc = {alloc};
+		fullSrc.sprintf("%s\n%s", commonSrc.cstr(), src.cstr());
+		ANKI_TEST_EXPECT_NO_ERR(createShader(fullSrc, ShaderType::ANY_HIT, *gr));
+	}
+
+	COMMON_END();
+}
+
 } // end namespace anki
 } // end namespace anki