| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851 |
- // Copyright (C) 2009-2022, Panagiotis Christopoulos Charitos and contributors.
- // All rights reserved.
- // Code licensed under the BSD License.
- // http://www.anki3d.org/LICENSE
- #include <AnKi/Resource/MaterialResource.h>
- #include <AnKi/Resource/ResourceManager.h>
- #include <AnKi/Resource/ImageResource.h>
- #include <AnKi/Util/Xml.h>
- namespace anki {
- static const Array<CString, U32(BuiltinMutatorId::COUNT)> BUILTIN_MUTATOR_NAMES = {
- {"NONE", "ANKI_TECHNIQUE", "ANKI_LOD", "ANKI_BONES", "ANKI_VELOCITY"}};
- static const Array<CString, U(RenderingTechnique::COUNT)> TECHNIQUE_NAMES = {
- {"GBuffer", "GBufferEarlyZ", "Shadow", "Forward", "RtShadow"}};
- // This is some trickery to select calling between XmlElement::getAttributeNumber and XmlElement::getAttributeNumbers
- namespace {
- template<typename T>
- class IsShaderVarDataTypeAnArray
- {
- public:
- static constexpr Bool VALUE = false;
- };
- #define ANKI_SVDT_MACRO(capital, type, baseType, rowCount, columnCount, isIntagralType) \
- template<> \
- class IsShaderVarDataTypeAnArray<type> \
- { \
- public: \
- static constexpr Bool VALUE = rowCount * columnCount > 1; \
- };
- #include <AnKi/Gr/ShaderVariableDataType.defs.h>
- #undef ANKI_SVDT_MACRO
- template<typename T, Bool isArray = IsShaderVarDataTypeAnArray<T>::VALUE>
- class GetAttribute
- {
- public:
- Error operator()(const XmlElement& el, T& out)
- {
- return el.getAttributeNumbers("value", out);
- }
- };
- template<typename T>
- class GetAttribute<T, false>
- {
- public:
- Error operator()(const XmlElement& el, T& out)
- {
- return el.getAttributeNumber("value", out);
- }
- };
- } // namespace
- MaterialVariable::MaterialVariable()
- {
- m_Mat4 = Mat4::getZero();
- }
- MaterialVariable::~MaterialVariable()
- {
- }
- class MaterialResource::Program
- {
- public:
- ShaderProgramResourcePtr m_prog;
- mutable Array4d<MaterialVariant, U(RenderingTechnique::COUNT), MAX_LOD_COUNT, 2, 2> m_variantMatrix;
- mutable RWMutex m_variantMatrixMtx;
- DynamicArray<PartialMutation> m_partialMutation; ///< Only with the non-builtins.
- U32 m_presentBuildinMutators = 0;
- U32 m_localUniformsStructIdx = 0; ///< Struct index in the program binary.
- U8 m_lodCount = 1;
- Program() = default;
- Program(const Program&) = delete; // Non-copyable
- Program(Program&& b)
- {
- *this = std::move(b);
- }
- Program& operator=(const Program& b) = delete; // Non-copyable
- Program& operator=(Program&& b)
- {
- m_prog = std::move(b.m_prog);
- for(RenderingTechnique t : EnumIterable<RenderingTechnique>())
- {
- for(U32 l = 0; l < MAX_LOD_COUNT; ++l)
- {
- for(U32 skin = 0; skin < 2; ++skin)
- {
- for(U32 vel = 0; vel < 2; ++vel)
- {
- m_variantMatrix[t][skin][skin][vel] = std::move(b.m_variantMatrix[t][skin][skin][vel]);
- }
- }
- }
- }
- m_partialMutation = std::move(b.m_partialMutation);
- m_presentBuildinMutators = b.m_presentBuildinMutators;
- m_localUniformsStructIdx = b.m_localUniformsStructIdx;
- m_lodCount = b.m_lodCount;
- return *this;
- }
- };
- MaterialResource::MaterialResource(ResourceManager* manager)
- : ResourceObject(manager)
- {
- memset(m_techniqueToProgram.getBegin(), 0xFF, m_techniqueToProgram.getSizeInBytes());
- }
- MaterialResource::~MaterialResource()
- {
- for(Program& p : m_programs)
- {
- p.m_partialMutation.destroy(getAllocator());
- }
- m_textures.destroy(getAllocator());
- for(MaterialVariable& var : m_vars)
- {
- var.m_name.destroy(getAllocator());
- }
- m_vars.destroy(getAllocator());
- m_programs.destroy(getAllocator());
- getAllocator().deallocate(m_prefilledLocalUniforms, 0);
- }
- const MaterialVariable* MaterialResource::tryFindVariableInternal(CString name) const
- {
- for(const MaterialVariable& v : m_vars)
- {
- if(v.m_name == name)
- {
- return &v;
- }
- }
- return nullptr;
- }
- Error MaterialResource::load(const ResourceFilename& filename, Bool async)
- {
- XmlDocument doc;
- XmlElement el;
- ANKI_CHECK(openFileParseXml(filename, doc));
- // <material>
- XmlElement rootEl;
- ANKI_CHECK(doc.getChildElement("material", rootEl));
- // <shaderPrograms>
- XmlElement shaderProgramsEl;
- ANKI_CHECK(rootEl.getChildElement("shaderPrograms", shaderProgramsEl));
- XmlElement shaderProgramEl;
- ANKI_CHECK(shaderProgramsEl.getChildElement("shaderProgram", shaderProgramEl));
- do
- {
- ANKI_CHECK(parseShaderProgram(shaderProgramEl, async));
- ANKI_CHECK(shaderProgramEl.getNextSiblingElement("shaderProgram", shaderProgramEl));
- } while(shaderProgramEl);
- ANKI_ASSERT(!!m_techniquesMask);
- // <inputs>
- BitSet<128> varsSet(false);
- ANKI_CHECK(rootEl.getChildElementOptional("inputs", el));
- if(el)
- {
- XmlElement inputEl;
- ANKI_CHECK(el.getChildElement("input", inputEl));
- do
- {
- ANKI_CHECK(parseInput(inputEl, async, varsSet));
- ANKI_CHECK(inputEl.getNextSiblingElement("input", inputEl));
- } while(inputEl);
- }
- if(varsSet.getEnabledBitCount() != m_vars.getSize())
- {
- ANKI_RESOURCE_LOGE("Forgot to set a default value in %u input variables",
- U32(m_vars.getSize() - varsSet.getEnabledBitCount()));
- return Error::USER_DATA;
- }
- prefillLocalUniforms();
- return Error::NONE;
- }
- Error MaterialResource::parseShaderProgram(XmlElement shaderProgramEl, Bool async)
- {
- // name
- CString shaderName;
- ANKI_CHECK(shaderProgramEl.getAttributeText("name", shaderName));
- if(!getManager().getGrManager().getDeviceCapabilities().m_rayTracingEnabled && shaderName.find("Rt") == 0)
- {
- // Skip RT programs when RT is disabled
- return Error::NONE;
- }
- StringAuto fname(getTempAllocator());
- fname.sprintf("ShaderBinaries/%s.ankiprogbin", shaderName.cstr());
- Program& prog = *m_programs.emplaceBack(getAllocator());
- ANKI_CHECK(getManager().loadResource(fname, prog.m_prog, async));
- // <mutation>
- XmlElement mutatorsEl;
- ANKI_CHECK(shaderProgramEl.getChildElementOptional("mutation", mutatorsEl));
- if(mutatorsEl)
- {
- ANKI_CHECK(parseMutators(mutatorsEl, prog));
- }
- // And find the builtin mutators
- ANKI_CHECK(findBuiltinMutators(prog));
- // Create the vars
- ANKI_CHECK(createVars(prog));
- return Error::NONE;
- }
- Error MaterialResource::createVars(Program& prog)
- {
- const ShaderProgramBinary& binary = prog.m_prog->getBinary();
- // Find struct
- const ShaderProgramBinaryStruct* localUniformsStruct = nullptr;
- for(const ShaderProgramBinaryStruct& strct : binary.m_structs)
- {
- if(CString(strct.m_name.getBegin()) == "AnKiLocalUniforms")
- {
- localUniformsStruct = &strct;
- break;
- }
- ++prog.m_localUniformsStructIdx;
- }
- if(localUniformsStruct == nullptr)
- {
- prog.m_localUniformsStructIdx = MAX_U32;
- }
- // Iterate all members of the local uniforms struct to add its members
- U32 offsetof = 0;
- for(U32 i = 0; localUniformsStruct && i < localUniformsStruct->m_members.getSize(); ++i)
- {
- const ShaderProgramBinaryStructMember& member = localUniformsStruct->m_members[i];
- const CString memberName = member.m_name.getBegin();
- // Check if it needs to be added
- Bool addIt = false;
- if(member.m_dependentMutator == MAX_U32)
- {
- addIt = true;
- }
- else
- {
- Bool found = false;
- for(const PartialMutation& m : prog.m_partialMutation)
- {
- if(m.m_mutator->m_name == binary.m_mutators[member.m_dependentMutator].m_name.getBegin())
- {
- if(m.m_value == member.m_dependentMutatorValue)
- {
- addIt = true;
- }
- found = true;
- break;
- }
- }
- if(!found)
- {
- ANKI_RESOURCE_LOGE("Incorrect combination of member variable %s and dependent mutator %s",
- memberName.cstr(), binary.m_mutators[member.m_dependentMutator].m_name.getBegin());
- return Error::USER_DATA;
- }
- }
- if(addIt)
- {
- MaterialVariable* var = tryFindVariable(memberName);
- if(var)
- {
- if(var->m_dataType != member.m_type || var->m_offsetInLocalUniforms != offsetof)
- {
- ANKI_RESOURCE_LOGE("Member variable doesn't match between techniques: %s", memberName.cstr());
- return Error::USER_DATA;
- }
- }
- else
- {
- // Check that there are no other vars that overlap with the current var. This could happen if
- // different programs have different signature for AnKiLocalUniforms
- for(const MaterialVariable& otherVar : m_vars)
- {
- if(!otherVar.isUniform())
- {
- continue;
- }
- const U32 aVarOffset = otherVar.m_offsetInLocalUniforms;
- const U32 aVarEnd = aVarOffset + getShaderVariableDataTypeInfo(otherVar.m_dataType).m_size;
- const U32 bVarOffset = offsetof;
- const U32 bVarEnd = bVarOffset + getShaderVariableDataTypeInfo(member.m_type).m_size;
- if((aVarOffset <= bVarOffset && aVarEnd > bVarOffset)
- || (bVarOffset <= aVarOffset && bVarEnd > aVarOffset))
- {
- ANKI_RESOURCE_LOGE("Member %s in AnKiLocalUniforms overlaps with %s. Check your shaders",
- memberName.cstr(), otherVar.m_name.cstr());
- return Error::USER_DATA;
- }
- }
- // All good, add it
- var = m_vars.emplaceBack(getAllocator());
- var->m_name.create(getAllocator(), memberName);
- var->m_offsetInLocalUniforms = offsetof;
- var->m_dataType = member.m_type;
- offsetof += getShaderVariableDataTypeInfo(member.m_type).m_size;
- }
- }
- }
- m_localUniformsSize = max(offsetof, m_localUniformsSize);
- // Iterate all variants of builtin mutators to gather the opaques
- ShaderProgramResourceVariantInitInfo initInfo(prog.m_prog);
- for(const PartialMutation& m : prog.m_partialMutation)
- {
- initInfo.addMutation(m.m_mutator->m_name, m.m_value);
- }
- Array<const ShaderProgramResourceMutator*, U(BuiltinMutatorId::COUNT)> mutatorPtrs = {};
- for(BuiltinMutatorId id : EnumIterable<BuiltinMutatorId>())
- {
- mutatorPtrs[id] = prog.m_prog->tryFindMutator(BUILTIN_MUTATOR_NAMES[id]);
- }
- #define ANKI_LOOP(builtIn) \
- for(U32 i = 0; \
- i \
- < ((mutatorPtrs[BuiltinMutatorId::builtIn]) ? mutatorPtrs[BuiltinMutatorId::builtIn]->m_values.getSize() : 1); \
- ++i) \
- { \
- if(mutatorPtrs[BuiltinMutatorId::builtIn]) \
- { \
- initInfo.addMutation(mutatorPtrs[BuiltinMutatorId::builtIn]->m_name, \
- mutatorPtrs[BuiltinMutatorId::builtIn]->m_values[i]); \
- }
- #define ANKI_LOOP_END() }
- ANKI_LOOP(TECHNIQUE)
- ANKI_LOOP(LOD)
- ANKI_LOOP(BONES)
- ANKI_LOOP(VELOCITY)
- {
- const ShaderProgramResourceVariant* variant;
- prog.m_prog->getOrCreateVariant(initInfo, variant);
- // Add opaque vars
- for(const ShaderProgramBinaryOpaqueInstance& instance : variant->getBinaryVariant().m_opaques)
- {
- const ShaderProgramBinaryOpaque& opaque = binary.m_opaques[instance.m_index];
- if(opaque.m_type == ShaderVariableDataType::SAMPLER)
- {
- continue;
- }
- const CString opaqueName = opaque.m_name.getBegin();
- MaterialVariable* var = tryFindVariable(opaqueName);
- if(var)
- {
- if(var->m_dataType != opaque.m_type || var->m_opaqueBinding != opaque.m_binding)
- {
- ANKI_RESOURCE_LOGE("Opaque variable doesn't match between techniques: %s", opaqueName.cstr());
- return Error::USER_DATA;
- }
- }
- else
- {
- // Check that there are no other opaque with the same binding
- for(const MaterialVariable& otherVar : m_vars)
- {
- if(!otherVar.isBoundableTexture())
- {
- continue;
- }
- if(otherVar.m_opaqueBinding == opaque.m_binding)
- {
- ANKI_RESOURCE_LOGE("Opaque variable %s has the same binding as %s. Check your shaders",
- otherVar.m_name.cstr(), opaqueName.cstr());
- return Error::USER_DATA;
- }
- }
- // All good, add it
- var = m_vars.emplaceBack(getAllocator());
- var->m_name.create(getAllocator(), opaqueName);
- var->m_opaqueBinding = opaque.m_binding;
- var->m_dataType = opaque.m_type;
- }
- }
- }
- ANKI_LOOP_END()
- ANKI_LOOP_END()
- ANKI_LOOP_END()
- ANKI_LOOP_END()
- #undef ANKI_LOOP
- #undef ANKI_LOOP_END
- return Error::NONE;
- }
- Error MaterialResource::parseMutators(XmlElement mutatorsEl, Program& prog)
- {
- XmlElement mutatorEl;
- ANKI_CHECK(mutatorsEl.getChildElement("mutator", mutatorEl));
- U32 mutatorCount = 0;
- ANKI_CHECK(mutatorEl.getSiblingElementsCount(mutatorCount));
- ++mutatorCount;
- ANKI_ASSERT(mutatorCount > 0);
- prog.m_partialMutation.create(getAllocator(), mutatorCount);
- mutatorCount = 0;
- do
- {
- PartialMutation& pmutation = prog.m_partialMutation[mutatorCount];
- // name
- CString mutatorName;
- ANKI_CHECK(mutatorEl.getAttributeText("name", mutatorName));
- if(mutatorName.isEmpty())
- {
- ANKI_RESOURCE_LOGE("Mutator name is empty");
- return Error::USER_DATA;
- }
- for(BuiltinMutatorId id : EnumIterable<BuiltinMutatorId>())
- {
- if(id == BuiltinMutatorId::NONE)
- {
- continue;
- }
- if(mutatorName == BUILTIN_MUTATOR_NAMES[id])
- {
- ANKI_RESOURCE_LOGE("Materials shouldn't list builtin mutators: %s", mutatorName.cstr());
- return Error::USER_DATA;
- }
- }
- if(mutatorName.find("ANKI_") == 0)
- {
- ANKI_RESOURCE_LOGE("Mutators can't start with ANKI_: %s", mutatorName.cstr());
- return Error::USER_DATA;
- }
- // value
- ANKI_CHECK(mutatorEl.getAttributeNumber("value", pmutation.m_value));
- // Find mutator
- pmutation.m_mutator = prog.m_prog->tryFindMutator(mutatorName);
- if(!pmutation.m_mutator)
- {
- ANKI_RESOURCE_LOGE("Mutator not found in program %s", &mutatorName[0]);
- return Error::USER_DATA;
- }
- if(!pmutation.m_mutator->valueExists(pmutation.m_value))
- {
- ANKI_RESOURCE_LOGE("Value %d is not part of the mutator %s", pmutation.m_value, mutatorName.cstr());
- return Error::USER_DATA;
- }
- // Advance
- ++mutatorCount;
- ANKI_CHECK(mutatorEl.getNextSiblingElement("mutator", mutatorEl));
- } while(mutatorEl);
- ANKI_ASSERT(mutatorCount == prog.m_partialMutation.getSize());
- return Error::NONE;
- }
- Error MaterialResource::findBuiltinMutators(Program& prog)
- {
- U builtinMutatorCount = 0;
- // ANKI_TECHNIQUE
- CString techniqueMutatorName = BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::TECHNIQUE];
- const ShaderProgramResourceMutator* techniqueMutator = prog.m_prog->tryFindMutator(techniqueMutatorName);
- if(techniqueMutator)
- {
- for(U32 i = 0; i < techniqueMutator->m_values.getSize(); ++i)
- {
- const MutatorValue mvalue = techniqueMutator->m_values[i];
- if(mvalue >= MutatorValue(RenderingTechnique::COUNT) || mvalue < MutatorValue(RenderingTechnique::FIRST))
- {
- ANKI_RESOURCE_LOGE("Mutator %s has a wrong value %d", techniqueMutatorName.cstr(), mvalue);
- return Error::USER_DATA;
- }
- const RenderingTechnique techniqueId = RenderingTechnique(mvalue);
- const PtrSize progIdx = &prog - m_programs.getBegin();
- ANKI_ASSERT(progIdx < m_programs.getSize());
- m_techniqueToProgram[techniqueId] = U8(progIdx);
- const RenderingTechniqueBit mask = RenderingTechniqueBit(1 << techniqueId);
- if(!!(m_techniquesMask & mask))
- {
- ANKI_RESOURCE_LOGE("The %s technique appeared more than once", TECHNIQUE_NAMES[mvalue].cstr());
- return Error::USER_DATA;
- }
- m_techniquesMask |= mask;
- }
- ++builtinMutatorCount;
- prog.m_presentBuildinMutators |= U32(1 << BuiltinMutatorId::TECHNIQUE);
- }
- else
- {
- ANKI_RESOURCE_LOGE("Mutator %s should be present in every shader program referenced by a material",
- techniqueMutatorName.cstr());
- return Error::USER_DATA;
- }
- // ANKI_LOD
- CString lodMutatorName = BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::LOD];
- const ShaderProgramResourceMutator* lodMutator = prog.m_prog->tryFindMutator(lodMutatorName);
- if(lodMutator)
- {
- if(lodMutator->m_values.getSize() > MAX_LOD_COUNT)
- {
- ANKI_RESOURCE_LOGE("Mutator %s should have at least %u values in the program", lodMutatorName.cstr(),
- U32(MAX_LOD_COUNT));
- return Error::USER_DATA;
- }
- for(U32 i = 0; i < lodMutator->m_values.getSize(); ++i)
- {
- if(lodMutator->m_values[i] != MutatorValue(i))
- {
- ANKI_RESOURCE_LOGE("Values of the %s mutator in the program are not the expected",
- lodMutatorName.cstr());
- return Error::USER_DATA;
- }
- }
- prog.m_lodCount = U8(lodMutator->m_values.getSize());
- ++builtinMutatorCount;
- prog.m_presentBuildinMutators |= U32(1 << BuiltinMutatorId::LOD);
- }
- // ANKI_BONES
- CString bonesMutatorName = BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::BONES];
- const ShaderProgramResourceMutator* bonesMutator = prog.m_prog->tryFindMutator(bonesMutatorName);
- if(bonesMutator)
- {
- if(bonesMutator->m_values.getSize() != 2)
- {
- ANKI_RESOURCE_LOGE("Mutator %s should have 2 values in the program", bonesMutatorName.cstr());
- return Error::USER_DATA;
- }
- for(U32 i = 0; i < bonesMutator->m_values.getSize(); ++i)
- {
- if(bonesMutator->m_values[i] != MutatorValue(i))
- {
- ANKI_RESOURCE_LOGE("Values of the %s mutator in the program are not the expected",
- bonesMutatorName.cstr());
- return Error::USER_DATA;
- }
- }
- ++builtinMutatorCount;
- // Find if the bindings are present
- ConstWeakArray<ShaderProgramBinaryBlock> storageBlocks = prog.m_prog->getBinary().m_storageBlocks;
- U foundCount = 0;
- for(U32 i = 0; i < storageBlocks.getSize(); ++i)
- {
- const U32 binding = storageBlocks[i].m_binding;
- const U32 set = storageBlocks[i].m_set;
- if((binding == MATERIAL_BINDING_BONE_TRANSFORMS || binding == MATERIAL_BINDING_PREVIOUS_BONE_TRANSFORMS)
- && set == MATERIAL_SET_LOCAL)
- {
- ++foundCount;
- }
- }
- if(foundCount != 2)
- {
- ANKI_RESOURCE_LOGE("The shader has %s mutation but not the storage buffers for the bone transforms",
- bonesMutatorName.cstr());
- return Error::USER_DATA;
- }
- m_supportsSkinning = true;
- prog.m_presentBuildinMutators |= U32(1 << BuiltinMutatorId::BONES);
- }
- // VELOCITY
- CString velocityMutatorName = BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::VELOCITY];
- const ShaderProgramResourceMutator* velocityMutator = prog.m_prog->tryFindMutator(velocityMutatorName);
- if(velocityMutator)
- {
- if(velocityMutator->m_values.getSize() != 2)
- {
- ANKI_RESOURCE_LOGE("Mutator %s should have 2 values in the program", velocityMutatorName.cstr());
- return Error::USER_DATA;
- }
- for(U32 i = 0; i < velocityMutator->m_values.getSize(); ++i)
- {
- if(velocityMutator->m_values[i] != MutatorValue(i))
- {
- ANKI_RESOURCE_LOGE("Values of the %s mutator in the program are not the expected",
- velocityMutatorName.cstr());
- return Error::USER_DATA;
- }
- }
- ++builtinMutatorCount;
- prog.m_presentBuildinMutators |= U32(1 << BuiltinMutatorId::VELOCITY);
- }
- if(prog.m_partialMutation.getSize() + builtinMutatorCount != prog.m_prog->getMutators().getSize())
- {
- ANKI_RESOURCE_LOGE("Some mutatators are unacounted for");
- return Error::USER_DATA;
- }
- return Error::NONE;
- }
- Error MaterialResource::parseInput(XmlElement inputEl, Bool async, BitSet<128>& varsSet)
- {
- // Get var name
- CString varName;
- ANKI_CHECK(inputEl.getAttributeText("name", varName));
- // Try find var
- MaterialVariable* foundVar = tryFindVariable(varName);
- if(!foundVar)
- {
- ANKI_RESOURCE_LOGE("Input name is wrong, variable not found: %s", varName.cstr());
- return Error::USER_DATA;
- }
- // Set check
- const U32 idx = U32(foundVar - m_vars.getBegin());
- if(varsSet.get(idx))
- {
- ANKI_RESOURCE_LOGE("Input already has a value: %s", varName.cstr());
- return Error::USER_DATA;
- }
- varsSet.set(idx);
- // Set the value
- if(foundVar->isBoundableTexture())
- {
- CString texfname;
- ANKI_CHECK(inputEl.getAttributeText("value", texfname));
- ANKI_CHECK(getManager().loadResource(texfname, foundVar->m_image, async));
- m_textures.emplaceBack(getAllocator(), foundVar->m_image->getTexture());
- }
- else if(foundVar->m_dataType == ShaderVariableDataType::U32)
- {
- // U32 is a bit special. It might be a number or a bindless texture
- CString value;
- ANKI_CHECK(inputEl.getAttributeText("value", value));
- // Check if the value has letters
- Bool containsAlpharithmetic = false;
- for(Char c : value)
- {
- if((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'a'))
- {
- containsAlpharithmetic = true;
- break;
- }
- }
- // If it has letters it's a texture
- if(containsAlpharithmetic)
- {
- ANKI_CHECK(getManager().loadResource(value, foundVar->m_image, async));
- foundVar->m_U32 = foundVar->m_image->getTextureView()->getOrCreateBindlessTextureIndex();
- }
- else
- {
- ANKI_CHECK(GetAttribute<U32>()(inputEl, foundVar->m_U32));
- }
- }
- else
- {
- switch(foundVar->m_dataType)
- {
- #define ANKI_SVDT_MACRO(capital, type, baseType, rowCount, columnCount, isIntagralType) \
- case ShaderVariableDataType::capital: \
- ANKI_CHECK(GetAttribute<type>()(inputEl, foundVar->ANKI_CONCATENATE(m_, type))); \
- break;
- #include <AnKi/Gr/ShaderVariableDataType.defs.h>
- #undef ANKI_SVDT_MACRO
- default:
- ANKI_ASSERT(0);
- break;
- }
- }
- return Error::NONE;
- }
- void MaterialResource::prefillLocalUniforms()
- {
- if(m_localUniformsSize == 0)
- {
- return;
- }
- m_prefilledLocalUniforms = getAllocator().allocate(m_localUniformsSize, 1);
- memset(m_prefilledLocalUniforms, 0, m_localUniformsSize);
- for(const MaterialVariable& var : m_vars)
- {
- if(!var.isUniform())
- {
- continue;
- }
- switch(var.m_dataType)
- {
- #define ANKI_SVDT_MACRO(capital, type, baseType, rowCount, columnCount, isIntagralType) \
- case ShaderVariableDataType::capital: \
- ANKI_ASSERT(var.m_offsetInLocalUniforms + sizeof(type) <= m_localUniformsSize); \
- memcpy(static_cast<U8*>(m_prefilledLocalUniforms) + var.m_offsetInLocalUniforms, &var.m_##type, sizeof(type)); \
- break;
- #include <AnKi/Gr/ShaderVariableDataType.defs.h>
- #undef ANKI_SVDT_MACRO
- default:
- ANKI_ASSERT(0);
- break;
- }
- }
- }
- const MaterialVariant& MaterialResource::getOrCreateVariant(const RenderingKey& key_) const
- {
- RenderingKey key = key_;
- ANKI_ASSERT(m_techniqueToProgram[key.getRenderingTechnique()] != MAX_U8);
- const Program& prog = m_programs[m_techniqueToProgram[key.getRenderingTechnique()]];
- key.setLod(min<U32>(prog.m_lodCount - 1, key.getLod()));
- ANKI_ASSERT(!key.getSkinned() || !!(prog.m_presentBuildinMutators & U32(1 << BuiltinMutatorId::BONES)));
- ANKI_ASSERT(!key.getVelocity() || !!(prog.m_presentBuildinMutators & U32(1 << BuiltinMutatorId::VELOCITY)));
- MaterialVariant& variant =
- prog.m_variantMatrix[key.getRenderingTechnique()][key.getLod()][key.getSkinned()][key.getVelocity()];
- // Check if it's initialized
- {
- RLockGuard<RWMutex> lock(prog.m_variantMatrixMtx);
- if(ANKI_LIKELY(variant.m_prog.isCreated()))
- {
- return variant;
- }
- }
- // Not initialized, init it
- WLockGuard<RWMutex> lock(prog.m_variantMatrixMtx);
- // Check again
- if(variant.m_prog.isCreated())
- {
- return variant;
- }
- ShaderProgramResourceVariantInitInfo initInfo(prog.m_prog);
- for(const PartialMutation& m : prog.m_partialMutation)
- {
- initInfo.addMutation(m.m_mutator->m_name, m.m_value);
- }
- initInfo.addMutation(BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::TECHNIQUE], MutatorValue(key.getRenderingTechnique()));
- if(!!(prog.m_presentBuildinMutators & U32(1 << BuiltinMutatorId::LOD)))
- {
- initInfo.addMutation(BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::LOD], MutatorValue(key.getLod()));
- }
- if(!!(prog.m_presentBuildinMutators & U32(1 << BuiltinMutatorId::BONES)))
- {
- initInfo.addMutation(BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::BONES], MutatorValue(key.getSkinned()));
- }
- if(!!(prog.m_presentBuildinMutators & U32(1 << BuiltinMutatorId::VELOCITY)))
- {
- initInfo.addMutation(BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::VELOCITY], MutatorValue(key.getVelocity()));
- }
- const ShaderProgramResourceVariant* progVariant;
- prog.m_prog->getOrCreateVariant(initInfo, progVariant);
- variant.m_prog = progVariant->getProgram();
- if(!!(RenderingTechniqueBit(1 << key.getRenderingTechnique()) & RenderingTechniqueBit::ALL_RT))
- {
- variant.m_rtShaderGroupHandleIndex = progVariant->getShaderGroupHandleIndex();
- }
- return variant;
- }
- } // end namespace anki
|