1#include "MaterialManager.h"
8#include "MaterialBuilder.h"
9#include "ResourceStore.h"
10#include "ShaderBuilder.h"
12#include "Components/Core/ClipShapeComponent.h"
13#include "Serialization/MaterialReader.h"
14#include "Systems/Core/CameraSystem.h"
16#include "TextureManager.h"
17#include "EffectManager.h"
18#include "DefaultMaterial.h"
19#include "MaterialDefinition.h"
21#include "Foundation/Logging/Logger.h"
22#include "Foundation/Platform/FileSystemWatcher.h"
23#include "Foundation/Platform/IO.h"
24#include "Foundation/Platform/Timer.h"
46 const static char * ShaderNames[ShaderTypes::ShaderTypeCount] = {
60 reportLeaks(
"Material");
72 context->resourceStore->addSearchPath(
"../Data/Materials/");
73 context->resourceStore->addSearchPath(
"Materials/");
75 materialBase = loadMaterial(
"MaterialBase.material");
77 defaultResource = loadMaterial(
"DefaultMaterial.material");
79 static_cast<void>(loadMaterial(
"LineMaterial.material"));
80 static_cast<void>(loadMaterial(
"PointMaterial.material"));
81 static_cast<void>(loadMaterial(
"StandardMaterial.material"));
85 defaultResource->setTextureProperty(DefaultMaterial::DiffuseMap, context->textureManager->white);
90 return defaultResource;
95 auto found = materials.find(name.
to_string());
97 if (found != materials.end())
return found->second;
104 auto existing = getMaterial(fileName);
113 auto loaded = getAllocatedResources();
115 for (
auto & m : loaded) {
116 if (fileName == m->getSource()) {
124 loadInfo.materialLoadFlags = materialLoadFlags;
126 if (context->variables->get(
"resources.materials.autoReload",
false)) {
127 loadInfo.
loadFlags |= ResourceLoadFlags::AutoReload;
130 return loadResource(&loadInfo);
135 auto material = get(loadInfo->
handle);
138 if (!parseMaterial(context, loadInfo->
resourcePath, material->definition)) {
139 loadInfo->
handle->setFailedLoad();
140 setProcessed(loadInfo);
145 if (!setupMaterial(material)) {
146 LOG_WARNING(logger,
"Failed set up material %.*s", StringViewFormat(material->getName()));
147 loadInfo->
handle->setFailedLoad();
148 setProcessed(loadInfo);
152 auto found = materials.find(material->getName().to_string());
154 if (found != materials.end()) {
155 LOG_WARNING(logger,
"Overwriting registered material with name %s. Existing instances will not be affected, but retrieving by name will return new material.", material->getName().data());
158 materials[material->getName().to_string()] = loadInfo->
handle;
160 setProcessed(loadInfo);
167 auto loadInfo = createLoadInfo();
168 loadInfo->resourceId = material->getId();
169 loadInfo->resourcePath = material->getSource().to_string();
170 loadInfo->resourceName = material->getName().to_string();
172 loadInfo->handle = material;
174 static_cast<void>(loadResource(loadInfo));
177bool Cogs::Core::MaterialManager::setupMaterial(
Material * material)
179 auto & definition = material->definition;
181 if (!definition.isTemplate()) {
182 if (!material->constantBuffers.
buffers.size()) {
183 if (!applyMaterialDefinition(context, material->definition, *material))
return false;
185 material->constantBuffers.
buffers.clear();
187 if (!applyMaterialDefinition(context, definition_, *material))
return false;
188 material->definition = definition_;
193 if (definition.isTemplate()) {
194 material->setResident();
198 material->permutationKeys.resize(definition.permutations.size());
200 for (
auto & materialPermutation : definition.permutations) {
201 material->permutationKeys[materialPermutation.permutationIndex] = materialPermutation.permutationName;
214 case Cogs::Format::R8_UNORM:
215 case Cogs::Format::R16_UNORM:
216 case Cogs::Format::R8_SNORM:
217 case Cogs::Format::R16_SNORM:
218 case Cogs::Format::R16_FLOAT:
219 case Cogs::Format::R32_FLOAT:
220 return MaterialDataType::Float;
221 case Cogs::Format::R8G8_UNORM:
222 case Cogs::Format::R16G16_UNORM:
223 case Cogs::Format::R8G8_SNORM:
224 case Cogs::Format::R16G16_SNORM:
225 case Cogs::Format::R16G16_FLOAT:
226 case Cogs::Format::R32G32_FLOAT:
227 return MaterialDataType::Float2;
228 case Cogs::Format::R8G8B8_UNORM:
229 case Cogs::Format::R16G16B16_UNORM:
230 case Cogs::Format::R8G8B8_SNORM:
231 case Cogs::Format::R16G16B16_SNORM:
232 case Cogs::Format::R16G16B16_FLOAT:
233 case Cogs::Format::R32G32B32_FLOAT:
234 case Cogs::Format::R8G8B8_UNORM_SRGB:
235 case Cogs::Format::R11G11B10_FLOAT:
236 case Cogs::Format::R5G6B5_UNORM:
237 return MaterialDataType::Float3;
238 case Cogs::Format::R8G8B8A8_UNORM:
239 case Cogs::Format::R16G16B16A16_UNORM:
240 case Cogs::Format::R8G8B8A8_SNORM:
241 case Cogs::Format::R16G16B16A16_SNORM:
242 case Cogs::Format::R16G16B16A16_FLOAT:
243 case Cogs::Format::R32G32B32A32_FLOAT:
244 case Cogs::Format::R8G8B8A8_UNORM_SRGB:
245 case Cogs::Format::R10G10B10A2_UNORM:
246 case Cogs::Format::R5G5B5A1_UNORM:
247 case Cogs::Format::R4G4B4A4_UNORM:
248 case Cogs::Format::R9G9B9E5_FLOAT:
249 return MaterialDataType::Float4;
250 case Cogs::Format::R8_UINT:
251 case Cogs::Format::R16_UINT:
252 case Cogs::Format::R32_UINT:
253 return MaterialDataType::UInt;
254 case Cogs::Format::R8G8_UINT:
255 case Cogs::Format::R16G16_UINT:
256 case Cogs::Format::R32G32_UINT:
257 return MaterialDataType::UInt2;
258 case Cogs::Format::R8G8B8_UINT:
259 case Cogs::Format::R16G16B16_UINT:
260 case Cogs::Format::R32G32B32_UINT:
261 return MaterialDataType::UInt3;
262 case Cogs::Format::R8G8B8A8_UINT:
263 case Cogs::Format::R16G16B16A16_UINT:
264 case Cogs::Format::R32G32B32A32_UINT:
265 case Cogs::Format::R10G10B10A2_UINT:
266 return MaterialDataType::UInt4;
267 case Cogs::Format::R8_SINT:
268 case Cogs::Format::R16_SINT:
269 case Cogs::Format::R32_SINT:
270 return MaterialDataType::Int;
271 case Cogs::Format::R8G8_SINT:
272 case Cogs::Format::R16G16_SINT:
273 case Cogs::Format::R32G32_SINT:
274 return MaterialDataType::Int2;
275 case Cogs::Format::R8G8B8_SINT:
276 case Cogs::Format::R16G16B16_SINT:
277 case Cogs::Format::R32G32B32_SINT:
278 return MaterialDataType::Int3;
279 case Cogs::Format::R8G8B8A8_SINT:
280 case Cogs::Format::R16G16B16A16_SINT:
281 case Cogs::Format::R32G32B32A32_SINT:
282 return MaterialDataType::Int4;
283 case Cogs::Format::MAT4X4_FLOAT:
284 return MaterialDataType::Float4x4;
286 LOG_ERROR(logger,
"Illegal format %u",
unsigned(format));
287 return MaterialDataType::Unknown;
291 const char* formatShaderTypeString(Cogs::Format format)
293 switch (formatShaderType(format)) {
294 case MaterialDataType::Float:
return "float";
295 case MaterialDataType::Float2:
return "float2";
296 case MaterialDataType::Float3:
return "float3";
297 case MaterialDataType::Float4:
return "float4";
298 case MaterialDataType::UInt:
return "uint";
299 case MaterialDataType::UInt2:
return "uint2";
300 case MaterialDataType::UInt3:
return "uint3";
301 case MaterialDataType::UInt4:
return "uint4";
302 case MaterialDataType::Int:
return "int";
303 case MaterialDataType::Int2:
return "int2";
304 case MaterialDataType::Int3:
return "int3";
305 case MaterialDataType::Int4:
return "int4";
306 case MaterialDataType::Float4x4:
return "float4x4";
313 void moveSystemGeneratedParametersLast(std::vector<ShaderInterfaceMemberDefinition>& parameters)
315 std::sort(parameters.begin(), parameters.end(),
318 int aValue = (a.type == MaterialDataType::SV_IsFrontFace || a.type == MaterialDataType::VFACE || a.type == MaterialDataType::SV_InstanceID) ? 1 : 0;
319 int bValue = (b.type == MaterialDataType::SV_IsFrontFace || b.type == MaterialDataType::VFACE || b.type == MaterialDataType::SV_InstanceID) ? 1 : 0;
320 return aValue < bValue;
324 void addShaderStageInterfaceMembers(
const std::string& materialName,
325 std::vector<ShaderInterfaceMemberDefinition>& existingMembers,
326 std::span<const ShaderInterfaceMemberDefinition> newMembers)
335 if ((member.semantic.name != ShaderInterfaceMemberDefinition::SemanticName::None) &&
336 (member.semantic.name == existing.semantic.name) &&
337 (member.semantic.slot == existing.semantic.slot))
341 if (member.modifiers == existing.modifiers &&
342 member.name == existing.name &&
343 member.type == existing.type &&
344 member.dimension == existing.dimension &&
345 member.dimensionString == existing.dimensionString)
349 existing.inheritanceLevel = std::min(existing.inheritanceLevel, member.inheritanceLevel);
351 else if (member.inheritanceLevel < existing.inheritanceLevel) {
352 LOG_DEBUG(logger,
"%s: Replacing '%s' (level=%d) with '%s' (level=%d) (semantic=%d:%d)",
353 materialName.c_str(),
354 existing.name.c_str(),
int(existing.inheritanceLevel),
355 member.name.c_str(),
int(member.inheritanceLevel),
356 int(existing.semantic.name),
int(existing.semantic.slot));
357 existing.name = member.name;
358 existing.modifiers = member.modifiers;
359 existing.type = member.type;
360 existing.dimension = member.dimension;
361 existing.dimensionString = member.dimensionString;
363 else if (existing.inheritanceLevel < member.inheritanceLevel) {
364 LOG_DEBUG(logger,
"%s: Keeping '%s' (level=%d) over '%s' (level=%d) (semantic=%d:%d)",
365 materialName.c_str(),
366 existing.name.c_str(),
int(existing.inheritanceLevel),
367 member.name.c_str(),
int(member.inheritanceLevel),
368 int(existing.semantic.name),
int(existing.semantic.slot));
371 LOG_ERROR(logger,
"%s: Conflicting inheritance levels: '%s' (level=%d) over '%s' (level=%d) (semantic=%d:%d)",
372 materialName.c_str(),
373 existing.name.c_str(),
int(existing.inheritanceLevel),
374 member.name.c_str(),
int(member.inheritanceLevel),
375 int(existing.semantic.name),
int(existing.semantic.slot));
380 if (member.name == existing.name) {
387 existingMembers.emplace_back(member);
396 std::vector<ShaderInterfaceMemberDefinition>& vertexMembers = materialPermutation.effect.vertexShader.shaderInterface.members;
397 std::vector<ShaderInterfaceMemberDefinition>& geometryMembers = materialPermutation.effect.geometryShader.shaderInterface.members;
398 std::vector<ShaderInterfaceMemberDefinition>& surfaceMembers = materialPermutation.effect.pixelShader.shaderInterface.members;
400 std::vector<ShaderInterfaceMemberDefinition> tmp;
401 addShaderStageInterfaceMembers(materialPermutation.name, tmp, vertexMembers);
402 vertexMembers.swap(tmp);
405 addShaderStageInterfaceMembers(materialPermutation.name, tmp, geometryMembers);
406 geometryMembers.swap(tmp);
409 addShaderStageInterfaceMembers(materialPermutation.name, tmp, surfaceMembers);
410 surfaceMembers.swap(tmp);
415 std::span<const ShaderVariantSelector> selectors,
416 std::span<const ShaderVariantDefinition> variants)
418 std::vector<ShaderInterfaceMemberDefinition>& vertexMembers = materialPermutation.effect.vertexShader.shaderInterface.members;
419 std::vector<ShaderInterfaceMemberDefinition>& geometryMembers = materialPermutation.effect.geometryShader.shaderInterface.members;
420 std::vector<ShaderInterfaceMemberDefinition>& surfaceMembers = materialPermutation.effect.pixelShader.shaderInterface.members;
424 if ((variant.type == ShaderVariantType::Bool && v.value == 1) ||
425 (variant.type == ShaderVariantType::Format && v.value != 0))
427 size_t a = vertexMembers.size();
428 addShaderStageInterfaceMembers(materialPermutation.name, vertexMembers, variant.vertexInterface.members);
429 size_t b = vertexMembers.size();
432 if (variant.type == ShaderVariantType::Format) {
433 for (
size_t i = a; i < b; i++) {
434 if (vertexMembers[i].type == MaterialDataType::Unknown) {
435 vertexMembers[i].type = formatShaderType(Cogs::Format(selectors[variant.index].value));
439 addShaderStageInterfaceMembers(materialPermutation.name, geometryMembers, variant.geometryInterface.members);
440 addShaderStageInterfaceMembers(materialPermutation.name, surfaceMembers, variant.surfaceInterface.members);
443 moveSystemGeneratedParametersLast(materialPermutation.effect.pixelShader.shaderInterface.members);
448 void addDefinesFromVariants(std::vector<std::pair<std::string, std::string>>& definitions,
450 std::span<const ShaderVariantSelector> selectors,
451 std::span<const ShaderVariantDefinition> variants)
456 if (variant.type == ShaderVariantType::Bool && selector.value == 1) {
457 definitions.emplace_back(variant.value,
"1");
460 else if (variant.type == ShaderVariantType::Int) {
461 definitions.emplace_back(variant.value, std::to_string(selector.value));
464 else if (variant.type == ShaderVariantType::Enum) {
465 for (
auto & enumerator : variant.values) {
466 if (enumerator.index == selector.value) {
467 definitions.emplace_back(enumerator.value,
"1");
473 else if (variant.type == ShaderVariantType::Format && selector.value != 0) {
475 const char* value =
nullptr;
476 switch (formatShaderType(Cogs::Format(selector.value))) {
477 case MaterialDataType::Float: value =
"COGS_FLOAT";
break;
478 case MaterialDataType::Float2: value =
"COGS_FLOAT2";
break;
479 case MaterialDataType::Float3: value =
"COGS_FLOAT3";
break;
480 case MaterialDataType::Float4: value =
"COGS_FLOAT4";
break;
481 case MaterialDataType::UInt: value =
"COGS_UINT";
break;
482 case MaterialDataType::UInt2: value =
"COGS_UINT2";
break;
483 case MaterialDataType::UInt3: value =
"COGS_UINT3";
break;
484 case MaterialDataType::UInt4: value =
"COGS_UINT4";
break;
485 case MaterialDataType::Int: value =
"COGS_INT";
break;
486 case MaterialDataType::Int2: value =
"COGS_INT2";
break;
487 case MaterialDataType::Int3: value =
"COGS_INT3";
break;
488 case MaterialDataType::Int4: value =
"COGS_INT4";
break;
489 case MaterialDataType::Float4x4: value =
"COGS_FLOAT4X4";
break;
491 LOG_ERROR(logger,
"Variant selector value is not a valid vertex format");
495 definitions.emplace_back(variant.value, value);
498 else if (variant.type == ShaderVariantType::String) {
499 if (selector.value ==
size_t(-1))
continue;
501 assert(selector.value <= materialInstance->
variantStrings.size() &&
"Variant selector string index out of range.");
502 definitions.emplace_back(variant.value, materialInstance->
variantStrings[selector.value]);
507 bool sanityCheckVertexElements(std::span<const Cogs::VertexElement> vertexElements)
509 for (
size_t i = 1; i < vertexElements.size(); i++) {
510 for (
size_t j = i; j < vertexElements.size(); j++) {
512 if ((vertexElements[i - 1].semantic == vertexElements[j].semantic) &&
513 (vertexElements[i - 1].semanticIndex == vertexElements[j].semanticIndex))
515 LOG_ERROR(logger,
"Invalid streams layout, vertex element semantic %.*s%u is specified more than once",
516 StringViewFormat(Cogs::getElementSemanticName(vertexElements[j].semantic)),
517 unsigned(vertexElements[j].semanticIndex));
526 void adjustVariantsUsingVertexElements(ShaderVariantSelectors& variantSelectors,
528 std::span<const Cogs::VertexElement> vertexElements)
530 const size_t indexLimit = variantSelectors.size();
531 const ShaderVariants& variantDefinitions = materialInstance->
material->definition.variants;
532 assert(variantDefinitions.size() == indexLimit);
534 std::string variantKeyBase;
537 switch (element.semantic) {
546 assert(
false &&
"Illegal semantic");
550 assert(element.semanticIndex < 10);
551 variantKeyBase.push_back(
char(
'0' + element.semanticIndex));
552 if (
size_t index = materialInstance->
material->getVariantIndex(variantKeyBase); index != Material::NoVariantIndex) {
553 assert(index < indexLimit);
554 assert(variantSelectors[index].index == index);
555 assert(variantDefinitions[index].type == ShaderVariantType::Format &&
"Error in MaterialBase.material");
556 variantSelectors[index].value = size_t(element.format);
562 [[nodiscard]]
bool checkSingleRequirement(
const ShaderVariantSelectors& variantSelectors,
566 if (requirement.variant.empty()) {
567 LOG_ERROR(logger,
"Empty variant requirement");
572 if (requirement.value.empty()) {
573 const char* a = requirement.variant.c_str();
577 while (*b !=
'\0' && *b !=
'|') { b++; }
580 if (
size_t ix = materialInstance->
material->getVariantIndex(key); ix != Material::NoVariantIndex) {
582 switch (target.type) {
583 case ShaderVariantType::Bool:
584 case ShaderVariantType::Int:
585 case ShaderVariantType::Format:
586 if (variantSelectors[ix].value != 0)
return true;
589 case ShaderVariantType::Enum:
590 case ShaderVariantType::String:
591 LOG_ERROR(logger,
"Requirement '%.*s' references variant with unsupported type", StringViewFormat(key));
598 LOG_ERROR(logger,
"Variant requirement '%.*s' refers non-existing variant", StringViewFormat(key));
611 size_t ix = materialInstance->
material->getVariantIndex(requirement.variant);
613 if (ix == Material::NoVariantIndex) {
614 LOG_ERROR(logger,
"Variant requirement %s=%s refers non-existing variant", requirement.variant.c_str(), requirement.value.c_str());
618 assert(ix < materialInstance->material->definition.variants.size());
622 bool anySuccess =
false;
632 switch (target.type) {
633 case ShaderVariantType::Format:
635 if (variantSelectors[ix].value && value == formatShaderTypeString(Cogs::Format(variantSelectors[ix].value))) {
638 else if (
const Cogs::FormatInfo* info = Cogs::getFormatInfo(Cogs::Format(variantSelectors[ix].value)); info) {
639 if (value == info->vName || value == info->name) {
645 case ShaderVariantType::Bool:
646 case ShaderVariantType::Int:
647 case ShaderVariantType::Enum:
648 case ShaderVariantType::String:
649 LOG_ERROR(logger,
"Requirement '%s' references variant with type with unimplemented handling", requirement.variant.c_str());
657 }
while (!anySuccess);
662 void checkVariantTriggers(ShaderVariantSelectors& variantSelectors,
665 std::vector<size_t> unsatisifiedSet;
668 if ( variant.type == ShaderVariantType::Bool && !variant.triggers.empty()) {
669 unsatisifiedSet.push_back(selector.index);
673 bool anyChange =
true;
674 std::vector<size_t> nextSet;
675 while (!unsatisifiedSet.empty() && anyChange) {
679 while (!unsatisifiedSet.empty()) {
680 size_t unsatisfiedIx = unsatisifiedSet.back();
681 unsatisifiedSet.pop_back();
685 bool allSatisfied =
true;
687 allSatisfied = checkSingleRequirement(variantSelectors, materialInstance, requirement);
688 if (!allSatisfied)
break;
692 variantSelectors[unsatisfiedIx].value = 1;
696 nextSet.push_back(unsatisfiedIx);
699 unsatisifiedSet.swap(nextSet);
703 [[nodiscard]]
bool checkMaterialRequirements(
const ShaderVariantSelectors& variantSelectors,
708 if (!checkSingleRequirement(variantSelectors, materialInstance, requirement)) {
709 LOG_ERROR(logger,
"Material requirement %s=%s not met", requirement.variant.c_str(), requirement.value.c_str());
716 [[nodiscard]]
bool checkVariantRequirements(
const ShaderVariantSelectors& variantSelectors,
722 if (selector.value && variant.type == ShaderVariantType::Bool && !variant.requirements.empty()) {
726 if (!checkSingleRequirement(variantSelectors, materialInstance, requirement)) {
727 LOG_ERROR(logger,
"Material '%.*s' instance '%.*s' variant requirement %s=%s not met",
729 StringViewFormat(materialInstance->
getName()),
730 requirement.variant.c_str(),
731 requirement.value.c_str());
743 bool matchInterfaceMemberToVertexElement(std::span<size_t> memberElementIndex,
744 std::span<const ShaderInterfaceMemberDefinition> interfaceMembers,
745 std::span<const Cogs::VertexElement> vertexElements)
748 assert(memberElementIndex.size() == interfaceMembers.size());
750 for (
size_t j = 0; j < memberElementIndex.size(); j++) {
755 switch (member.semantic.name) {
758 case ShaderInterfaceMemberDefinition::SemanticName::None:
759 LOG_ERROR(logger,
"Vertex shader input '%s' has no associated semantic", member.name.c_str());
772 assert(
size_t(ShaderInterfaceMemberDefinition::SemanticName::FirstSystemValueSemantic) <=
size_t(member.semantic.name));
773 memberElementIndex[j] = ~size_t(0);
778 for (
size_t i = 0; i < vertexElements.size(); i++) {
784 memberElementIndex[j] = i;
790 LOG_ERROR(logger,
"Failed to match vertex shader input '%s' with semantic %.*s:%u to a vertex stream semantic",
792 StringViewFormat(ShaderInterfaceMemberDefinition::semanticNameString(member.semantic.name)),
793 unsigned(member.semantic.slot));
803 if (
size_t index = materialInstance->
material->getVariantIndex(key); index != Material::NoVariantIndex) {
804 assert(index < variantSelectors.size());
805 assert(variantSelectors[index].index == index);
806 const ShaderVariants& variantDefinitions = materialInstance->
material->definition.variants;
807 assert(variantDefinitions[index].type == ShaderVariantType::Enum &&
"Error in MaterialBase.material");
809 if (e.key == value) {
810 variantSelectors[index].value = e.index;
817 if (
size_t index = materialInstance->
material->getVariantIndex(key); index != Material::NoVariantIndex) {
818 assert(index < variantSelectors.size());
819 assert(variantSelectors[index].index == index);
820 const ShaderVariants& variantDefinitions = materialInstance->
material->definition.variants;
821 assert(variantDefinitions[index].type == ShaderVariantType::Bool &&
"Error in MaterialBase.material");
822 variantSelectors[index].value = value ? 1 : 0;
835 assert(materialInstance);
836 assert(streamsLayout);
842 if (material->definition.permutations.empty() || materialInstance->
permutationIndex > (material->definition.permutations.size() - 1)) {
843 LOG_ERROR(logger,
"Permutation out of range.");
848 std::vector<VertexElement> vertexElements;
849 for (
size_t i = 0; i < streamsLayout->
numStreams; i++) {
851 vertexElements.insert(vertexElements.end(),
855 if (!sanityCheckVertexElements(vertexElements)) {
859 ShaderVariantSelectors variantSelectors = materialInstance->
variantSelectors;
860 adjustVariantsUsingVertexElements(variantSelectors, materialInstance, vertexElements);
870 setEnumVariant(variantSelectors, materialInstance,
"ClipShape",
"Cube");
873 setEnumVariant(variantSelectors, materialInstance,
"ClipShape",
"InvertedCube");
874 clipInPixelShader =
true;
877 assert(
false &&
"Invalid enum");
880 if (clipInPixelShader) {
881 setBoolVariant(variantSelectors, materialInstance,
"ClipInPixelShader",
true);
884 setBoolVariant(variantSelectors, materialInstance,
"ClipInVertexShader",
true);
889 checkVariantTriggers(variantSelectors, materialInstance);
892 if (!checkMaterialRequirements(variantSelectors, materialInstance)
893 || !checkVariantRequirements(variantSelectors, materialInstance))
903 materialPermutation.name += std::to_string(
id++);
907 assert(variantSelectors.size() == material->definition.variants.size());
909 if (definition.isShared) {
910 variantSelectors[definition.index].value = definition.defaultValue;
915 resolveShaderInterfaceMembers(materialPermutation);
918 addShaderInterfaceMembersFromVariants(materialPermutation, variantSelectors, materialPermutation.variants);
919 addShaderInterfaceMembersFromVariants(materialPermutation, permutation->getSelectors(), permutation->getVariants());
922 std::vector<size_t> memberElementIndex(materialPermutation.effect.vertexShader.shaderInterface.members.size());
923 if (!matchInterfaceMemberToVertexElement(memberElementIndex,
924 materialPermutation.effect.vertexShader.shaderInterface.members,
930 const std::string& permutationName = permutation->getDefinition()->name;
933 materialPermutation.effect.
name = materialPermutation.name + permutationName;
934 materialPermutation.effect.vertexShader.loadPath = materialPermutation.name + ShaderNames[ShaderTypes::Vertex] + permutationName;
935 if (materialPermutation.effect.hullShader.customSourcePath.size()) {
936 materialPermutation.effect.hullShader.loadPath = materialPermutation.name + ShaderNames[ShaderTypes::Hull] + permutationName;
937 materialPermutation.effect.domainShader.loadPath = materialPermutation.name + ShaderNames[ShaderTypes::Domain] + permutationName;
939 if (materialPermutation.effect.geometryShader.customSourcePath.size()) {
940 materialPermutation.effect.geometryShader.loadPath = materialPermutation.name + ShaderNames[ShaderTypes::Geometry] + permutationName;
942 materialPermutation.effect.pixelShader.loadPath = materialPermutation.name + ShaderNames[ShaderTypes::Pixel] + permutationName;
945 std::vector<std::pair<std::string, std::string>> definitions{
948 {
"COGS_FLOAT",
"1" },
949 {
"COGS_FLOAT2",
"2" },
950 {
"COGS_FLOAT3",
"3" },
951 {
"COGS_FLOAT4",
"4" },
952 {
"COGS_UINT",
"5" },
953 {
"COGS_UINT2",
"6" },
954 {
"COGS_UINT3",
"7" },
955 {
"COGS_UINT4",
"8" },
957 {
"COGS_INT2",
"10" },
958 {
"COGS_INT3",
"11" },
959 {
"COGS_INT4",
"12" },
960 {
"COGS_FLOAT4X4",
"13" }
964 for (
auto & d : materialPermutation.effect.
definitions) {
965 definitions.emplace_back(d.first, d.second);
967 for (
auto & d : materialPermutation.effect.
definitions) {
968 definitions.emplace_back(d.first, d.second);
970 for (
auto & d : permutation->getDefinition()->definitions) {
971 definitions.emplace_back(d.first, d.second);
973 addDefinesFromVariants(definitions, materialInstance, permutation->getSelectors(), permutation->getVariants());
974 addDefinesFromVariants(definitions, materialInstance, variantSelectors, materialPermutation.variants);
978 switch (graphicsDeviceType)
981 success = buildEffectES3(context, definitions, materialPermutation, *permutation, passOptions.multiViews);
984 success = buildEffectWebGPU(context, definitions, materialPermutation, *permutation, passOptions.multiViews);
987 success = buildEffect(context, definitions, materialPermutation, *permutation);
991 LOG_ERROR(logger,
"Failed to build material shader source");
997 for (
const std::pair<std::string,std::string>& d : definitions) {
1001 EffectHandle effect = context->effectManager->loadEffect(materialPermutation.effect);
1005 if (context->variables->get(
"resources.effects.autoReload",
false)) {
1006 auto watchShader = [&](
const StringView & fileName) {
1007 auto path = context->resourceStore->getResourcePath(fileName);
1010 context->resourceStore->purge(path);
1015 auto absolute = IO::absolute(path);
1017 context->watcher->watchFile(absolute, callback);
1020 watchShader(materialPermutation.effect.vertexShader.customSourcePath);
1021 watchShader(materialPermutation.effect.pixelShader.customSourcePath);
1023 watchShader(permutation->getDefinition()->vertexShader);
1024 watchShader(permutation->getDefinition()->pixelShader);
1032 return context->renderer->getResources()->updateResource(handle);
1037 context->renderer->getResources()->releaseResource(resource);
1042 reportLeaks(
"MaterialInstance");
1047 ResourceManager::initialize();
1049 resources.resize(16384);
1052void Cogs::Core::MaterialInstanceManager::initializeDefaultMaterialInstance()
1054 defaultResource = createMaterialInstance(context->materialManager->getDefaultMaterial());
1059 auto material = materialHandle.
resolve();
1061 auto handle = create();
1062 auto instance = handle.resolve();
1064 instance->setupInstance(material);
1066 instance->setLoaded();
1067 instance->setChanged();
1074 return getByName(name);
1079 return context->renderer->getResources()->updateResource(handle);
1084 context->renderer->getResources()->releaseResource(resource);
1087int Cogs::Core::MaterialInstanceManager::getUpdateQuota()
const
1089 return context->variables->get(
"resources.materialInstances.frameUpdateQuota", 0);
void initialize() override
Initialize the MaterialInstanceManager.
~MaterialInstanceManager()
Destructs the MaterialInstanceManager.
MaterialInstanceHandle createMaterialInstance(const MaterialHandle &material)
Create a new MaterialInstance from the Material given held by material.
void handleDeletion(MaterialInstance *resource) override
Overridden to handle material instance deletion, removing the resource from the renderer.
ActivationResult handleActivation(MaterialInstanceHandle handle, MaterialInstance *resource) override
Overridden to handle activation of MaterialInstances, updating the resource in the renderer.
MaterialHandle loadMaterial(const StringView &fileName, MaterialLoadFlags materialLoadFlags=MaterialLoadFlags::None, ResourceId resourceId=NoResourceId)
Loads a Material from the given fileName.
void handleDeletion(Material *resource) override
Overridden to handle material deletion, removing the resource from the renderer.
ActivationResult handleActivation(MaterialHandle handle, Material *resource) override
Overridden to handle activation of Materials, updating the resource in the renderer.
MaterialHandle getDefaultMaterial()
Get the default material.
void releaseAll()
Clear out all materials, done as part of shutdown process.
EffectHandle loadMaterialVariant(Material *material, const MaterialInstance *materialInstance, const MeshStreamsLayout *streamsLayout, const EnginePermutation *permutation, const RenderPassOptions &passOptions, const ClipShapeType clipShape)
void handleLoad(MaterialLoadInfo *loadInfo) override
Overridden to handle loading of Material resources.
void initializeDefaultMaterial()
Initializes the MaterialManager, setting up the default material.
~MaterialManager()
Destructs the MaterialManager.
void clear() override
Clear the resource manager, cleaning up resources held by member handles.
Log implementation class.
Provides a weakly referenced view over the contents of a string.
size_t find_first_of(char character, size_t pos=0) const noexcept
Find the first occurance of the given character from the specified starting position.
constexpr StringView substr(size_t offset, size_t count=NoPosition) const noexcept
Get the given sub string.
static constexpr size_t NoPosition
No position.
std::string to_string() const
String conversion method.
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
ClipShapeType
Specifices what kind of shape a clip shape has.
@ InvertedCube
Clip the inside of a cube.
@ None
No clipping at all.
@ Cube
Clip the outside of a cube,.
ActivationResult
Defines results for resource activation.
MaterialDataType
Defines available data types for material properties.
MaterialLoadFlags
Material loading flags.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
GraphicsDeviceType
Contains types of graphics devices that may be supported.
@ OpenGLES30
Graphics device using the OpenGLES 3.0 API.
@ WebGPU
Graphics device using the WebGPU API Backend.
std::pair< std::string, std::string > PreprocessorDefinition
Preprocessor definition.
ElementSemantic
Element semantics used to map data to the shader stage.
@ Position
Position semantic.
@ Tangent
Tangent semantic.
@ InstanceMatrix
Instance matrix semantic.
@ InstanceVector
Instance vector semantic.
@ TextureCoordinate
Texture coordinate semantic.
std::vector< MaterialPropertyBuffer > buffers
Constant buffer instances.
uint16_t buffersGeneration
If the constant buffer bindings need updates.
static void initialize(MaterialManager *materialManager)
Initialize the default material, updating all material property keys.
std::string name
Name of the effect.
MeshStreamsLayout streamsLayout
The vertex layout this effect expects.
PreprocessorDefinitions definitions
Preprocessor definitions.
struct Material * material
Owning material resource.
Material instances represent a specialized Material combined with state for all its buffers and prope...
std::vector< std::string > variantStrings
String storage for string variants.
size_t permutationIndex
Index of material permutation to use.
Material * material
Material resource this MaterialInstance is created from.
ShaderVariantSelectors variantSelectors
Variant selectors.
Defines loading information for Material resources.
Material resources define the how of geometry rendering (the what is defined by Mesh and Texture reso...
VertexFormatHandle vertexFormats[maxStreams]
StringView getName() const
Get the name of the resource.
Resource handle base class handling reference counting of resources derived from ResourceBase.
static const ResourceHandle_t NoHandle
Handle representing a default (or none if default not present) resource.
ResourceType * resolve() const
Resolve the handle, returning a pointer to the actual resource.
std::string resourcePath
Resource path. Used to locate resource.
ResourceId resourceId
Unique resource identifier. Must be unique among resources of the same kind.
ResourceHandleBase handle
Handle to resource structure for holding actual resource data.
ResourceLoadFlags loadFlags
Desired loading flags. Used to specify how the resource will be loaded.
Vertex element structure used to describe a single data element in a vertex for the input assembler.
uint16_t semanticIndex
Index for the semantic mapping.
ElementSemantic semantic
Semantic mapping of the element (position, normal, etc...).