|
|
@@ -4,6 +4,7 @@
|
|
|
// http://www.anki3d.org/LICENSE
|
|
|
|
|
|
#include <anki/shader_compiler/ShaderProgramParser.h>
|
|
|
+#include <anki/shader_compiler/Glslang.h>
|
|
|
|
|
|
namespace anki
|
|
|
{
|
|
|
@@ -16,6 +17,9 @@ namespace anki
|
|
|
ANKI_SHADER_COMPILER_LOGE("%s: " msg_ ": %s", fname.cstr(), line.cstr()); \
|
|
|
return Error::USER_DATA
|
|
|
|
|
|
+static const Array<CString, U32(ShaderType::COUNT)> SHADER_STAGE_NAMES = {
|
|
|
+ {"VERTEX", "TESSELLATION_CONTROL", "TESSELLATION_EVALUATION", "GEOMETRY", "FRAGMENT", "COMPUTE"}};
|
|
|
+
|
|
|
static ANKI_USE_RESULT Error computeShaderVariableDataType(const CString& str, ShaderVariableDataType& out)
|
|
|
{
|
|
|
Error err = Error::NONE;
|
|
|
@@ -101,7 +105,27 @@ static ANKI_USE_RESULT Error computeShaderVariableDataType(const CString& str, S
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
-void ShaderProgramParser::tokenizeLine(CString line, DynamicArrayAuto<StringAuto>& tokens)
|
|
|
+static ANKI_USE_RESULT Error preprocessCommon(CString in, StringAuto& out)
|
|
|
+{
|
|
|
+ glslang::TShader shader(EShLangVertex);
|
|
|
+ Array<const char*, 1> csrc = {{&in[0]}};
|
|
|
+ shader.setStrings(&csrc[0], 1);
|
|
|
+
|
|
|
+ DirStackFileIncluder includer;
|
|
|
+ EShMessages messages = EShMsgDefault;
|
|
|
+ std::string glslangOut;
|
|
|
+ if(!shader.preprocess(&GLSLANG_LIMITS, 450, ENoProfile, false, false, messages, &glslangOut, includer))
|
|
|
+ {
|
|
|
+ ANKI_SHADER_COMPILER_LOGE("Preprocessing failed:\n%s", shader.getInfoLog());
|
|
|
+ return Error::USER_DATA;
|
|
|
+ }
|
|
|
+
|
|
|
+ out.append(glslangOut.c_str());
|
|
|
+
|
|
|
+ return Error::NONE;
|
|
|
+}
|
|
|
+
|
|
|
+void ShaderProgramParser::tokenizeLine(CString line, DynamicArrayAuto<StringAuto>& tokens) const
|
|
|
{
|
|
|
ANKI_ASSERT(line.getLength() > 0);
|
|
|
|
|
|
@@ -165,38 +189,33 @@ Error ShaderProgramParser::parsePragmaStart(const StringAuto* begin, const Strin
|
|
|
if(*begin == "vert")
|
|
|
{
|
|
|
shaderType = ShaderType::VERTEX;
|
|
|
- m_lines.pushBack("#ifdef ANKI_VERTEX_SHADER");
|
|
|
}
|
|
|
else if(*begin == "tessc")
|
|
|
{
|
|
|
shaderType = ShaderType::TESSELLATION_CONTROL;
|
|
|
- m_lines.pushBack("#ifdef ANKI_TESSELATION_CONTROL_SHADER");
|
|
|
}
|
|
|
else if(*begin == "tesse")
|
|
|
{
|
|
|
- shaderType = ShaderType::TESSELLATION_EVALUATION;
|
|
|
- m_lines.pushBack("#ifdef ANKI_TESSELLATION_EVALUATION_SHADER");
|
|
|
}
|
|
|
else if(*begin == "geom")
|
|
|
{
|
|
|
shaderType = ShaderType::GEOMETRY;
|
|
|
- m_lines.pushBack("#ifdef ANKI_GEOMETRY_SHADER");
|
|
|
}
|
|
|
else if(*begin == "frag")
|
|
|
{
|
|
|
shaderType = ShaderType::FRAGMENT;
|
|
|
- m_lines.pushBack("#ifdef ANKI_FRAGMENT_SHADER");
|
|
|
}
|
|
|
else if(*begin == "comp")
|
|
|
{
|
|
|
shaderType = ShaderType::COMPUTE;
|
|
|
- m_lines.pushBack("#ifdef ANKI_COMPUTE_SHADER");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
ANKI_PP_ERROR_MALFORMED();
|
|
|
}
|
|
|
|
|
|
+ m_codeLines.pushBackSprintf("#ifdef ANKI_%s", SHADER_STAGE_NAMES[shaderType].cstr());
|
|
|
+
|
|
|
++begin;
|
|
|
if(begin != end)
|
|
|
{
|
|
|
@@ -240,7 +259,7 @@ Error ShaderProgramParser::parsePragmaEnd(const StringAuto* begin, const StringA
|
|
|
m_insideShader = false;
|
|
|
|
|
|
// Write code
|
|
|
- m_lines.pushBack("#endif // Shader guard");
|
|
|
+ m_codeLines.pushBack("#endif // Shader guard");
|
|
|
|
|
|
return Error::NONE;
|
|
|
}
|
|
|
@@ -338,14 +357,24 @@ Error ShaderProgramParser::parsePragmaInput(const StringAuto* begin, const Strin
|
|
|
ANKI_PP_ERROR_MALFORMED();
|
|
|
}
|
|
|
|
|
|
+ // 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_globalsLines.pushBackSprintf("#if _ANKI_ACTIVATE_INPUT_%s", input.m_name.cstr());
|
|
|
m_globalsLines.pushBackSprintf("#define %s_DEFINED 1", input.m_name.cstr());
|
|
|
|
|
|
+ // TODO add vector support
|
|
|
+
|
|
|
m_globalsLines.pushBackSprintf("layout(constant_id = %u) const %s %s = %s(0);",
|
|
|
input.m_specConstId,
|
|
|
dataTypeStr.cstr(),
|
|
|
input.m_name.cstr(),
|
|
|
dataTypeStr.cstr(),
|
|
|
input.m_name.cstr());
|
|
|
+
|
|
|
+ m_globalsLines.pushBack("#else");
|
|
|
+ m_globalsLines.pushBackSprintf("#define %s_DEFINED 0", input.m_name.cstr());
|
|
|
+ m_globalsLines.pushBack("#endf");
|
|
|
}
|
|
|
else if(isSampler || isTexture)
|
|
|
{
|
|
|
@@ -357,12 +386,20 @@ Error ShaderProgramParser::parsePragmaInput(const StringAuto* begin, const Strin
|
|
|
ANKI_PP_ERROR_MALFORMED();
|
|
|
}
|
|
|
|
|
|
+ // 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_globalsLines.pushBackSprintf("#if _ANKI_ACTIVATE_INPUT_%s", input.m_name.cstr());
|
|
|
m_globalsLines.pushBackSprintf("#define %s_DEFINED 1", input.m_name.cstr());
|
|
|
|
|
|
m_globalsLines.pushBackSprintf("layout(set = _ANKI_DSET, binding = _ANKI_%s_BINDING) uniform %s %s;",
|
|
|
input.m_name.cstr(),
|
|
|
dataTypeStr.cstr(),
|
|
|
input.m_name.cstr());
|
|
|
+
|
|
|
+ m_globalsLines.pushBack("#else");
|
|
|
+ m_globalsLines.pushBackSprintf("#define %s_DEFINED 0", input.m_name.cstr());
|
|
|
+ m_globalsLines.pushBack("#endf");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
@@ -372,11 +409,11 @@ 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_lines.pushBackSprintf("//_anki_input_pesent %s", name);
|
|
|
+ m_codeLines.pushBackSprintf("//_anki_input_pesent %s", name);
|
|
|
|
|
|
if(input.m_instanced)
|
|
|
{
|
|
|
- m_uboStructLines.pushBackSprintf("#if _ANKI_UNI_%s_ACTIVE", name);
|
|
|
+ m_uboStructLines.pushBackSprintf("#if _ANKI_ACTIVATE_INPUT_%s", 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");
|
|
|
@@ -384,7 +421,7 @@ Error ShaderProgramParser::parsePragmaInput(const StringAuto* begin, const Strin
|
|
|
m_uboStructLines.pushBack("#endif");
|
|
|
m_uboStructLines.pushBack("#endif");
|
|
|
|
|
|
- m_globalsLines.pushBackSprintf("#if _ANKI_UNI_%s_ACTIVE", name);
|
|
|
+ m_globalsLines.pushBackSprintf("#if _ANKI_ACTIVATE_INPUT_%s", name);
|
|
|
m_globalsLines.pushBack("#ifdef ANKI_VERTEX_SHADER");
|
|
|
m_globalsLines.pushBackSprintf("#define %s_DEFINED 1", name);
|
|
|
m_globalsLines.pushBack("#if _ANKI_INSTANCE_COUNT > 1");
|
|
|
@@ -392,18 +429,22 @@ Error ShaderProgramParser::parsePragmaInput(const StringAuto* begin, const Strin
|
|
|
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 //ANKI_VERTEX_SHADER");
|
|
|
+ m_globalsLines.pushBack("#else");
|
|
|
+ m_globalsLines.pushBackSprintf("#define %s_DEFINED 0", name);
|
|
|
m_globalsLines.pushBack("#endif");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- m_uboStructLines.pushBackSprintf("#if _ANKI_UNI_%s_ACTIVE", name);
|
|
|
+ m_uboStructLines.pushBackSprintf("#if _ANKI_ACTIVATE_INPUT_%s", name);
|
|
|
m_uboStructLines.pushBackSprintf("%s _anki_uni_%s;", type, name);
|
|
|
m_uboStructLines.pushBack("#endif");
|
|
|
|
|
|
- m_globalsLines.pushBackSprintf("#if _ANKI_UNI_%s_ACTIVE", name);
|
|
|
+ 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("#define %s_DEFINED 1", name);
|
|
|
+ m_globalsLines.pushBack("#else");
|
|
|
+ m_globalsLines.pushBackSprintf("#define %s_DEFINED 0", name);
|
|
|
m_globalsLines.pushBack("#endif");
|
|
|
}
|
|
|
}
|
|
|
@@ -596,8 +637,8 @@ Error ShaderProgramParser::parseLine(CString line, CString fname, Bool& foundPra
|
|
|
// 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",
|
|
|
+ m_codeLines.pushBackSprintf("#ifndef _ANKI_INCL_GUARD_%llu\n"
|
|
|
+ "#define _ANKI_INCL_GUARD_%llu",
|
|
|
hash,
|
|
|
hash);
|
|
|
}
|
|
|
@@ -636,13 +677,13 @@ Error ShaderProgramParser::parseLine(CString line, CString fname, Bool& foundPra
|
|
|
{
|
|
|
// Some other pragma
|
|
|
ANKI_SHADER_COMPILER_LOGW("Ignoring: %s", line.cstr());
|
|
|
- m_lines.pushBack(line);
|
|
|
+ m_codeLines.pushBack(line);
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
// Ignore
|
|
|
- m_lines.pushBack(line);
|
|
|
+ m_codeLines.pushBack(line);
|
|
|
}
|
|
|
|
|
|
return Error::NONE;
|
|
|
@@ -680,14 +721,366 @@ Error ShaderProgramParser::parseFile(CString fname, U32 depth)
|
|
|
else
|
|
|
{
|
|
|
// Just append the line
|
|
|
- m_lines.pushBack(line.toCString());
|
|
|
+ m_codeLines.pushBack(line.toCString());
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if(foundPragmaOnce)
|
|
|
{
|
|
|
// Append the guard
|
|
|
- m_lines.pushBack("#endif // Include guard");
|
|
|
+ m_codeLines.pushBack("#endif // Include guard");
|
|
|
+ }
|
|
|
+
|
|
|
+ if(m_insideShader)
|
|
|
+ {
|
|
|
+ ANKI_SHADER_COMPILER_LOGE("Forgot a \"pragma anki end\"");
|
|
|
+ return Error::USER_DATA;
|
|
|
+ }
|
|
|
+
|
|
|
+ return Error::NONE;
|
|
|
+}
|
|
|
+
|
|
|
+Error ShaderProgramParser::parse()
|
|
|
+{
|
|
|
+ ANKI_ASSERT(!m_fname.isEmpty());
|
|
|
+ ANKI_ASSERT(m_codeLines.isEmpty());
|
|
|
+
|
|
|
+ const CString fname = m_fname;
|
|
|
+
|
|
|
+ // Parse recursively
|
|
|
+ ANKI_CHECK(parseFile(fname, 0));
|
|
|
+
|
|
|
+ // Checks
|
|
|
+ {
|
|
|
+ if(m_foundAtLeastOneInstancedInput != (m_instancedMutatorIdx != MAX_U32))
|
|
|
+ {
|
|
|
+ ANKI_SHADER_COMPILER_LOGE("If there is an instanced mutator there should be at least one instanced input");
|
|
|
+ return Error::USER_DATA;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(!!(m_shaderTypes & ShaderTypeBit::COMPUTE))
|
|
|
+ {
|
|
|
+ if(m_shaderTypes != ShaderTypeBit::COMPUTE)
|
|
|
+ {
|
|
|
+ ANKI_SHADER_COMPILER_LOGE("Can't combine compute shader with other types of shaders");
|
|
|
+ return Error::USER_DATA;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(m_instancedMutatorIdx != MAX_U32)
|
|
|
+ {
|
|
|
+ ANKI_SHADER_COMPILER_LOGE("Can't have instanced mutators in compute programs");
|
|
|
+ return Error::USER_DATA;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if(!(m_shaderTypes & ShaderTypeBit::VERTEX))
|
|
|
+ {
|
|
|
+ ANKI_SHADER_COMPILER_LOGE("Missing vertex shader");
|
|
|
+ return Error::USER_DATA;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(!(m_shaderTypes & ShaderTypeBit::FRAGMENT))
|
|
|
+ {
|
|
|
+ ANKI_SHADER_COMPILER_LOGE("Missing fragment shader");
|
|
|
+ return Error::USER_DATA;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Create the UBO source code
|
|
|
+ if(m_uboStructLines.getSize() > 0)
|
|
|
+ {
|
|
|
+ m_uboStructLines.pushFront("struct _AnkiUniforms {");
|
|
|
+ m_uboStructLines.pushBack("};");
|
|
|
+
|
|
|
+ m_uboStructLines.pushBack("#if _ANKI_USE_PUSH_CONSTANTS == 1");
|
|
|
+ m_uboStructLines.pushBackSprintf(
|
|
|
+ "layout(push_constant, std140, row_major) uniform _anki_pc {_AnkiUniforms _anki_unis;};");
|
|
|
+ m_uboStructLines.pushBack("#else");
|
|
|
+ m_uboStructLines.pushBack(
|
|
|
+ "layout(set = _ANKI_DSET, binding = 0, row_major) uniform _anki_ubo {_AnkiUniforms _anki_unis;};");
|
|
|
+ m_uboStructLines.pushBack("#endif\n");
|
|
|
+
|
|
|
+ m_uboStructLines.join("\n", m_uboSource);
|
|
|
+ m_uboStructLines.destroy();
|
|
|
+ }
|
|
|
+
|
|
|
+ // Create the globals source code
|
|
|
+ if(m_globalsLines.getSize() > 0)
|
|
|
+ {
|
|
|
+ m_globalsLines.join("\n", m_globalsSource);
|
|
|
+ m_globalsLines.destroy();
|
|
|
+ }
|
|
|
+
|
|
|
+ // Create the code lines
|
|
|
+ if(m_codeLines.getSize())
|
|
|
+ {
|
|
|
+ m_codeLines.join("\n", m_codeSource);
|
|
|
+ m_codeLines.destroy();
|
|
|
+ }
|
|
|
+
|
|
|
+ return Error::NONE;
|
|
|
+}
|
|
|
+
|
|
|
+Error ShaderProgramParser::findActiveInputVars(CString source, BitSet<MAX_SHADER_PROGRAM_INPUT_VARIABLES>& active) const
|
|
|
+{
|
|
|
+ StringAuto preprocessedSrc(m_alloc);
|
|
|
+ ANKI_CHECK(preprocessCommon(source, preprocessedSrc));
|
|
|
+
|
|
|
+ StringListAuto lines(m_alloc);
|
|
|
+ lines.splitString(preprocessedSrc, '\n');
|
|
|
+
|
|
|
+ for(const String& line : lines)
|
|
|
+ {
|
|
|
+ if(line.find("//_anki_input_pesent") == String::NPOS)
|
|
|
+ {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ DynamicArrayAuto<StringAuto> tokens(m_alloc);
|
|
|
+ tokenizeLine(line, tokens);
|
|
|
+ ANKI_ASSERT(tokens.getSize() == 2);
|
|
|
+
|
|
|
+ // Find the input var
|
|
|
+ Bool found = false;
|
|
|
+ for(const Input& in : m_inputs)
|
|
|
+ {
|
|
|
+ if(in.m_name == tokens[1])
|
|
|
+ {
|
|
|
+ active.set(in.m_idx);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ (void)found;
|
|
|
+ ANKI_ASSERT(found);
|
|
|
+ }
|
|
|
+
|
|
|
+ return Error::NONE;
|
|
|
+}
|
|
|
+
|
|
|
+Error ShaderProgramParser::generateSource(
|
|
|
+ ConstWeakArray<ShaderProgramParserMutatorState> mutatorStates, ShaderProgramVariant& variant) const
|
|
|
+{
|
|
|
+ // Sanity checks
|
|
|
+ ANKI_ASSERT(m_codeSource.getLength() > 0);
|
|
|
+ ANKI_ASSERT(mutatorStates.getSize() == m_mutators.getSize());
|
|
|
+ BitSet<128> mutatorPresent = {false};
|
|
|
+ for(const ShaderProgramParserMutatorState& state : mutatorStates)
|
|
|
+ {
|
|
|
+ ANKI_ASSERT(state.m_mutator >= &m_mutators[0] && state.m_mutator <= &m_mutators[m_mutators.getSize() - 1]);
|
|
|
+ const U idx = state.m_mutator - &m_mutators[0];
|
|
|
+ ANKI_ASSERT(!mutatorPresent.get(idx) && "Appeared 2 times");
|
|
|
+ mutatorPresent.set(idx);
|
|
|
+
|
|
|
+ Bool found = false;
|
|
|
+ for(Mutator::ValueType val : state.m_mutator->m_values)
|
|
|
+ {
|
|
|
+ if(val == state.m_value)
|
|
|
+ {
|
|
|
+ found = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ANKI_ASSERT(found && "Value not found");
|
|
|
+ }
|
|
|
+
|
|
|
+ // Init variant
|
|
|
+ variant.m_alloc = m_alloc;
|
|
|
+ variant.m_bindings.create(m_alloc, m_inputs.getSize(), -1);
|
|
|
+ variant.m_blockInfos.create(m_alloc, m_inputs.getSize());
|
|
|
+
|
|
|
+ // Get instance count, one mutation has it
|
|
|
+ U32 instanceCount = 1;
|
|
|
+ if(m_instancedMutatorIdx != MAX_U32)
|
|
|
+ {
|
|
|
+ for(const ShaderProgramParserMutatorState& state : mutatorStates)
|
|
|
+ {
|
|
|
+ const U32 idx = U32(state.m_mutator - &m_mutators[0]);
|
|
|
+
|
|
|
+ if(idx == m_instancedMutatorIdx)
|
|
|
+ {
|
|
|
+ ANKI_ASSERT(state.m_value > 0);
|
|
|
+ instanceCount = state.m_value;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Create the mutator defines
|
|
|
+ StringAuto mutatorDefines(m_alloc);
|
|
|
+ for(const ShaderProgramParserMutatorState& state : mutatorStates)
|
|
|
+ {
|
|
|
+ mutatorDefines.append(
|
|
|
+ StringAuto(m_alloc).sprintf("#define %s %d\n", state.m_mutator->m_name.cstr(), state.m_value));
|
|
|
+ }
|
|
|
+
|
|
|
+ // Find active vars by running the preprocessor
|
|
|
+ StringAuto activeInputs(m_alloc);
|
|
|
+ if(m_inputs.getSize() > 0)
|
|
|
+ {
|
|
|
+ StringAuto src(m_alloc);
|
|
|
+ src.append(mutatorDefines);
|
|
|
+ src.append(m_globalsSource);
|
|
|
+ ANKI_CHECK(findActiveInputVars(src, variant.m_activeInputVarsMask));
|
|
|
+
|
|
|
+ StringListAuto lines(m_alloc);
|
|
|
+ for(const Input& in : m_inputs)
|
|
|
+ {
|
|
|
+ const Bool active = variant.m_activeInputVarsMask.get(in.m_idx);
|
|
|
+ lines.pushBackSprintf("#define _ANKI_ACTIVATE_INPUT_%s %u", in.m_name.cstr(), active);
|
|
|
+ }
|
|
|
+
|
|
|
+ lines.join("\n", activeInputs);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Initialize the active vars that are inside a UBO
|
|
|
+ for(const Input& in : m_inputs)
|
|
|
+ {
|
|
|
+ if(!variant.m_activeInputVarsMask.get(in.m_idx))
|
|
|
+ {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(!in.inUbo())
|
|
|
+ {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ ShaderVariableBlockInfo& blockInfo = variant.m_blockInfos[in.m_idx];
|
|
|
+
|
|
|
+ // std140 rules
|
|
|
+ blockInfo.m_offset = I16(variant.m_uniBlockSize);
|
|
|
+ blockInfo.m_arraySize = (in.m_instanced) ? I16(instanceCount) : 1;
|
|
|
+
|
|
|
+ if(in.m_dataType == ShaderVariableDataType::FLOAT || in.m_dataType == ShaderVariableDataType::INT
|
|
|
+ || in.m_dataType == ShaderVariableDataType::UINT)
|
|
|
+ {
|
|
|
+ blockInfo.m_arrayStride = sizeof(Vec4);
|
|
|
+
|
|
|
+ if(blockInfo.m_arraySize == 1)
|
|
|
+ {
|
|
|
+ // No need to align the in.m_offset
|
|
|
+ variant.m_uniBlockSize += sizeof(F32);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ alignRoundUp(sizeof(Vec4), blockInfo.m_offset);
|
|
|
+ variant.m_uniBlockSize += sizeof(Vec4) * blockInfo.m_arraySize;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if(in.m_dataType == ShaderVariableDataType::VEC2 || in.m_dataType == ShaderVariableDataType::IVEC2
|
|
|
+ || in.m_dataType == ShaderVariableDataType::UVEC2)
|
|
|
+ {
|
|
|
+ blockInfo.m_arrayStride = sizeof(Vec4);
|
|
|
+
|
|
|
+ if(blockInfo.m_arraySize == 1)
|
|
|
+ {
|
|
|
+ alignRoundUp(sizeof(Vec2), blockInfo.m_offset);
|
|
|
+ variant.m_uniBlockSize = blockInfo.m_offset + sizeof(Vec2);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ alignRoundUp(sizeof(Vec4), blockInfo.m_offset);
|
|
|
+ variant.m_uniBlockSize = blockInfo.m_offset + sizeof(Vec4) * blockInfo.m_arraySize;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if(in.m_dataType == ShaderVariableDataType::VEC3 || in.m_dataType == ShaderVariableDataType::IVEC3
|
|
|
+ || in.m_dataType == ShaderVariableDataType::UVEC3)
|
|
|
+ {
|
|
|
+ alignRoundUp(sizeof(Vec4), blockInfo.m_offset);
|
|
|
+ blockInfo.m_arrayStride = sizeof(Vec4);
|
|
|
+
|
|
|
+ if(blockInfo.m_arraySize == 1)
|
|
|
+ {
|
|
|
+ variant.m_uniBlockSize = blockInfo.m_offset + sizeof(Vec3);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ variant.m_uniBlockSize = blockInfo.m_offset + sizeof(Vec4) * blockInfo.m_arraySize;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if(in.m_dataType == ShaderVariableDataType::VEC4 || in.m_dataType == ShaderVariableDataType::IVEC4
|
|
|
+ || in.m_dataType == ShaderVariableDataType::UVEC4)
|
|
|
+ {
|
|
|
+ blockInfo.m_arrayStride = sizeof(Vec4);
|
|
|
+ alignRoundUp(sizeof(Vec4), blockInfo.m_offset);
|
|
|
+ variant.m_uniBlockSize = blockInfo.m_offset + sizeof(Vec4) * blockInfo.m_arraySize;
|
|
|
+ }
|
|
|
+ else if(in.m_dataType == ShaderVariableDataType::MAT3)
|
|
|
+ {
|
|
|
+ alignRoundUp(sizeof(Vec4), blockInfo.m_offset);
|
|
|
+ blockInfo.m_arrayStride = sizeof(Vec4) * 3;
|
|
|
+ variant.m_uniBlockSize = blockInfo.m_offset + sizeof(Vec4) * 3 * blockInfo.m_arraySize;
|
|
|
+ blockInfo.m_matrixStride = sizeof(Vec4);
|
|
|
+ }
|
|
|
+ else if(in.m_dataType == ShaderVariableDataType::MAT4)
|
|
|
+ {
|
|
|
+ alignRoundUp(sizeof(Vec4), blockInfo.m_offset);
|
|
|
+ blockInfo.m_arrayStride = sizeof(Mat4);
|
|
|
+ variant.m_uniBlockSize = blockInfo.m_offset + sizeof(Mat4) * blockInfo.m_arraySize;
|
|
|
+ blockInfo.m_matrixStride = sizeof(Vec4);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ ANKI_ASSERT(0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Find if it's using push constants
|
|
|
+ StringAuto pushConstantDefineSrc(m_alloc);
|
|
|
+ {
|
|
|
+ variant.m_usesPushConstants = variant.m_uniBlockSize <= m_pushConstSize;
|
|
|
+ pushConstantDefineSrc.sprintf("#define _ANKI_USE_PUSH_CONSTANTS %u\n", variant.m_usesPushConstants);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Handle the bindings for the textures and samplers
|
|
|
+ StringAuto bindingDefines(m_alloc);
|
|
|
+ {
|
|
|
+ StringListAuto defines(m_alloc);
|
|
|
+ U32 texOrSamplerBinding = variant.m_usesPushConstants ? 0 : 1;
|
|
|
+ for(const Input& in : m_inputs)
|
|
|
+ {
|
|
|
+ if(!variant.m_activeInputVarsMask.get(in.m_idx))
|
|
|
+ {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(!in.isSampler() && !in.isTexture())
|
|
|
+ {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ defines.pushBackSprintf("#define _ANKI_%s_BINDING %u", in.m_name.cstr(), texOrSamplerBinding);
|
|
|
+ variant.m_bindings[in.m_idx] = I16(texOrSamplerBinding++);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(!defines.isEmpty())
|
|
|
+ {
|
|
|
+ defines.join("\n", bindingDefines);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Generate souce per stage
|
|
|
+ for(ShaderType shaderType = ShaderType::FIRST; shaderType < ShaderType::COUNT; ++shaderType)
|
|
|
+ {
|
|
|
+ if(!((1u << ShaderTypeBit(shaderType)) & m_shaderTypes))
|
|
|
+ {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Create the final source without the bindings
|
|
|
+ StringAuto finalSource(m_alloc);
|
|
|
+ finalSource.append(mutatorDefines);
|
|
|
+ finalSource.append(StringAuto(m_alloc).sprintf("#define ANKI_%s 1\n", SHADER_STAGE_NAMES[shaderType].cstr()));
|
|
|
+ finalSource.append(activeInputs);
|
|
|
+ finalSource.append(pushConstantDefineSrc);
|
|
|
+ finalSource.append(m_uboSource);
|
|
|
+ finalSource.append(m_globalsSource);
|
|
|
+ finalSource.append(m_codeSource);
|
|
|
+
|
|
|
+ // Move the source
|
|
|
+ variant.m_sources[shaderType] = std::move(finalSource);
|
|
|
}
|
|
|
|
|
|
return Error::NONE;
|