Browse Source

Some work

Panagiotis Christopoulos Charitos 6 năm trước cách đây
mục cha
commit
d79fd5a9e3

+ 308 - 17
src/anki/shader_compiler/ShaderProgramParser.cpp

@@ -147,6 +147,8 @@ Error ShaderProgramParser::parsePragmaDescriptorSet(
 		ANKI_PP_ERROR_MALFORMED_MSG("The descriptor set index is too high");
 	}
 
+	m_globalsLines.pushFrontSprintf("#define _ANKI_DSET %u", m_set);
+
 	return Error::NONE;
 }
 
@@ -163,32 +165,32 @@ Error ShaderProgramParser::parsePragmaStart(const StringAuto* begin, const Strin
 	if(*begin == "vert")
 	{
 		shaderType = ShaderType::VERTEX;
-		m_lines.pushBack("#ifdef _ANKI_VERTEX_SHADER");
+		m_lines.pushBack("#ifdef ANKI_VERTEX_SHADER");
 	}
 	else if(*begin == "tessc")
 	{
 		shaderType = ShaderType::TESSELLATION_CONTROL;
-		m_lines.pushBack("#ifdef _ANKI_TESSELATION_CONTROL_SHADER");
+		m_lines.pushBack("#ifdef ANKI_TESSELATION_CONTROL_SHADER");
 	}
 	else if(*begin == "tesse")
 	{
 		shaderType = ShaderType::TESSELLATION_EVALUATION;
-		m_lines.pushBack("#ifdef _ANKI_TESSELLATION_EVALUATION_SHADER");
+		m_lines.pushBack("#ifdef ANKI_TESSELLATION_EVALUATION_SHADER");
 	}
 	else if(*begin == "geom")
 	{
 		shaderType = ShaderType::GEOMETRY;
-		m_lines.pushBack("#ifdef _ANKI_GEOMETRY_SHADER");
+		m_lines.pushBack("#ifdef ANKI_GEOMETRY_SHADER");
 	}
 	else if(*begin == "frag")
 	{
 		shaderType = ShaderType::FRAGMENT;
-		m_lines.pushBack("#ifdef _ANKI_FRAGMENT_SHADER");
+		m_lines.pushBack("#ifdef ANKI_FRAGMENT_SHADER");
 	}
 	else if(*begin == "comp")
 	{
 		shaderType = ShaderType::COMPUTE;
-		m_lines.pushBack("#ifdef _ANKI_COMPUTE_SHADER");
+		m_lines.pushBack("#ifdef ANKI_COMPUTE_SHADER");
 	}
 	else
 	{
@@ -255,18 +257,18 @@ Error ShaderProgramParser::parsePragmaInput(const StringAuto* begin, const Strin
 	m_inputs.emplaceBack(m_alloc);
 	Input& input = m_inputs.getBack();
 
-	if(m_insideShader)
-	{
-		ANKI_PP_ERROR_MALFORMED_MSG("Can't have #pragma input inside a pragma start/end");
-	}
-
 	// const
+	Bool isConst;
 	{
 		if(*begin == "const")
 		{
-			input.m_specConstId = m_specConstIdx++;
+			isConst = true;
 			++begin;
 		}
+		else
+		{
+			isConst = false;
+		}
 	}
 
 	// instanced
@@ -369,11 +371,12 @@ Error ShaderProgramParser::parsePragmaInput(const StringAuto* begin, const Strin
 		const char* name = input.m_name.cstr();
 		const char* type = dataTypeStr.cstr();
 
-		m_globalsLines.pushBackSprintf("#define %s_DEFINED 1", input.m_name.cstr());
+		// Add an tag for later pre-processing (when trying to see if the variable is present)
+		m_lines.pushBackSprintf("//_anki_input_pesent %s", name);
 
 		if(input.m_instanced)
 		{
-			m_uboStructLines.pushBackSprintf("#if _ANKI_%s_ACTIVE", name);
+			m_uboStructLines.pushBackSprintf("#if _ANKI_UNI_%s_ACTIVE", name);
 			m_uboStructLines.pushBack("#if _ANKI_INSTANCE_COUNT > 1");
 			m_uboStructLines.pushBackSprintf("%s _anki_uni_%s[_ANKI_INSTANCE_COUNT];", type, name);
 			m_uboStructLines.pushBack("#else");
@@ -381,23 +384,311 @@ Error ShaderProgramParser::parsePragmaInput(const StringAuto* begin, const Strin
 			m_uboStructLines.pushBack("#endif");
 			m_uboStructLines.pushBack("#endif");
 
-			m_globalsLines.pushBack("#ifdef _ANKI_VERTEX_SHADER");
+			m_globalsLines.pushBackSprintf("#if _ANKI_UNI_%s_ACTIVE", name);
+			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.pushBack("#else");
 			m_globalsLines.pushBackSprintf("%s %s = _anki_unis._anki_uni_%s;", type, name, name);
 			m_globalsLines.pushBack("#endif");
 			m_globalsLines.pushBack("#endif");
+			m_globalsLines.pushBack("#endif");
 		}
 		else
 		{
-			m_uboStructLines.pushBackSprintf("#if _ANKI_%s_ACTIVE", name);
+			m_uboStructLines.pushBackSprintf("#if _ANKI_UNI_%s_ACTIVE", name);
 			m_uboStructLines.pushBackSprintf("%s _anki_uni_%s;", type, name);
-			m_globalsLines.pushBack("#endif");
+			m_uboStructLines.pushBack("#endif");
 
+			m_globalsLines.pushBackSprintf("#if _ANKI_UNI_%s_ACTIVE", name);
 			m_globalsLines.pushBackSprintf("%s %s = _anki_unis_._anki_uni_%s;", type, name, name);
+			m_globalsLines.pushBackSprintf("#define %s_DEFINED 1", name);
+			m_globalsLines.pushBack("#endif");
+		}
+	}
+
+	return Error::NONE;
+}
+
+Error ShaderProgramParser::parsePragmaMutator(
+	const StringAuto* begin, const StringAuto* end, CString line, CString fname)
+{
+	ANKI_ASSERT(begin && end);
+
+	if(begin >= end)
+	{
+		ANKI_PP_ERROR_MALFORMED();
+	}
+
+	m_mutators.emplaceBack(m_alloc);
+	Mutator& mutator = m_mutators.getBack();
+
+	// Instanced
+	{
+		if(*begin == "instanced")
+		{
+			mutator.m_instanced = true;
+
+			// Check
+			if(m_instancedMutatorIdx != MAX_U32)
+			{
+				ANKI_PP_ERROR_MALFORMED_MSG("Can't have more than one instanced mutators");
+			}
+
+			m_instancedMutatorIdx = U32(m_mutators.getSize() - 1);
+			++begin;
+		}
+		else
+		{
+			mutator.m_instanced = false;
+		}
+	}
+
+	// Name
+	{
+		if(begin >= end)
+		{
+			// Need to have a name
+			ANKI_PP_ERROR_MALFORMED();
+		}
+
+		// Check for duplicate mutators
+		for(U i = 0; i < m_mutators.getSize() - 1; ++i)
+		{
+			if(m_mutators[i].m_name == *begin)
+			{
+				ANKI_PP_ERROR_MALFORMED_MSG("Duplicate mutator");
+			}
+		}
+
+		mutator.m_name.create(begin->toCString());
+		++begin;
+	}
+
+	// Values
+	{
+		// Gather them
+		for(; begin < end; ++begin)
+		{
+			Mutator::ValueType value = 0;
+
+			if(tokenIsComment(begin->toCString()))
+			{
+				break;
+			}
+
+			if(begin->toNumber(value))
+			{
+				ANKI_PP_ERROR_MALFORMED();
+			}
+
+			mutator.m_values.emplaceBack(value);
+		}
+
+		// Check for correct count
+		if(mutator.m_values.getSize() < 2)
+		{
+			ANKI_PP_ERROR_MALFORMED_MSG("Mutator with less that 2 values doesn't make sense");
+		}
+
+		std::sort(mutator.m_values.getBegin(), mutator.m_values.getEnd());
+
+		// Check for duplicates
+		for(U i = 1; i < mutator.m_values.getSize(); ++i)
+		{
+			if(mutator.m_values[i - 1] == mutator.m_values[i])
+			{
+				ANKI_PP_ERROR_MALFORMED_MSG("Same value appeared more than once");
+			}
+		}
+	}
+
+	// Update some source
+	if(mutator.m_instanced)
+	{
+		m_globalsLines.pushFrontSprintf("#define _ANKI_INSTANCE_COUNT %s", mutator.m_name.cstr());
+	}
+
+	return Error::NONE;
+}
+
+Error ShaderProgramParser::parseInclude(
+	const StringAuto* begin, const StringAuto* end, CString line, CString fname, U32 depth)
+{
+	// Gather the path
+	StringAuto path(m_alloc);
+	for(; begin < end; ++begin)
+	{
+		path.append(*begin);
+	}
+
+	if(path.isEmpty())
+	{
+		ANKI_PP_ERROR_MALFORMED();
+	}
+
+	// Check
+	const char firstChar = path[0];
+	const char lastChar = path[path.getLength() - 1];
+
+	if((firstChar == '\"' && lastChar == '\"') || (firstChar == '<' && lastChar == '>'))
+	{
+		StringAuto fname2(m_alloc);
+		fname2.create(path.begin() + 1, path.begin() + path.getLength() - 1);
+
+		if(parseFile(fname2, depth + 1))
+		{
+			ANKI_PP_ERROR_MALFORMED_MSG("Error parsing include. See previous errors");
 		}
 	}
+	else
+	{
+		ANKI_PP_ERROR_MALFORMED();
+	}
+
+	return Error::NONE;
+}
+
+Error ShaderProgramParser::parseLine(CString line, CString fname, Bool& foundPragmaOnce, U32 depth)
+{
+	// Tokenize
+	DynamicArrayAuto<StringAuto> tokens(m_alloc);
+	tokenizeLine(line, tokens);
+	ANKI_ASSERT(tokens.getSize() > 0);
+
+	const StringAuto* token = tokens.getBegin();
+	const StringAuto* end = tokens.getEnd();
+
+	// Skip the hash
+	Bool foundAloneHash = false;
+	if(*token == "#")
+	{
+		++token;
+		foundAloneHash = true;
+	}
+
+	if((token < end) && ((foundAloneHash && *token == "include") || *token == "#include"))
+	{
+		// We _must_ have an #include
+		ANKI_CHECK(parseInclude(token + 1, end, line, fname, depth));
+	}
+	else if((token < end) && ((foundAloneHash && *token == "pragma") || *token == "#pragma"))
+	{
+		// We may have a #pragma once or a #pragma anki or something else
+
+		++token;
+
+		if(*token == "once")
+		{
+			// Pragma once
+
+			if(foundPragmaOnce)
+			{
+				ANKI_PP_ERROR_MALFORMED_MSG("Can't have more than one #pragma once per file");
+			}
+
+			if(token + 1 != end)
+			{
+				ANKI_PP_ERROR_MALFORMED();
+			}
+
+			// Add the guard unique for this file
+			foundPragmaOnce = true;
+			const U64 hash = fname.computeHash();
+			m_lines.pushBackSprintf("#ifndef _ANKI_INCL_GUARD_%llu\n"
+									"#define _ANKI_INCL_GUARD_%llu",
+				hash,
+				hash);
+		}
+		else if(*token == "anki")
+		{
+			// Must be a #pragma anki
+
+			++token;
+
+			if(*token == "mutator")
+			{
+				ANKI_CHECK(parsePragmaMutator(token + 1, end, line, fname));
+			}
+			else if(*token == "input")
+			{
+				ANKI_CHECK(parsePragmaInput(token + 1, end, line, fname));
+			}
+			else if(*token == "start")
+			{
+				ANKI_CHECK(parsePragmaStart(token + 1, end, line, fname));
+			}
+			else if(*token == "end")
+			{
+				ANKI_CHECK(parsePragmaEnd(token + 1, end, line, fname));
+			}
+			else if(*token == "descriptor_set")
+			{
+				ANKI_CHECK(parsePragmaDescriptorSet(token + 1, end, line, fname));
+			}
+			else
+			{
+				ANKI_PP_ERROR_MALFORMED();
+			}
+		}
+		else
+		{
+			// Some other pragma
+			ANKI_SHADER_COMPILER_LOGW("Ignoring: %s", line.cstr());
+			m_lines.pushBack(line);
+		}
+	}
+	else
+	{
+		// Ignore
+		m_lines.pushBack(line);
+	}
+
+	return Error::NONE;
+}
+
+Error ShaderProgramParser::parseFile(CString fname, U32 depth)
+{
+	// First check the depth
+	if(depth > MAX_INCLUDE_DEPTH)
+	{
+		ANKI_SHADER_COMPILER_LOGE("The include depth is too high. Probably circular includance");
+	}
+
+	Bool foundPragmaOnce = false;
+
+	// Load file in lines
+	StringAuto txt(m_alloc);
+	ANKI_CHECK(m_fsystem->readAllText(fname, txt));
+
+	StringListAuto lines(m_alloc);
+	lines.splitString(txt.toCString(), '\n');
+	if(lines.getSize() < 1)
+	{
+		ANKI_SHADER_COMPILER_LOGE("Source is empty");
+	}
+
+	// Parse lines
+	for(const String& line : lines)
+	{
+		if(line.find("pragma") != CString::NPOS || line.find("include") != CString::NPOS)
+		{
+			// Possibly a preprocessor directive we care
+			ANKI_CHECK(parseLine(line.toCString(), fname, foundPragmaOnce, depth));
+		}
+		else
+		{
+			// Just append the line
+			m_lines.pushBack(line.toCString());
+		}
+	}
+
+	if(foundPragmaOnce)
+	{
+		// Append the guard
+		m_lines.pushBack("#endif // Include guard");
+	}
 
 	return Error::NONE;
 }

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

@@ -10,14 +10,14 @@
 #include <anki/util/WeakArray.h>
 #include <anki/util/DynamicArray.h>
 #include <anki/util/BitSet.h>
-#include <anki/gr/Common.h>
+#include <anki/gr/utils/Functions.h>
 
 namespace anki
 {
 
 // Forward
 class ShaderProgramParser;
-class ShaderProgramParserOutput;
+class ShaderProgramVariant;
 
 /// @addtogroup resource
 /// @{
@@ -61,7 +61,7 @@ private:
 class ShaderProgramParserInput
 {
 	friend ShaderProgramParser;
-	friend ShaderProgramParserOutput;
+	friend ShaderProgramVariant;
 
 public:
 	ShaderProgramParserInput(GenericMemoryPoolAllocator<U8> alloc)
@@ -103,27 +103,28 @@ private:
 };
 
 /// @memberof ShaderProgramParser
-class ShaderProgramParserOutput
+class ShaderProgramVariant
 {
 public:
-	ShaderProgramParserOutput(GenericMemoryPoolAllocator<U8> alloc)
-		: m_source(alloc)
+	CString getSource(ShaderType type) const
 	{
+		return m_sources[type];
 	}
 
-	CString getSource() const
+	Bool isInputActive(const ShaderProgramParserInput& in)
 	{
-		return m_source;
-	}
-
-	Bool inputIsActive(const ShaderProgramParserInput& in)
-	{
-		return m_activeInputMask.get(in.m_idx);
+		return m_activeInputVarsMask.get(in.m_idx);
 	}
 
 private:
-	StringAuto m_source;
-	BitSet<128> m_activeInputMask = {false};
+	GenericMemoryPoolAllocator<U8> m_alloc;
+	Array<String, U(ShaderType::COUNT)> m_sources;
+	DynamicArray<ShaderVariableBlockInfo> m_blockInfos;
+	DynamicArray<I16> m_bindings;
+	U32 m_uniBlockSize = 0;
+	U8 m_bindingCount = 0;
+	Bool m_usesPushConstants = false;
+	BitSet<128> m_activeInputVarsMask = {false};
 };
 
 /// @memberof ShaderProgramParser
@@ -180,8 +181,7 @@ public:
 	ANKI_USE_RESULT Error parse();
 
 	/// Get the source (and a few more things) given a list of mutators.
-	ShaderProgramParserOutput generateSource(
-		ConstWeakArray<ShaderProgramParserMutatorState> mutatorStates, ShaderType stage) const;
+	ShaderProgramVariant generateSource(ConstWeakArray<ShaderProgramParserMutatorState> mutatorStates) const;
 
 	ConstWeakArray<ShaderProgramParserMutator> getMutators() const
 	{