Ver Fonte

Add some tests and fix some bugs

Panagiotis Christopoulos Charitos há 6 anos atrás
pai
commit
245b006652

+ 1 - 1
src/anki/shader_compiler/Common.h

@@ -5,7 +5,7 @@
 
 #pragma once
 
-#include <anki/Config.h>
+#include <anki/util/Logger.h>
 
 /// @addtogroup shader_compiler
 /// @{

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

@@ -8,6 +8,22 @@
 namespace anki
 {
 
+class GlslangCtx
+{
+public:
+	GlslangCtx()
+	{
+		glslang::InitializeProcess();
+	}
+
+	~GlslangCtx()
+	{
+		glslang::FinalizeProcess();
+	}
+};
+
+GlslangCtx g_glslangCtx;
+
 static TBuiltInResource setGlslangLimits()
 {
 	TBuiltInResource c = {};

+ 1 - 0
src/anki/shader_compiler/Glslang.h

@@ -5,6 +5,7 @@
 
 #pragma once
 
+#include <anki/shader_compiler/Common.h>
 #include <anki/gr/Enums.h>
 
 #if ANKI_COMPILER_GCC_COMPATIBLE

+ 28 - 16
src/anki/shader_compiler/ShaderProgramParser.cpp

@@ -384,8 +384,14 @@ Error ShaderProgramParser::parsePragmaInput(const StringAuto* begin, const Strin
 		ANKI_PP_ERROR_MALFORMED();
 	}
 
+	if(m_insideShader)
+	{
+		ANKI_PP_ERROR_MALFORMED_MSG("Can't have #pragma input inside shader blocks");
+	}
+
 	m_inputs.emplaceBack(m_alloc);
 	Input& input = m_inputs.getBack();
+	input.m_idx = U32(m_inputs.getSize() - 1);
 
 	// const
 	Bool isConst;
@@ -477,7 +483,7 @@ Error ShaderProgramParser::parsePragmaInput(const StringAuto* begin, const Strin
 		const U32 scalarType = shaderVariableScalarType(input.m_dataType);
 
 		// Add an tag for later pre-processing (when trying to see if the variable is present)
-		m_codeLines.pushBackSprintf("//_anki_input_pesent %s", input.m_name.cstr());
+		m_codeLines.pushBackSprintf("#pragma _anki_input_present_%s", input.m_name.cstr());
 
 		m_globalsLines.pushBackSprintf("#if _ANKI_ACTIVATE_INPUT_%s", input.m_name.cstr());
 		m_globalsLines.pushBackSprintf("#define %s_DEFINED 1", input.m_name.cstr());
@@ -498,8 +504,9 @@ Error ShaderProgramParser::parsePragmaInput(const StringAuto* begin, const Strin
 
 			if(comp == 0)
 			{
-				inputDeclaration.sprintf("const %s = %s(_anki_const_%s_%u",
+				inputDeclaration.sprintf("const %s %s = %s(_anki_const_%s_%u",
 					dataTypeStr.cstr(),
+					input.m_name.cstr(),
 					dataTypeStr.cstr(),
 					input.m_name.cstr(),
 					comp);
@@ -536,7 +543,7 @@ Error ShaderProgramParser::parsePragmaInput(const StringAuto* begin, const Strin
 		}
 
 		// Add an tag for later pre-processing (when trying to see if the variable is present)
-		m_codeLines.pushBackSprintf("//_anki_input_pesent %s", input.m_name.cstr());
+		m_codeLines.pushBackSprintf("#pragma _anki_input_present_%s", input.m_name.cstr());
 
 		m_globalsLines.pushBackSprintf("#if _ANKI_ACTIVATE_INPUT_%s", input.m_name.cstr());
 		m_globalsLines.pushBackSprintf("#define %s_DEFINED 1", input.m_name.cstr());
@@ -558,7 +565,7 @@ Error ShaderProgramParser::parsePragmaInput(const StringAuto* begin, const Strin
 		const char* type = dataTypeStr.cstr();
 
 		// Add an tag for later pre-processing (when trying to see if the variable is present)
-		m_codeLines.pushBackSprintf("//_anki_input_pesent %s", name);
+		m_codeLines.pushBackSprintf("#pragma _anki_input_present_%s", name);
 
 		if(input.m_instanced)
 		{
@@ -574,9 +581,9 @@ Error ShaderProgramParser::parsePragmaInput(const StringAuto* begin, const Strin
 			m_globalsLines.pushBack("#ifdef ANKI_VERTEX_SHADER");
 			m_globalsLines.pushBackSprintf("#define %s_DEFINED 1", name);
 			m_globalsLines.pushBack("#if _ANKI_INSTANCE_COUNT > 1");
-			m_globalsLines.pushBackSprintf("%s %s = _anki_unis._anki_uni_%s[gl_InstanceID];", type, name, name);
+			m_globalsLines.pushBackSprintf("const %s %s = _anki_unis._anki_uni_%s[gl_InstanceID];", type, name, name);
 			m_globalsLines.pushBack("#else");
-			m_globalsLines.pushBackSprintf("%s %s = _anki_unis._anki_uni_%s;", type, name, name);
+			m_globalsLines.pushBackSprintf("const %s %s = _anki_unis._anki_uni_%s;", type, name, name);
 			m_globalsLines.pushBack("#endif");
 			m_globalsLines.pushBack("#endif //ANKI_VERTEX_SHADER");
 			m_globalsLines.pushBack("#else");
@@ -590,7 +597,7 @@ Error ShaderProgramParser::parsePragmaInput(const StringAuto* begin, const Strin
 			m_uboStructLines.pushBack("#endif");
 
 			m_globalsLines.pushBackSprintf("#if _ANKI_ACTIVATE_INPUT_%s", name);
-			m_globalsLines.pushBackSprintf("%s %s = _anki_unis_._anki_uni_%s;", type, name, name);
+			m_globalsLines.pushBackSprintf("const %s %s = _anki_unis_._anki_uni_%s;", type, name, name);
 			m_globalsLines.pushBackSprintf("#define %s_DEFINED 1", name);
 			m_globalsLines.pushBack("#else");
 			m_globalsLines.pushBackSprintf("#define %s_DEFINED 0", name);
@@ -958,6 +965,7 @@ Error ShaderProgramParser::parse()
 	// Create the globals source code
 	if(m_globalsLines.getSize() > 0)
 	{
+		m_globalsLines.pushBack("\n");
 		m_globalsLines.join("\n", m_globalsSource);
 		m_globalsLines.destroy();
 	}
@@ -965,6 +973,7 @@ Error ShaderProgramParser::parse()
 	// Create the code lines
 	if(m_codeLines.getSize())
 	{
+		m_codeLines.pushBack("\n");
 		m_codeLines.join("\n", m_codeSource);
 		m_codeLines.destroy();
 	}
@@ -982,22 +991,23 @@ Error ShaderProgramParser::findActiveInputVars(CString source, BitSet<MAX_SHADER
 
 	for(const String& line : lines)
 	{
-		if(line.find("//_anki_input_pesent") == String::NPOS)
+		const CString prefix = "#pragma _anki_input_present_";
+		if(line.find(prefix) == String::NPOS)
 		{
 			continue;
 		}
 
-		DynamicArrayAuto<StringAuto> tokens(m_alloc);
-		tokenizeLine(line, tokens);
-		ANKI_ASSERT(tokens.getSize() == 2);
+		ANKI_ASSERT(line.getLength() > prefix.getLength());
+		const CString varName = line.getBegin() + prefix.getLength();
 
 		// Find the input var
 		Bool found = false;
 		for(const Input& in : m_inputs)
 		{
-			if(in.m_name == tokens[1])
+			if(in.m_name == varName)
 			{
 				active.set(in.m_idx);
+				found = true;
 				break;
 			}
 		}
@@ -1008,8 +1018,8 @@ Error ShaderProgramParser::findActiveInputVars(CString source, BitSet<MAX_SHADER
 	return Error::NONE;
 }
 
-Error ShaderProgramParser::generateSource(
-	ConstWeakArray<ShaderProgramParserMutatorState> mutatorStates, ShaderProgramVariant& variant) const
+Error ShaderProgramParser::generateVariant(
+	ConstWeakArray<ShaderProgramParserMutatorState> mutatorStates, ShaderProgramParserVariant& variant) const
 {
 	// Sanity checks
 	ANKI_ASSERT(m_codeSource.getLength() > 0);
@@ -1035,6 +1045,7 @@ Error ShaderProgramParser::generateSource(
 	}
 
 	// Init variant
+	::new(&variant) ShaderProgramParserVariant();
 	variant.m_alloc = m_alloc;
 	variant.m_bindings.create(m_alloc, m_inputs.getSize(), -1);
 	variant.m_blockInfos.create(m_alloc, m_inputs.getSize());
@@ -1068,7 +1079,7 @@ Error ShaderProgramParser::generateSource(
 	StringAuto header(m_alloc);
 	header.sprintf(SHADER_HEADER,
 		m_backendMinor,
-		m_backendMinor,
+		m_backendMajor,
 		GPU_VENDOR_STR[m_gpuVendor].cstr(),
 		MAX_BINDLESS_TEXTURES,
 		MAX_BINDLESS_IMAGES);
@@ -1081,7 +1092,7 @@ Error ShaderProgramParser::generateSource(
 		src.append(header);
 		src.append("#define ANKI_VERTEX_SHADER 1\n"); // Something random to avoid compilation errors
 		src.append(mutatorDefines);
-		src.append(m_globalsSource);
+		src.append(m_codeSource);
 		ANKI_CHECK(findActiveInputVars(src, variant.m_activeInputVarsMask));
 
 		StringListAuto lines(m_alloc);
@@ -1091,6 +1102,7 @@ Error ShaderProgramParser::generateSource(
 			lines.pushBackSprintf("#define _ANKI_ACTIVATE_INPUT_%s %u", in.m_name.cstr(), active);
 		}
 
+		lines.pushBack("\n");
 		lines.join("\n", activeInputs);
 	}
 

+ 25 - 9
src/anki/shader_compiler/ShaderProgramParser.h

@@ -17,7 +17,7 @@ namespace anki
 
 // Forward
 class ShaderProgramParser;
-class ShaderProgramVariant;
+class ShaderProgramParserVariant;
 
 /// @addtogroup resource
 /// @{
@@ -63,7 +63,7 @@ private:
 class ShaderProgramParserInput
 {
 	friend ShaderProgramParser;
-	friend ShaderProgramVariant;
+	friend ShaderProgramParserVariant;
 
 public:
 	ShaderProgramParserInput(GenericMemoryPoolAllocator<U8> alloc)
@@ -121,11 +121,21 @@ private:
 };
 
 /// @memberof ShaderProgramParser
-class ShaderProgramVariant
+class ShaderProgramParserVariant
 {
 	friend class ShaderProgramParser;
 
 public:
+	~ShaderProgramParserVariant()
+	{
+		for(String& s : m_sources)
+		{
+			s.destroy(m_alloc);
+		}
+		m_blockInfos.destroy(m_alloc);
+		m_bindings.destroy(m_alloc);
+	}
+
 	CString getSource(ShaderType type) const
 	{
 		return m_sources[type];
@@ -181,11 +191,17 @@ public:
 	ShaderProgramParser(CString fname,
 		ShaderProgramParserFilesystemInterface* fsystem,
 		GenericMemoryPoolAllocator<U8> alloc,
-		U32 pushConstantsSize)
+		U32 pushConstantsSize,
+		U32 backendMinor,
+		U32 backendMajor,
+		GpuVendor gpuVendor)
 		: m_alloc(alloc)
 		, m_fname(alloc, fname)
 		, m_fsystem(fsystem)
 		, m_pushConstSize(pushConstantsSize)
+		, m_backendMinor(backendMinor)
+		, m_backendMajor(backendMajor)
+		, m_gpuVendor(gpuVendor)
 	{
 	}
 
@@ -197,8 +213,8 @@ public:
 	ANKI_USE_RESULT Error parse();
 
 	/// Get the source (and a few more things) given a list of mutators.
-	ANKI_USE_RESULT Error generateSource(
-		ConstWeakArray<ShaderProgramParserMutatorState> mutatorStates, ShaderProgramVariant& variant) const;
+	ANKI_USE_RESULT Error generateVariant(
+		ConstWeakArray<ShaderProgramParserMutatorState> mutatorStates, ShaderProgramParserVariant& variant) const;
 
 	ConstWeakArray<ShaderProgramParserMutator> getMutators() const
 	{
@@ -246,9 +262,9 @@ private:
 	U32 m_instancedMutatorIdx = MAX_U32;
 	U32 m_specConstIdx = 0;
 	const U32 m_pushConstSize = 0;
-	const U32 m_backendMinor = 1; // TODO
-	const U32 m_backendMajor = 1; // TODO
-	const GpuVendor m_gpuVendor = GpuVendor::AMD; // TODO
+	const U32 m_backendMinor = 1;
+	const U32 m_backendMajor = 1;
+	const GpuVendor m_gpuVendor = GpuVendor::AMD;
 	Bool m_foundAtLeastOneInstancedInput = false;
 
 	ANKI_USE_RESULT Error parseFile(CString fname, U32 depth);

+ 50 - 6
src/anki/util/Singleton.h

@@ -6,6 +6,7 @@
 #pragma once
 
 #include <anki/util/Assert.h>
+#include <anki/util/Thread.h>
 #include <utility>
 
 namespace anki
@@ -99,18 +100,18 @@ typename SingletonInit<T>::Value* SingletonInit<T>::m_instance = nullptr;
 
 /// This template makes a class singleton with thread local instance
 template<typename T>
-class SingletonThreadSafe
+class SingletonThreadLocal
 {
 public:
 	typedef T Value;
 
 	// Non copyable
-	SingletonThreadSafe(const SingletonThreadSafe&) = delete;
-	SingletonThreadSafe& operator=(const SingletonThreadSafe&) = delete;
+	SingletonThreadLocal(const SingletonThreadLocal&) = delete;
+	SingletonThreadLocal& operator=(const SingletonThreadLocal&) = delete;
 
 	// Non constructable
-	SingletonThreadSafe() = delete;
-	~SingletonThreadSafe() = delete;
+	SingletonThreadLocal() = delete;
+	~SingletonThreadLocal() = delete;
 
 	/// Get instance
 	static Value& get()
@@ -132,7 +133,50 @@ private:
 };
 
 template<typename T>
-thread_local typename SingletonThreadSafe<T>::Value* SingletonThreadSafe<T>::m_instance = nullptr;
+thread_local typename SingletonThreadLocal<T>::Value* SingletonThreadLocal<T>::m_instance = nullptr;
+
+/// This template makes a class with a destructor with arguments singleton
+template<typename T>
+class SingletonThreadsafe
+{
+public:
+	typedef T Value;
+
+	// Non copyable
+	SingletonThreadsafe(const SingletonThreadsafe&) = delete;
+	SingletonThreadsafe& operator=(const SingletonThreadsafe&) = delete;
+
+	// Non constructable
+	SingletonThreadsafe() = delete;
+	~SingletonThreadsafe() = delete;
+
+	/// Get instance
+	static Value& get()
+	{
+		LockGuard<Mutex> lock(m_mtx);
+		return *(m_instance ? m_instance : (m_instance = new Value));
+	}
+
+	/// Cleanup
+	static void destroy()
+	{
+		LockGuard<Mutex> lock(m_mtx);
+		if(m_instance)
+		{
+			delete m_instance;
+		}
+	}
+
+private:
+	static Value* m_instance;
+	static Mutex m_mtx;
+};
+
+template<typename T>
+typename SingletonThreadsafe<T>::Value* SingletonThreadsafe<T>::m_instance = nullptr;
+
+template<typename T>
+Mutex SingletonThreadsafe<T>::m_mtx;
 /// @}
 
 } // end namespace anki

+ 11 - 0
src/anki/util/String.h

@@ -688,6 +688,17 @@ public:
 		return *this;
 	}
 
+	/// Copy from string.
+	StringAuto& operator=(const CString& b)
+	{
+		destroy();
+		if(!b.isEmpty())
+		{
+			create(b.getBegin(), b.getEnd());
+		}
+		return *this;
+	}
+
 	/// Move one string to this one.
 	StringAuto& operator=(StringAuto&& b)
 	{

+ 58 - 0
tests/shader_compiler/ShaderProgramParser.cpp

@@ -8,4 +8,62 @@
 
 ANKI_TEST(ShaderCompiler, ShaderCompilerParser)
 {
+	HeapAllocator<U8> alloc(allocAligned, nullptr);
+
+	class FilesystemInterface : public ShaderProgramParserFilesystemInterface
+	{
+	public:
+		U32 count = 0;
+
+		Error readAllText(CString filename, StringAuto& txt) final
+		{
+			if(count == 0)
+			{
+				txt = R"(
+#pragma anki mutator M0 1 2
+#pragma anki mutator M1 3 4
+
+#if M0 == 1
+#pragma anki input Vec3 var0
+#endif
+
+#if M1 == 4
+#pragma anki input const Vec3 var1
+#endif
+
+#pragma anki start vert
+
+// vert
+#pragma anki end
+
+#pragma anki start frag
+// frag
+#pragma anki end
+				)";
+			}
+			else
+			{
+				return Error::FUNCTION_FAILED;
+			}
+
+			++count;
+			return Error::NONE;
+		}
+	} interface;
+
+	ShaderProgramParser parser("filename0", &interface, alloc, 128, 1, 1, GpuVendor::AMD);
+	ANKI_TEST_EXPECT_NO_ERR(parser.parse());
+
+	// Check inputs
+	ANKI_TEST_EXPECT_EQ(parser.getInputs().getSize(), 2);
+
+	// Test a variant
+	Array<ShaderProgramParserMutatorState, 2> arr = {{{&parser.getMutators()[0], 2}, {&parser.getMutators()[1], 4}}};
+	ConstWeakArray<ShaderProgramParserMutatorState> mutatorStates(arr);
+
+	ShaderProgramParserVariant variant;
+	ANKI_TEST_EXPECT_NO_ERR(parser.generateVariant(mutatorStates, variant));
+	ANKI_TEST_EXPECT_EQ(variant.isInputActive(parser.getInputs()[0]), false);
+	ANKI_TEST_EXPECT_EQ(variant.isInputActive(parser.getInputs()[1]), true);
+	// printf("%s\n", variant.getSource(ShaderType::VERTEX).cstr());
 }