diff --git a/NEW_RELEASE_NOTES.md b/NEW_RELEASE_NOTES.md index c3161a7700..1ca02cd83c 100644 --- a/NEW_RELEASE_NOTES.md +++ b/NEW_RELEASE_NOTES.md @@ -8,3 +8,4 @@ appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md). ## Release notes for next branch cut +- materials: prepare ES2 support [⚠️ **New Material Version**] diff --git a/libs/filabridge/include/filament/MaterialEnums.h b/libs/filabridge/include/filament/MaterialEnums.h index 280a2d2adc..5c94ce3bbf 100644 --- a/libs/filabridge/include/filament/MaterialEnums.h +++ b/libs/filabridge/include/filament/MaterialEnums.h @@ -27,7 +27,7 @@ namespace filament { // update this when a new version of filament wouldn't work with older materials -static constexpr size_t MATERIAL_VERSION = 32; +static constexpr size_t MATERIAL_VERSION = 33; /** * Supported shading models diff --git a/libs/filamat/src/MaterialBuilder.cpp b/libs/filamat/src/MaterialBuilder.cpp index 46345adf45..f7a18abce5 100644 --- a/libs/filamat/src/MaterialBuilder.cpp +++ b/libs/filamat/src/MaterialBuilder.cpp @@ -639,7 +639,7 @@ bool MaterialBuilder::runSemanticAnalysis(MaterialInfo const& info, using namespace backend; TargetApi targetApi = semanticCodeGenParams.targetApi; - TargetLanguage targetLanguage = semanticCodeGenParams.targetLanguage; + TargetLanguage const targetLanguage = semanticCodeGenParams.targetLanguage; assertSingleTargetApi(targetApi); if (mEnableFramebufferFetch) { @@ -648,13 +648,14 @@ bool MaterialBuilder::runSemanticAnalysis(MaterialInfo const& info, } bool result = false; - ShaderModel model = semanticCodeGenParams.shaderModel; + std::string shaderCode; + ShaderModel const model = semanticCodeGenParams.shaderModel; if (mMaterialDomain == filament::MaterialDomain::COMPUTE) { - std::string shaderCode = peek(ShaderStage::COMPUTE, semanticCodeGenParams, mProperties); + shaderCode = peek(ShaderStage::COMPUTE, semanticCodeGenParams, mProperties); result = GLSLTools::analyzeComputeShader(shaderCode, model, targetApi, targetLanguage, info); } else { - std::string shaderCode = peek(ShaderStage::VERTEX, semanticCodeGenParams, mProperties); + shaderCode = peek(ShaderStage::VERTEX, semanticCodeGenParams, mProperties); result = GLSLTools::analyzeVertexShader(shaderCode, model, mMaterialDomain, targetApi, targetLanguage, info); if (result) { @@ -663,6 +664,9 @@ bool MaterialBuilder::runSemanticAnalysis(MaterialInfo const& info, targetApi, targetLanguage, mCustomSurfaceShading, info); } } + if (!result && mPrintShaders) { + slog.e << shaderCode << io::endl; + } return result; #else return true; @@ -817,7 +821,7 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector lock(entriesLock); + std::unique_lock const lock(entriesLock); // below we rely on casting ShaderStage to uint8_t static_assert(sizeof(filament::backend::ShaderStage) == 1); @@ -1241,7 +1248,7 @@ std::string MaterialBuilder::peek(backend::ShaderStage stage, case backend::ShaderStage::COMPUTE: return sg.createComputeProgram( params.shaderModel, params.targetApi, params.targetLanguage, - info, {}); + info); } } diff --git a/libs/filamat/src/shaders/CodeGenerator.cpp b/libs/filamat/src/shaders/CodeGenerator.cpp index b9000dd8bd..b27a040466 100644 --- a/libs/filamat/src/shaders/CodeGenerator.cpp +++ b/libs/filamat/src/shaders/CodeGenerator.cpp @@ -59,7 +59,6 @@ utils::io::sstream& CodeGenerator::generateProlog(utils::io::sstream& out, Shade if (material.hasExternalSamplers) { out << "#extension GL_OES_EGL_image_external_essl3 : require\n\n"; } - out << "#define TARGET_MOBILE\n"; break; case ShaderModel::DESKTOP: if (mTargetLanguage == TargetLanguage::SPIRV || @@ -85,28 +84,45 @@ utils::io::sstream& CodeGenerator::generateProlog(utils::io::sstream& out, Shade << ") in;\n\n"; } - if (mTargetApi == TargetApi::VULKAN) { - out << "#define TARGET_VULKAN_ENVIRONMENT\n"; - } - if (mTargetApi == TargetApi::METAL) { - out << "#define TARGET_METAL_ENVIRONMENT\n"; - } - if (mTargetApi == TargetApi::OPENGL && mShaderModel == ShaderModel::MOBILE) { - out << "#define TARGET_GLES_ENVIRONMENT\n"; - } - if (mTargetApi == TargetApi::OPENGL && mShaderModel == ShaderModel::DESKTOP) { - out << "#define TARGET_GL_ENVIRONMENT\n"; + switch (mShaderModel) { + case ShaderModel::MOBILE: + out << "#define TARGET_MOBILE\n"; + break; + case ShaderModel::DESKTOP: + break; } - out << '\n'; - if (mTargetLanguage == TargetLanguage::SPIRV) { - out << "#define FILAMENT_VULKAN_SEMANTICS\n"; - } - if (mTargetLanguage == TargetLanguage::GLSL) { - out << "#define FILAMENT_OPENGL_SEMANTICS\n"; + switch (mTargetApi) { + case TargetApi::OPENGL: + switch (mShaderModel) { + case ShaderModel::MOBILE: + out << "#define TARGET_GLES_ENVIRONMENT\n"; + break; + case ShaderModel::DESKTOP: + out << "#define TARGET_GL_ENVIRONMENT\n"; + break; + } + break; + case TargetApi::VULKAN: + out << "#define TARGET_VULKAN_ENVIRONMENT\n"; + break; + case TargetApi::METAL: + out << "#define TARGET_METAL_ENVIRONMENT\n"; + break; + case TargetApi::ALL: + // invalid should never happen + break; + } + + switch (mTargetLanguage) { + case TargetLanguage::GLSL: + out << "#define FILAMENT_OPENGL_SEMANTICS\n"; + break; + case TargetLanguage::SPIRV: + out << "#define FILAMENT_VULKAN_SEMANTICS\n"; + break; } - out << '\n'; if (mTargetApi == TargetApi::VULKAN || mTargetApi == TargetApi::METAL || (mTargetApi == TargetApi::OPENGL && mShaderModel == ShaderModel::DESKTOP) || @@ -114,7 +130,34 @@ utils::io::sstream& CodeGenerator::generateProlog(utils::io::sstream& out, Shade out << "#define FILAMENT_HAS_FEATURE_TEXTURE_GATHER\n"; } - Precision defaultPrecision = getDefaultPrecision(stage); + if (stage == ShaderStage::VERTEX) { + CodeGenerator::generateDefine(out, "FLIP_UV_ATTRIBUTE", material.flipUV); + CodeGenerator::generateDefine(out, "LEGACY_MORPHING", material.useLegacyMorphing); + } + + if (stage == ShaderStage::VERTEX) { + generateDefine(out, "VARYING", "out"); + } else if (stage == ShaderStage::FRAGMENT) { + generateDefine(out, "VARYING", "in"); + } + + auto getShadingDefine = [](Shading shading) -> const char* { + switch (shading) { + case Shading::LIT: return "SHADING_MODEL_LIT"; + case Shading::UNLIT: return "SHADING_MODEL_UNLIT"; + case Shading::SUBSURFACE: return "SHADING_MODEL_SUBSURFACE"; + case Shading::CLOTH: return "SHADING_MODEL_CLOTH"; + case Shading::SPECULAR_GLOSSINESS: return "SHADING_MODEL_SPECULAR_GLOSSINESS"; + } + }; + + CodeGenerator::generateDefine(out, getShadingDefine(material.shading), true); + + generateQualityDefine(out, material.quality); + + // precision qualifiers + out << '\n'; + Precision const defaultPrecision = getDefaultPrecision(stage); const char* precision = getPrecisionQualifier(defaultPrecision); out << "precision " << precision << " float;\n"; out << "precision " << precision << " int;\n"; @@ -146,11 +189,6 @@ utils::io::sstream& CodeGenerator::generateProlog(utils::io::sstream& out, Shade out << '\n'; out << SHADERS_COMMON_DEFINES_GLSL_DATA; - if (stage != ShaderStage::COMPUTE) { - out << '\n'; - out << SHADERS_COMMON_TYPES_GLSL_DATA; - } - out << "\n"; return out; } @@ -159,25 +197,24 @@ Precision CodeGenerator::getDefaultPrecision(ShaderStage stage) const { switch (stage) { case ShaderStage::VERTEX: return Precision::HIGH; - break; case ShaderStage::FRAGMENT: - if (mShaderModel < ShaderModel::DESKTOP) { - return Precision::MEDIUM; - } else { - return Precision::HIGH; + switch (mShaderModel) { + case ShaderModel::MOBILE: + return Precision::MEDIUM; + case ShaderModel::DESKTOP: + return Precision::HIGH; } - break; case ShaderStage::COMPUTE: return Precision::HIGH; - break; } } Precision CodeGenerator::getDefaultUniformPrecision() const { - if (mShaderModel < ShaderModel::DESKTOP) { - return Precision::MEDIUM; - } else { - return Precision::HIGH; + switch (mShaderModel) { + case ShaderModel::MOBILE: + return Precision::MEDIUM; + case ShaderModel::DESKTOP: + return Precision::HIGH; } } @@ -186,6 +223,23 @@ io::sstream& CodeGenerator::generateEpilog(io::sstream& out) { return out; } +io::sstream& CodeGenerator::generateCommonTypes(io::sstream& out, ShaderStage stage) { + out << '\n'; + switch (stage) { + case ShaderStage::VERTEX: + out << '\n'; + out << SHADERS_COMMON_TYPES_GLSL_DATA; + break; + case ShaderStage::FRAGMENT: + out << '\n'; + out << SHADERS_COMMON_TYPES_GLSL_DATA; + break; + case ShaderStage::COMPUTE: + break; + } + return out; +} + io::sstream& CodeGenerator::generateShaderMain(io::sstream& out, ShaderStage stage) { switch (stage) { case ShaderStage::VERTEX: @@ -210,15 +264,15 @@ io::sstream& CodeGenerator::generatePostProcessMain(io::sstream& out, ShaderStag return out; } -io::sstream& CodeGenerator::generateVariable(io::sstream& out, ShaderStage type, +io::sstream& CodeGenerator::generateVariable(io::sstream& out, ShaderStage stage, const CString& name, size_t index) { if (!name.empty()) { - if (type == ShaderStage::VERTEX) { + if (stage == ShaderStage::VERTEX) { out << "\n#define VARIABLE_CUSTOM" << index << " " << name.c_str() << "\n"; out << "\n#define VARIABLE_CUSTOM_AT" << index << " variable_" << name.c_str() << "\n"; out << "LAYOUT_LOCATION(" << index << ") out vec4 variable_" << name.c_str() << ";\n"; - } else if (type == ShaderStage::FRAGMENT) { + } else if (stage == ShaderStage::FRAGMENT) { out << "\nLAYOUT_LOCATION(" << index << ") in highp vec4 variable_" << name.c_str() << ";\n"; } } @@ -231,26 +285,27 @@ io::sstream& CodeGenerator::generateShaderInputs(io::sstream& out, ShaderStage t const char* shading = getInterpolationQualifier(interpolation); out << "#define SHADING_INTERPOLATION " << shading << "\n"; - bool hasTangents = attributes.test(VertexAttribute::TANGENTS); + bool const hasTangents = attributes.test(VertexAttribute::TANGENTS); generateDefine(out, "HAS_ATTRIBUTE_TANGENTS", hasTangents); - bool hasColor = attributes.test(VertexAttribute::COLOR); + bool const hasColor = attributes.test(VertexAttribute::COLOR); generateDefine(out, "HAS_ATTRIBUTE_COLOR", hasColor); - bool hasUV0 = attributes.test(VertexAttribute::UV0); + bool const hasUV0 = attributes.test(VertexAttribute::UV0); generateDefine(out, "HAS_ATTRIBUTE_UV0", hasUV0); - bool hasUV1 = attributes.test(VertexAttribute::UV1); + bool const hasUV1 = attributes.test(VertexAttribute::UV1); generateDefine(out, "HAS_ATTRIBUTE_UV1", hasUV1); - bool hasBoneIndices = attributes.test(VertexAttribute::BONE_INDICES); + bool const hasBoneIndices = attributes.test(VertexAttribute::BONE_INDICES); generateDefine(out, "HAS_ATTRIBUTE_BONE_INDICES", hasBoneIndices); - bool hasBoneWeights = attributes.test(VertexAttribute::BONE_WEIGHTS); + bool const hasBoneWeights = attributes.test(VertexAttribute::BONE_WEIGHTS); generateDefine(out, "HAS_ATTRIBUTE_BONE_WEIGHTS", hasBoneWeights); - for (int i = 0; i < MAX_CUSTOM_ATTRIBUTES; i++) { - bool hasCustom = attributes.test(VertexAttribute::CUSTOM0 + i); + UTILS_NOUNROLL + for (size_t i = 0; i < MAX_CUSTOM_ATTRIBUTES; i++) { + bool const hasCustom = attributes.test(VertexAttribute::CUSTOM0 + i); if (hasCustom) { generateIndexedDefine(out, "HAS_ATTRIBUTE_CUSTOM", i, 1); } @@ -286,10 +341,6 @@ io::sstream& CodeGenerator::generateShaderInputs(io::sstream& out, ShaderStage t } out << SHADERS_ATTRIBUTES_VS_DATA; - - generateDefine(out, "VARYING", "out"); - } else if (type == ShaderStage::FRAGMENT) { - generateDefine(out, "VARYING", "in"); } out << SHADERS_VARYINGS_GLSL_DATA; return out; @@ -393,8 +444,8 @@ io::sstream& CodeGenerator::generateBufferInterfaceBlock(io::sstream& out, Shade blockName.front() = char(std::toupper((unsigned char)blockName.front())); instanceName.front() = char(std::tolower((unsigned char)instanceName.front())); - Precision uniformPrecision = getDefaultUniformPrecision(); - Precision defaultPrecision = getDefaultPrecision(stage); + Precision const uniformPrecision = getDefaultUniformPrecision(); + Precision const defaultPrecision = getDefaultPrecision(stage); auto metalBufferBindingOffset = 0; switch (uib.getTarget()) { @@ -450,7 +501,7 @@ io::sstream& CodeGenerator::generateBufferInterfaceBlock(io::sstream& out, Shade if (uib.getTarget() == BufferInterfaceBlock::Target::SSBO) { uint8_t qualifiers = uib.getQualifier(); while (qualifiers) { - uint8_t mask = 1u << utils::ctz(unsigned(qualifiers)); + uint8_t const mask = 1u << utils::ctz(unsigned(qualifiers)); switch (BufferInterfaceBlock::Qualifier(qualifiers & mask)) { case BufferInterfaceBlock::Qualifier::COHERENT: out << "coherent "; break; case BufferInterfaceBlock::Qualifier::WRITEONLY: out << "writeonly "; break; @@ -575,7 +626,7 @@ void CodeGenerator::fixupExternalSamplers( for (auto const& info : infos) { if (info.type == SamplerType::SAMPLER_EXTERNAL) { auto name = std::string("sampler2D ") + info.uniformName.c_str(); - size_t index = shader.find(name); + size_t const index = shader.find(name); if (index != std::string::npos) { hasExternalSampler = true; @@ -634,12 +685,12 @@ struct SpecializationConstantFormatter { utils::io::sstream& CodeGenerator::generateSpecializationConstant(utils::io::sstream& out, const char* name, uint32_t id, std::variant value) const { - std::string constantString = std::visit(SpecializationConstantFormatter(), value); + std::string const constantString = std::visit(SpecializationConstantFormatter(), value); static const char* types[] = { "int", "float", "bool" }; if (mTargetLanguage == MaterialBuilderBase::TargetLanguage::SPIRV) { out << "layout (constant_id = " << id << ") const " - << types[value.index()] << " " << name << " = " << constantString << ";\n\n"; + << types[value.index()] << " " << name << " = " << constantString << ";\n"; } else { out << "#ifndef SPIRV_CROSS_CONSTANT_ID_" << id << '\n' << "#define SPIRV_CROSS_CONSTANT_ID_" << id << " " << constantString << '\n' @@ -845,8 +896,7 @@ io::sstream& CodeGenerator::generateShaderUnlit(io::sstream& out, ShaderStage ty return out; } -io::sstream& CodeGenerator::generateShaderReflections(utils::io::sstream& out, ShaderStage type, - filament::Variant variant) { +io::sstream& CodeGenerator::generateShaderReflections(utils::io::sstream& out, ShaderStage type) { if (type == ShaderStage::VERTEX) { } else if (type == ShaderStage::FRAGMENT) { out << SHADERS_COMMON_LIGHTING_FS_DATA; diff --git a/libs/filamat/src/shaders/CodeGenerator.h b/libs/filamat/src/shaders/CodeGenerator.h index 113c55457f..3fbe32ef95 100644 --- a/libs/filamat/src/shaders/CodeGenerator.h +++ b/libs/filamat/src/shaders/CodeGenerator.h @@ -77,6 +77,8 @@ public: static utils::io::sstream& generateEpilog(utils::io::sstream& out); + static utils::io::sstream& generateCommonTypes(utils::io::sstream& out, ShaderStage stage); + // generate common functions for the given shader static utils::io::sstream& generateCommon(utils::io::sstream& out, ShaderStage stage); static utils::io::sstream& generatePostProcessCommon(utils::io::sstream& out, ShaderStage type); @@ -97,11 +99,10 @@ public: filament::Variant variant, bool hasShadowMultiplier); // generate the shader's code for the screen-space reflections - static utils::io::sstream& generateShaderReflections(utils::io::sstream& out, ShaderStage type, - filament::Variant variant); + static utils::io::sstream& generateShaderReflections(utils::io::sstream& out, ShaderStage type); // generate declarations for custom interpolants - static utils::io::sstream& generateVariable(utils::io::sstream& out, ShaderStage type, + static utils::io::sstream& generateVariable(utils::io::sstream& out, ShaderStage stage, const utils::CString& name, size_t index); // generate declarations for non-custom "in" variables diff --git a/libs/filamat/src/shaders/ShaderGenerator.cpp b/libs/filamat/src/shaders/ShaderGenerator.cpp index 406820f3f7..bf3f52344c 100644 --- a/libs/filamat/src/shaders/ShaderGenerator.cpp +++ b/libs/filamat/src/shaders/ShaderGenerator.cpp @@ -36,36 +36,179 @@ using namespace filament; using namespace filament::backend; using namespace utils; -static const char* getShadingDefine(Shading shading) noexcept { - switch (shading) { - case Shading::LIT: return "SHADING_MODEL_LIT"; - case Shading::UNLIT: return "SHADING_MODEL_UNLIT"; - case Shading::SUBSURFACE: return "SHADING_MODEL_SUBSURFACE"; - case Shading::CLOTH: return "SHADING_MODEL_CLOTH"; - case Shading::SPECULAR_GLOSSINESS: return "SHADING_MODEL_SPECULAR_GLOSSINESS"; +void ShaderGenerator::generateSurfaceMaterialVariantDefines(utils::io::sstream& out, + ShaderStage stage, + MaterialInfo const& material, filament::Variant variant) noexcept { + + bool const litVariants = material.isLit || material.hasShadowMultiplier; + + CodeGenerator::generateDefine(out, "VARIANT_HAS_DIRECTIONAL_LIGHTING", + litVariants && variant.hasDirectionalLighting()); + CodeGenerator::generateDefine(out, "VARIANT_HAS_DYNAMIC_LIGHTING", + litVariants && variant.hasDynamicLighting()); + CodeGenerator::generateDefine(out, "VARIANT_HAS_SHADOWING", + litVariants && filament::Variant::isShadowReceiverVariant(variant)); + CodeGenerator::generateDefine(out, "VARIANT_HAS_VSM", + filament::Variant::isVSMVariant(variant)); + + switch (stage) { + case ShaderStage::VERTEX: + CodeGenerator::generateDefine(out, "VARIANT_HAS_SKINNING_OR_MORPHING", + variant.hasSkinningOrMorphing()); + break; + case ShaderStage::FRAGMENT: + CodeGenerator::generateDefine(out, "VARIANT_HAS_FOG", + filament::Variant::isFogVariant(variant)); + CodeGenerator::generateDefine(out, "VARIANT_HAS_PICKING", + filament::Variant::isPickingVariant(variant)); + CodeGenerator::generateDefine(out, "VARIANT_HAS_SSR", + filament::Variant::isSSRVariant(variant)); + break; + case ShaderStage::COMPUTE: + break; + } + + out << '\n'; + CodeGenerator::generateDefine(out, "MATERIAL_HAS_SHADOW_MULTIPLIER", + material.hasShadowMultiplier); + + CodeGenerator::generateDefine(out, "MATERIAL_HAS_INSTANCES", material.instanced); + + CodeGenerator::generateDefine(out, "MATERIAL_HAS_VERTEX_DOMAIN_DEVICE_JITTERED", + material.vertexDomainDeviceJittered); + + CodeGenerator::generateDefine(out, "MATERIAL_HAS_TRANSPARENT_SHADOW", + material.hasTransparentShadow); + + if (stage == ShaderStage::FRAGMENT) { + // We only support both screen-space refractions and reflections at the same time. + // And the MATERIAL_HAS_REFRACTION/MATERIAL_HAS_REFLECTIONS defines signify if + // refraction/reflections are supported by the material. + + CodeGenerator::generateDefine(out, "MATERIAL_HAS_REFRACTION", + material.refractionMode != RefractionMode::NONE); + if (material.refractionMode != RefractionMode::NONE) { + CodeGenerator::generateDefine(out, "REFRACTION_MODE_CUBEMAP", + uint32_t(RefractionMode::CUBEMAP)); + CodeGenerator::generateDefine(out, "REFRACTION_MODE_SCREEN_SPACE", + uint32_t(RefractionMode::SCREEN_SPACE)); + switch (material.refractionMode) { + case RefractionMode::NONE: + // can't be here + break; + case RefractionMode::CUBEMAP: + CodeGenerator::generateDefine(out, "REFRACTION_MODE", + "REFRACTION_MODE_CUBEMAP"); + break; + case RefractionMode::SCREEN_SPACE: + CodeGenerator::generateDefine(out, "REFRACTION_MODE", + "REFRACTION_MODE_SCREEN_SPACE"); + break; + } + CodeGenerator::generateDefine(out, "REFRACTION_TYPE_SOLID", + uint32_t(RefractionType::SOLID)); + CodeGenerator::generateDefine(out, "REFRACTION_TYPE_THIN", + uint32_t(RefractionType::THIN)); + switch (material.refractionType) { + case RefractionType::SOLID: + CodeGenerator::generateDefine(out, "REFRACTION_TYPE", "REFRACTION_TYPE_SOLID"); + break; + case RefractionType::THIN: + CodeGenerator::generateDefine(out, "REFRACTION_TYPE", "REFRACTION_TYPE_THIN"); + break; + } + } + CodeGenerator::generateDefine(out, "MATERIAL_HAS_REFLECTIONS", + material.reflectionMode == ReflectionMode::SCREEN_SPACE); + + CodeGenerator::generateDefine(out, "MATERIAL_HAS_DOUBLE_SIDED_CAPABILITY", + material.hasDoubleSidedCapability); + + CodeGenerator::generateDefine(out, "MATERIAL_HAS_CUSTOM_SURFACE_SHADING", + material.hasCustomSurfaceShading); + + out << '\n'; + switch (material.blendingMode) { + case BlendingMode::OPAQUE: + CodeGenerator::generateDefine(out, "BLEND_MODE_OPAQUE", true); + break; + case BlendingMode::TRANSPARENT: + CodeGenerator::generateDefine(out, "BLEND_MODE_TRANSPARENT", true); + break; + case BlendingMode::ADD: + CodeGenerator::generateDefine(out, "BLEND_MODE_ADD", true); + break; + case BlendingMode::MASKED: + CodeGenerator::generateDefine(out, "BLEND_MODE_MASKED", true); + break; + case BlendingMode::FADE: + // Fade is a special case of transparent + CodeGenerator::generateDefine(out, "BLEND_MODE_TRANSPARENT", true); + CodeGenerator::generateDefine(out, "BLEND_MODE_FADE", true); + break; + case BlendingMode::MULTIPLY: + CodeGenerator::generateDefine(out, "BLEND_MODE_MULTIPLY", true); + break; + case BlendingMode::SCREEN: + CodeGenerator::generateDefine(out, "BLEND_MODE_SCREEN", true); + break; + } + + switch (material.postLightingBlendingMode) { + case BlendingMode::OPAQUE: + CodeGenerator::generateDefine(out, "POST_LIGHTING_BLEND_MODE_OPAQUE", true); + break; + case BlendingMode::TRANSPARENT: + CodeGenerator::generateDefine(out, "POST_LIGHTING_BLEND_MODE_TRANSPARENT", true); + break; + case BlendingMode::ADD: + CodeGenerator::generateDefine(out, "POST_LIGHTING_BLEND_MODE_ADD", true); + break; + case BlendingMode::MULTIPLY: + CodeGenerator::generateDefine(out, "POST_LIGHTING_BLEND_MODE_MULTIPLY", true); + break; + case BlendingMode::SCREEN: + CodeGenerator::generateDefine(out, "POST_LIGHTING_BLEND_MODE_SCREEN", true); + break; + default: + break; + } + + out << '\n'; + CodeGenerator::generateDefine(out, "GEOMETRIC_SPECULAR_AA", + material.specularAntiAliasing && material.isLit); + + CodeGenerator::generateDefine(out, "CLEAR_COAT_IOR_CHANGE", + material.clearCoatIorChange); } } -static void generateMaterialDefines(io::sstream& os, MaterialBuilder::PropertyList const properties, +void ShaderGenerator::generateSurfaceMaterialVariantProperties(io::sstream& out, + MaterialBuilder::PropertyList const properties, const MaterialBuilder::PreprocessorDefineList& defines) noexcept { + + UTILS_NOUNROLL for (size_t i = 0; i < MaterialBuilder::MATERIAL_PROPERTIES_COUNT; i++) { - CodeGenerator::generateMaterialProperty(os, static_cast(i), properties[i]); + CodeGenerator::generateMaterialProperty(out, + static_cast(i), properties[i]); } + // synthetic defines - bool hasTBN = + bool const hasTBN = properties[static_cast(MaterialBuilder::Property::ANISOTROPY)] || properties[static_cast(MaterialBuilder::Property::NORMAL)] || properties[static_cast(MaterialBuilder::Property::BENT_NORMAL)] || properties[static_cast(MaterialBuilder::Property::CLEAR_COAT_NORMAL)]; - CodeGenerator::generateDefine(os, "MATERIAL_NEEDS_TBN", hasTBN); + + CodeGenerator::generateDefine(out, "MATERIAL_NEEDS_TBN", hasTBN); // Additional, user-provided defines. for (const auto& define : defines) { - CodeGenerator::generateDefine(os, define.name.c_str(), define.value.c_str()); + CodeGenerator::generateDefine(out, define.name.c_str(), define.value.c_str()); } } -static void generateVertexDomain(io::sstream& vs, VertexDomain domain) noexcept { +void ShaderGenerator::generateVertexDomainDefines(io::sstream& vs, VertexDomain domain) noexcept { switch (domain) { case VertexDomain::OBJECT: CodeGenerator::generateDefine(vs, "VERTEX_DOMAIN_OBJECT", true); @@ -82,37 +225,30 @@ static void generateVertexDomain(io::sstream& vs, VertexDomain domain) noexcept } } -static void generatePostProcessMaterialVariantDefines(io::sstream& shader, +void ShaderGenerator::generatePostProcessMaterialVariantDefines(io::sstream& out, PostProcessVariant variant) noexcept { switch (variant) { case PostProcessVariant::OPAQUE: - CodeGenerator::generateDefine(shader, "POST_PROCESS_OPAQUE", 1u); + CodeGenerator::generateDefine(out, "POST_PROCESS_OPAQUE", 1u); break; case PostProcessVariant::TRANSLUCENT: - CodeGenerator::generateDefine(shader, "POST_PROCESS_OPAQUE", 0u); + CodeGenerator::generateDefine(out, "POST_PROCESS_OPAQUE", 0u); break; } } -static size_t countLines(const char* s) noexcept { - size_t lines = 0; - size_t i = 0; - while (s[i] != 0) { - if (s[i++] == '\n') lines++; - } - return lines; -} - -static size_t countLines(const CString& s) noexcept { - size_t lines = 0; - for (char i : s) { - if (i == '\n') lines++; - } - return lines; -} - -static void appendShader(io::sstream& ss, +void ShaderGenerator::appendShader(io::sstream& ss, const CString& shader, size_t lineOffset) noexcept { + + auto countLines = [](const char* s) -> size_t { + size_t lines = 0; + size_t i = 0; + while (s[i]) { + if (s[i++] == '\n') lines++; + } + return lines; + }; + if (!shader.empty()) { size_t lines = countLines(ss.c_str()); ss << "#line " << lineOffset + 1 << '\n'; @@ -122,16 +258,16 @@ static void appendShader(io::sstream& ss, lines++; } // + 2 to account for the #line directives we just added - ss << "#line " << lines + countLines(shader) + 2 << "\n"; + ss << "#line " << lines + countLines(shader.c_str()) + 2 << "\n"; } } -static void generateUserSpecConstants( - const CodeGenerator& cg, io::sstream& fs, MaterialBuilder::ConstantList constants) { +void ShaderGenerator::generateUserSpecConstants( + const CodeGenerator& cg, io::sstream& fs, MaterialBuilder::ConstantList const& constants) { // Constants 0 to CONFIG_MAX_RESERVED_SPEC_CONSTANTS - 1 are reserved by Filament. size_t index = CONFIG_MAX_RESERVED_SPEC_CONSTANTS; for (const auto& constant : constants) { - std::string fullName = std::string("materialConstants_") + constant.name.c_str(); + std::string const fullName = std::string("materialConstants_") + constant.name.c_str(); switch (constant.type) { case ConstantType::INT: cg.generateSpecializationConstant( @@ -149,6 +285,7 @@ static void generateUserSpecConstants( } } +// ------------------------------------------------------------------------------------------------ ShaderGenerator::ShaderGenerator( MaterialBuilder::PropertyList const& properties, @@ -215,6 +352,7 @@ std::string ShaderGenerator::createVertexProgram(ShaderModel shaderModel, MaterialInfo const& material, const filament::Variant variant, Interpolation interpolation, VertexDomain vertexDomain) const noexcept { + assert_invariant(filament::Variant::isValid(variant)); assert_invariant(mMaterialDomain != MaterialBuilder::MaterialDomain::COMPUTE); if (mMaterialDomain == MaterialBuilder::MaterialDomain::POST_PROCESS) { @@ -225,22 +363,11 @@ std::string ShaderGenerator::createVertexProgram(ShaderModel shaderModel, io::sstream vs; const CodeGenerator cg(shaderModel, targetApi, targetLanguage, material.featureLevel); - const bool lit = material.isLit; cg.generateProlog(vs, ShaderStage::VERTEX, material); generateUserSpecConstants(cg, vs, mConstants); - cg.generateQualityDefine(vs, material.quality); - - CodeGenerator::generateDefine(vs, "FLIP_UV_ATTRIBUTE", material.flipUV); - - CodeGenerator::generateDefine(vs, "LEGACY_MORPHING", material.useLegacyMorphing); - - const bool litVariants = lit || material.hasShadowMultiplier; - - assert_invariant(filament::Variant::isValid(variant)); - // note: even if the user vertex shader is empty, we can't use the "optimized" version if // we're in masked mode because fragment shader needs the color varyings const bool useOptimizedDepthVertexShader = @@ -258,31 +385,9 @@ std::string ShaderGenerator::createVertexProgram(ShaderModel shaderModel, CodeGenerator::generateDefine(vs, "USE_OPTIMIZED_DEPTH_VERTEX_SHADER", useOptimizedDepthVertexShader); - // material defines - CodeGenerator::generateDefine(vs, "MATERIAL_HAS_SHADOW_MULTIPLIER", - material.hasShadowMultiplier); + generateSurfaceMaterialVariantDefines(vs, ShaderStage::VERTEX, material, variant); - CodeGenerator::generateDefine(vs, "MATERIAL_HAS_INSTANCES", material.instanced); - - CodeGenerator::generateDefine(vs, "MATERIAL_HAS_VERTEX_DOMAIN_DEVICE_JITTERED", - material.vertexDomainDeviceJittered); - - CodeGenerator::generateDefine(vs, "MATERIAL_HAS_TRANSPARENT_SHADOW", - material.hasTransparentShadow); - - CodeGenerator::generateDefine(vs, "VARIANT_HAS_DIRECTIONAL_LIGHTING", - litVariants && variant.hasDirectionalLighting()); - CodeGenerator::generateDefine(vs, "VARIANT_HAS_DYNAMIC_LIGHTING", - litVariants && variant.hasDynamicLighting()); - CodeGenerator::generateDefine(vs, "VARIANT_HAS_SHADOWING", - litVariants && filament::Variant::isShadowReceiverVariant(variant)); - CodeGenerator::generateDefine(vs, "VARIANT_HAS_SKINNING_OR_MORPHING", - variant.hasSkinningOrMorphing()); - CodeGenerator::generateDefine(vs, "VARIANT_HAS_VSM", - filament::Variant::isVSMVariant(variant)); - - CodeGenerator::generateDefine(vs, getShadingDefine(material.shading), true); - generateMaterialDefines(vs, mProperties, mDefines); + generateSurfaceMaterialVariantProperties(vs, mProperties, mDefines); AttributeBitset attributes = material.requiredAttributes; if (variant.hasSkinningOrMorphing()) { @@ -301,6 +406,8 @@ std::string ShaderGenerator::createVertexProgram(ShaderModel shaderModel, } CodeGenerator::generateShaderInputs(vs, ShaderStage::VERTEX, attributes, interpolation); + CodeGenerator::generateCommonTypes(vs, ShaderStage::VERTEX); + // custom material variables size_t variableIndex = 0; for (const auto& variable : mVariables) { @@ -308,31 +415,40 @@ std::string ShaderGenerator::createVertexProgram(ShaderModel shaderModel, } // materials defines - generateVertexDomain(vs, vertexDomain); + generateVertexDomainDefines(vs, vertexDomain); // uniforms cg.generateUniforms(vs, ShaderStage::VERTEX, UniformBindingPoints::PER_VIEW, UibGenerator::getPerViewUib()); + cg.generateUniforms(vs, ShaderStage::VERTEX, UniformBindingPoints::PER_RENDERABLE, UibGenerator::getPerRenderableUib()); + + const bool litVariants = material.isLit || material.hasShadowMultiplier; if (litVariants && filament::Variant::isShadowReceiverVariant(variant)) { cg.generateUniforms(vs, ShaderStage::FRAGMENT, UniformBindingPoints::SHADOW, UibGenerator::getShadowUib()); } + if (variant.hasSkinningOrMorphing()) { cg.generateUniforms(vs, ShaderStage::VERTEX, UniformBindingPoints::PER_RENDERABLE_BONES, UibGenerator::getPerRenderableBonesUib()); + cg.generateUniforms(vs, ShaderStage::VERTEX, UniformBindingPoints::PER_RENDERABLE_MORPHING, UibGenerator::getPerRenderableMorphingUib()); + cg.generateSamplers(vs, SamplerBindingPoints::PER_RENDERABLE_MORPHING, material.samplerBindings.getBlockOffset(SamplerBindingPoints::PER_RENDERABLE_MORPHING), SibGenerator::getPerRenderPrimitiveMorphingSib(variant)); } + cg.generateUniforms(vs, ShaderStage::VERTEX, UniformBindingPoints::PER_MATERIAL_INSTANCE, material.uib); + CodeGenerator::generateSeparator(vs); + // TODO: should we generate per-view SIB in the vertex shader? cg.generateSamplers(vs, SamplerBindingPoints::PER_MATERIAL_INSTANCE, material.samplerBindings.getBlockOffset(SamplerBindingPoints::PER_MATERIAL_INSTANCE), @@ -357,6 +473,7 @@ std::string ShaderGenerator::createFragmentProgram(ShaderModel shaderModel, MaterialInfo const& material, const filament::Variant variant, Interpolation interpolation) const noexcept { + assert_invariant(filament::Variant::isValid(variant)); assert_invariant(mMaterialDomain != MaterialBuilder::MaterialDomain::COMPUTE); if (mMaterialDomain == MaterialBuilder::MaterialDomain::POST_PROCESS) { @@ -365,146 +482,30 @@ std::string ShaderGenerator::createFragmentProgram(ShaderModel shaderModel, } const CodeGenerator cg(shaderModel, targetApi, targetLanguage, material.featureLevel); - const bool lit = material.isLit; io::sstream fs; cg.generateProlog(fs, ShaderStage::FRAGMENT, material); generateUserSpecConstants(cg, fs, mConstants); - cg.generateQualityDefine(fs, material.quality); - - CodeGenerator::generateDefine(fs, "GEOMETRIC_SPECULAR_AA", material.specularAntiAliasing && lit); - - CodeGenerator::generateDefine(fs, "CLEAR_COAT_IOR_CHANGE", material.clearCoatIorChange); + generateSurfaceMaterialVariantDefines(fs, ShaderStage::FRAGMENT, material, variant); auto defaultSpecularAO = shaderModel == ShaderModel::MOBILE ? - SpecularAmbientOcclusion::NONE : SpecularAmbientOcclusion::SIMPLE; + SpecularAmbientOcclusion::NONE : SpecularAmbientOcclusion::SIMPLE; auto specularAO = material.specularAOSet ? material.specularAO : defaultSpecularAO; CodeGenerator::generateDefine(fs, "SPECULAR_AMBIENT_OCCLUSION", uint32_t(specularAO)); - // We only support both screen-space refractions and reflections at the same time. - // And the MATERIAL_HAS_REFRACTION/MATERIAL_HAS_REFLECTIONS defines signify if refraction/reflections are supported by - // the material. - - CodeGenerator::generateDefine(fs, "MATERIAL_HAS_REFRACTION", material.refractionMode != RefractionMode::NONE); - if (material.refractionMode != RefractionMode::NONE) { - CodeGenerator::generateDefine(fs, "REFRACTION_MODE_CUBEMAP", uint32_t(RefractionMode::CUBEMAP)); - CodeGenerator::generateDefine(fs, "REFRACTION_MODE_SCREEN_SPACE", uint32_t(RefractionMode::SCREEN_SPACE)); - switch (material.refractionMode) { - case RefractionMode::NONE: - // can't be here - break; - case RefractionMode::CUBEMAP: - CodeGenerator::generateDefine(fs, "REFRACTION_MODE", "REFRACTION_MODE_CUBEMAP"); - break; - case RefractionMode::SCREEN_SPACE: - CodeGenerator::generateDefine(fs, "REFRACTION_MODE", "REFRACTION_MODE_SCREEN_SPACE"); - break; - } - CodeGenerator::generateDefine(fs, "REFRACTION_TYPE_SOLID", uint32_t(RefractionType::SOLID)); - CodeGenerator::generateDefine(fs, "REFRACTION_TYPE_THIN", uint32_t(RefractionType::THIN)); - switch (material.refractionType) { - case RefractionType::SOLID: - CodeGenerator::generateDefine(fs, "REFRACTION_TYPE", "REFRACTION_TYPE_SOLID"); - break; - case RefractionType::THIN: - CodeGenerator::generateDefine(fs, "REFRACTION_TYPE", "REFRACTION_TYPE_THIN"); - break; - } - } - - CodeGenerator::generateDefine(fs, "MATERIAL_HAS_REFLECTIONS", - material.reflectionMode == ReflectionMode::SCREEN_SPACE); - - bool multiBounceAO = material.multiBounceAOSet ? - material.multiBounceAO : shaderModel == ShaderModel::DESKTOP; + bool const multiBounceAO = material.multiBounceAOSet ? + material.multiBounceAO : shaderModel == ShaderModel::DESKTOP; CodeGenerator::generateDefine(fs, "MULTI_BOUNCE_AMBIENT_OCCLUSION", multiBounceAO ? 1u : 0u); - assert_invariant(filament::Variant::isValid(variant)); + generateSurfaceMaterialVariantProperties(fs, mProperties, mDefines); - // lighting variants - bool litVariants = lit || material.hasShadowMultiplier; - // material defines - CodeGenerator::generateDefine(fs, "MATERIAL_HAS_SHADOW_MULTIPLIER", - material.hasShadowMultiplier); + CodeGenerator::generateShaderInputs(fs, ShaderStage::FRAGMENT, + material.requiredAttributes, interpolation); - CodeGenerator::generateDefine(fs, "MATERIAL_HAS_INSTANCES", material.instanced); - - CodeGenerator::generateDefine(fs, "MATERIAL_HAS_VERTEX_DOMAIN_DEVICE_JITTERED", - material.vertexDomainDeviceJittered); - - CodeGenerator::generateDefine(fs, "MATERIAL_HAS_TRANSPARENT_SHADOW", - material.hasTransparentShadow); - - CodeGenerator::generateDefine(fs, "VARIANT_HAS_DIRECTIONAL_LIGHTING", - litVariants && variant.hasDirectionalLighting()); - CodeGenerator::generateDefine(fs, "VARIANT_HAS_DYNAMIC_LIGHTING", - litVariants && variant.hasDynamicLighting()); - CodeGenerator::generateDefine(fs, "VARIANT_HAS_SHADOWING", - litVariants && filament::Variant::isShadowReceiverVariant(variant)); - CodeGenerator::generateDefine(fs, "VARIANT_HAS_FOG", - filament::Variant::isFogVariant(variant)); - CodeGenerator::generateDefine(fs, "VARIANT_HAS_PICKING", - filament::Variant::isPickingVariant(variant)); - CodeGenerator::generateDefine(fs, "VARIANT_HAS_VSM", - filament::Variant::isVSMVariant(variant)); - CodeGenerator::generateDefine(fs, "VARIANT_HAS_SSR", - filament::Variant::isSSRVariant(variant)); - - CodeGenerator::generateDefine(fs, "MATERIAL_HAS_DOUBLE_SIDED_CAPABILITY", - material.hasDoubleSidedCapability); - switch (material.blendingMode) { - case BlendingMode::OPAQUE: - CodeGenerator::generateDefine(fs, "BLEND_MODE_OPAQUE", true); - break; - case BlendingMode::TRANSPARENT: - CodeGenerator::generateDefine(fs, "BLEND_MODE_TRANSPARENT", true); - break; - case BlendingMode::ADD: - CodeGenerator::generateDefine(fs, "BLEND_MODE_ADD", true); - break; - case BlendingMode::MASKED: - CodeGenerator::generateDefine(fs, "BLEND_MODE_MASKED", true); - break; - case BlendingMode::FADE: - // Fade is a special case of transparent - CodeGenerator::generateDefine(fs, "BLEND_MODE_TRANSPARENT", true); - CodeGenerator::generateDefine(fs, "BLEND_MODE_FADE", true); - break; - case BlendingMode::MULTIPLY: - CodeGenerator::generateDefine(fs, "BLEND_MODE_MULTIPLY", true); - break; - case BlendingMode::SCREEN: - CodeGenerator::generateDefine(fs, "BLEND_MODE_SCREEN", true); - break; - } - switch (material.postLightingBlendingMode) { - case BlendingMode::OPAQUE: - CodeGenerator::generateDefine(fs, "POST_LIGHTING_BLEND_MODE_OPAQUE", true); - break; - case BlendingMode::TRANSPARENT: - CodeGenerator::generateDefine(fs, "POST_LIGHTING_BLEND_MODE_TRANSPARENT", true); - break; - case BlendingMode::ADD: - CodeGenerator::generateDefine(fs, "POST_LIGHTING_BLEND_MODE_ADD", true); - break; - case BlendingMode::MULTIPLY: - CodeGenerator::generateDefine(fs, "POST_LIGHTING_BLEND_MODE_MULTIPLY", true); - break; - case BlendingMode::SCREEN: - CodeGenerator::generateDefine(fs, "POST_LIGHTING_BLEND_MODE_SCREEN", true); - break; - default: - break; - } - CodeGenerator::generateDefine(fs, getShadingDefine(material.shading), true); - generateMaterialDefines(fs, mProperties, mDefines); - - CodeGenerator::generateDefine(fs, "MATERIAL_HAS_CUSTOM_SURFACE_SHADING", material.hasCustomSurfaceShading); - - CodeGenerator::generateShaderInputs(fs, ShaderStage::FRAGMENT, material.requiredAttributes, interpolation); + CodeGenerator::generateCommonTypes(fs, ShaderStage::FRAGMENT); // custom material variables size_t variableIndex = 0; @@ -515,22 +516,35 @@ std::string ShaderGenerator::createFragmentProgram(ShaderModel shaderModel, // uniforms and samplers cg.generateUniforms(fs, ShaderStage::FRAGMENT, UniformBindingPoints::PER_VIEW, UibGenerator::getPerViewUib()); + cg.generateUniforms(fs, ShaderStage::FRAGMENT, UniformBindingPoints::PER_RENDERABLE, UibGenerator::getPerRenderableUib()); - cg.generateUniforms(fs, ShaderStage::FRAGMENT, - UniformBindingPoints::LIGHTS, UibGenerator::getLightsUib()); + + if (variant.hasDynamicLighting()) { + cg.generateUniforms(fs, ShaderStage::FRAGMENT, + UniformBindingPoints::LIGHTS, UibGenerator::getLightsUib()); + } + + bool const litVariants = material.isLit || material.hasShadowMultiplier; if (litVariants && filament::Variant::isShadowReceiverVariant(variant)) { cg.generateUniforms(fs, ShaderStage::FRAGMENT, UniformBindingPoints::SHADOW, UibGenerator::getShadowUib()); } - cg.generateUniforms(fs, ShaderStage::FRAGMENT, - UniformBindingPoints::FROXEL_RECORDS, UibGenerator::getFroxelRecordUib()); + + if (variant.hasDynamicLighting()) { + cg.generateUniforms(fs, ShaderStage::FRAGMENT, + UniformBindingPoints::FROXEL_RECORDS, UibGenerator::getFroxelRecordUib()); + } + cg.generateUniforms(fs, ShaderStage::FRAGMENT, UniformBindingPoints::PER_MATERIAL_INSTANCE, material.uib); + CodeGenerator::generateSeparator(fs); + cg.generateSamplers(fs, SamplerBindingPoints::PER_VIEW, material.samplerBindings.getBlockOffset(SamplerBindingPoints::PER_VIEW), SibGenerator::getPerViewSib(variant)); + cg.generateSamplers(fs, SamplerBindingPoints::PER_MATERIAL_INSTANCE, material.samplerBindings.getBlockOffset(SamplerBindingPoints::PER_MATERIAL_INSTANCE), material.sib); @@ -551,13 +565,13 @@ std::string ShaderGenerator::createFragmentProgram(ShaderModel shaderModel, if (material.blendingMode == BlendingMode::MASKED || material.hasTransparentShadow) { appendShader(fs, mMaterialFragmentCode, mMaterialLineOffset); } - // these variants are special and are treated as DEPTH variants. Filament will never + // These variants are special and are treated as DEPTH variants. Filament will never // request that variant for the color pass. CodeGenerator::generateDepthShaderMain(fs, ShaderStage::FRAGMENT); } else { appendShader(fs, mMaterialFragmentCode, mMaterialLineOffset); if (filament::Variant::isSSRVariant(variant)) { - CodeGenerator::generateShaderReflections(fs, ShaderStage::FRAGMENT, variant); + CodeGenerator::generateShaderReflections(fs, ShaderStage::FRAGMENT); } else if (material.isLit) { CodeGenerator::generateShaderLit(fs, ShaderStage::FRAGMENT, variant, material.shading,material.hasCustomSurfaceShading); @@ -576,7 +590,7 @@ std::string ShaderGenerator::createFragmentProgram(ShaderModel shaderModel, std::string ShaderGenerator::createComputeProgram(filament::backend::ShaderModel shaderModel, MaterialBuilder::TargetApi targetApi, MaterialBuilder::TargetLanguage targetLanguage, - MaterialInfo const& material, filament::Variant variant) const noexcept { + MaterialInfo const& material) const noexcept { assert_invariant(mMaterialDomain == MaterialBuilder::MaterialDomain::COMPUTE); assert_invariant(material.featureLevel >= FeatureLevel::FEATURE_LEVEL_2); const CodeGenerator cg(shaderModel, targetApi, targetLanguage, material.featureLevel); @@ -586,7 +600,7 @@ std::string ShaderGenerator::createComputeProgram(filament::backend::ShaderModel generateUserSpecConstants(cg, s, mConstants); - cg.generateQualityDefine(s, material.quality); + CodeGenerator::generateCommonTypes(s, ShaderStage::COMPUTE); cg.generateUniforms(s, ShaderStage::COMPUTE, UniformBindingPoints::PER_VIEW, UibGenerator::getPerViewUib()); @@ -622,8 +636,6 @@ std::string ShaderGenerator::createPostProcessVertexProgram(ShaderModel sm, io::sstream vs; cg.generateProlog(vs, ShaderStage::VERTEX, material); - cg.generateQualityDefine(vs, material.quality); - CodeGenerator::generateDefine(vs, "LOCATION_POSITION", uint32_t(VertexAttribute::POSITION)); // custom material variables @@ -637,6 +649,7 @@ std::string ShaderGenerator::createPostProcessVertexProgram(ShaderModel sm, cg.generateUniforms(vs, ShaderStage::VERTEX, UniformBindingPoints::PER_VIEW, UibGenerator::getPerViewUib()); + cg.generateUniforms(vs, ShaderStage::VERTEX, UniformBindingPoints::PER_MATERIAL_INSTANCE, material.uib); @@ -662,8 +675,6 @@ std::string ShaderGenerator::createPostProcessFragmentProgram(ShaderModel sm, io::sstream fs; cg.generateProlog(fs, ShaderStage::FRAGMENT, material); - cg.generateQualityDefine(fs, material.quality); - generatePostProcessMaterialVariantDefines(fs, PostProcessVariant(variant)); // custom material variables @@ -674,6 +685,7 @@ std::string ShaderGenerator::createPostProcessFragmentProgram(ShaderModel sm, cg.generateUniforms(fs, ShaderStage::FRAGMENT, UniformBindingPoints::PER_VIEW, UibGenerator::getPerViewUib()); + cg.generateUniforms(fs, ShaderStage::FRAGMENT, UniformBindingPoints::PER_MATERIAL_INSTANCE, material.uib); diff --git a/libs/filamat/src/shaders/ShaderGenerator.h b/libs/filamat/src/shaders/ShaderGenerator.h index d1e35a293c..ccaceffc64 100644 --- a/libs/filamat/src/shaders/ShaderGenerator.h +++ b/libs/filamat/src/shaders/ShaderGenerator.h @@ -62,7 +62,7 @@ public: std::string createComputeProgram(filament::backend::ShaderModel shaderModel, MaterialBuilder::TargetApi targetApi, MaterialBuilder::TargetLanguage targetLanguage, - MaterialInfo const& material, filament::Variant variant) const noexcept; + MaterialInfo const& material) const noexcept; /** * When a GLSL shader is optimized we run it through an intermediate SPIR-V @@ -75,6 +75,23 @@ public: MaterialInfo const& material) noexcept; private: + static void generateVertexDomainDefines(utils::io::sstream& out, + filament::VertexDomain domain) noexcept; + + static void generateSurfaceMaterialVariantProperties(utils::io::sstream& out, + MaterialBuilder::PropertyList const properties, + const MaterialBuilder::PreprocessorDefineList& defines) noexcept; + + static void generateSurfaceMaterialVariantDefines(utils::io::sstream& out, + filament::backend::ShaderStage stage, + MaterialInfo const& material, filament::Variant variant) noexcept; + + static void generatePostProcessMaterialVariantDefines(utils::io::sstream& out, + filament::PostProcessVariant variant) noexcept; + + static void generateUserSpecConstants( + const CodeGenerator& cg, utils::io::sstream& fs, + MaterialBuilder::ConstantList const& constants); std::string createPostProcessVertexProgram(filament::backend::ShaderModel sm, MaterialBuilder::TargetApi targetApi, MaterialBuilder::TargetLanguage targetLanguage, @@ -84,6 +101,9 @@ private: MaterialBuilder::TargetApi targetApi, MaterialBuilder::TargetLanguage targetLanguage, MaterialInfo const& material, uint8_t variant) const noexcept; + static void appendShader(utils::io::sstream& ss, + const utils::CString& shader, size_t lineOffset) noexcept; + MaterialBuilder::PropertyList mProperties; MaterialBuilder::VariableList mVariables; MaterialBuilder::OutputList mOutputs; diff --git a/shaders/src/common_types.glsl b/shaders/src/common_types.glsl index 0f38c1ddd0..770a3919d3 100644 --- a/shaders/src/common_types.glsl +++ b/shaders/src/common_types.glsl @@ -1,5 +1,6 @@ +#if defined(VARIANT_HAS_SHADOWING) // Adreno drivers seem to ignore precision qualifiers in structs, unless they're used in -// UBOs, which is is the case here. +// UBOs, which is the case here. struct ShadowData { highp mat4 lightFromWorldMatrix; highp vec4 lightFromWorldZ; @@ -13,11 +14,14 @@ struct ShadowData { mediump uint reserved1; mediump uint reserved2; }; +#endif +#if defined(VARIANT_HAS_SKINNING_OR_MORPHING) struct BoneData { highp mat3x4 transform; // bone transform is mat4x3 stored in row-major (last row [0,0,0,1]) highp uvec4 cof; // 8 first cofactor matrix of transform's upper left }; +#endif struct PerRenderableData { highp mat4 worldFromModelMatrix; diff --git a/tools/matc/src/matc/MaterialCompiler.cpp b/tools/matc/src/matc/MaterialCompiler.cpp index 92f67265a5..ff4c3f319c 100644 --- a/tools/matc/src/matc/MaterialCompiler.cpp +++ b/tools/matc/src/matc/MaterialCompiler.cpp @@ -18,6 +18,7 @@ #include #include +#include #include @@ -71,7 +72,7 @@ bool MaterialCompiler::processMaterial(const MaterialLexeme& jsonLexeme, jlexer.lex(jsonLexeme.getStart(), jsonLexeme.getSize(), jsonLexeme.getLine()); JsonishParser parser(jlexer.getLexemes()); - std::unique_ptr json = parser.parse(); + std::unique_ptr const json = parser.parse(); if (json == nullptr) { std::cerr << "JsonishParser error (see above)." << std::endl; @@ -79,7 +80,7 @@ bool MaterialCompiler::processMaterial(const MaterialLexeme& jsonLexeme, } ParametersProcessor parametersProcessor; - bool ok = parametersProcessor.process(builder, *json); + bool const ok = parametersProcessor.process(builder, *json); if (!ok) { std::cerr << "Error while processing material." << std::endl; return false; @@ -91,8 +92,8 @@ bool MaterialCompiler::processMaterial(const MaterialLexeme& jsonLexeme, bool MaterialCompiler::processVertexShader(const MaterialLexeme& lexeme, MaterialBuilder& builder) const noexcept { - MaterialLexeme trimmedLexeme = lexeme.trimBlockMarkers(); - std::string shaderStr = trimmedLexeme.getStringValue(); + MaterialLexeme const trimmedLexeme = lexeme.trimBlockMarkers(); + std::string const shaderStr = trimmedLexeme.getStringValue(); // getLine() returns a line number, with 1 being the first line, but .material wants a 0-based // line number offset, where 0 is the first line. @@ -103,8 +104,8 @@ bool MaterialCompiler::processVertexShader(const MaterialLexeme& lexeme, bool MaterialCompiler::processFragmentShader(const MaterialLexeme& lexeme, MaterialBuilder& builder) const noexcept { - MaterialLexeme trimmedLexeme = lexeme.trimBlockMarkers(); - std::string shaderStr = trimmedLexeme.getStringValue(); + MaterialLexeme const trimmedLexeme = lexeme.trimBlockMarkers(); + std::string const shaderStr = trimmedLexeme.getStringValue(); // getLine() returns a line number, with 1 being the first line, but .material wants a 0-based // line number offset, where 0 is the first line. @@ -117,8 +118,7 @@ bool MaterialCompiler::processComputeShader(const MaterialLexeme& lexeme, return MaterialCompiler::processFragmentShader(lexeme, builder); } -bool MaterialCompiler::ignoreLexeme(const MaterialLexeme& lexeme, - MaterialBuilder& builder) const noexcept { +bool MaterialCompiler::ignoreLexeme(const MaterialLexeme&, MaterialBuilder&) const noexcept { return true; } @@ -139,7 +139,7 @@ bool MaterialCompiler::processMaterialJSON(const JsonishValue* value, } ParametersProcessor parametersProcessor; - bool ok = parametersProcessor.process(builder, *value->toJsonObject()); + bool const ok = parametersProcessor.process(builder, *value->toJsonObject()); if (!ok) { std::cerr << "Error while processing material." << std::endl; return false; @@ -208,12 +208,12 @@ bool MaterialCompiler::processComputeShaderJSON(const JsonishValue* value, } bool MaterialCompiler::ignoreLexemeJSON(const JsonishValue*, - filamat::MaterialBuilder& builder) const noexcept { + filamat::MaterialBuilder&) const noexcept { return true; } static bool reflectParameters(const MaterialBuilder& builder) { - uint8_t count = builder.getParameterCount(); + uint8_t const count = builder.getParameterCount(); const MaterialBuilder::ParameterList& parameters = builder.getParameters(); std::cout << "{" << std::endl; @@ -316,7 +316,7 @@ bool MaterialCompiler::run(const Config& config) { ++endCursor; } // At this point, cursor points to the F in ${FOO} and endCursor points to the }. - std::string_view macro(&buffer[cursor], endCursor - cursor); + std::string_view const macro(&buffer[cursor], endCursor - cursor); if (auto iter = templateMap.find(macro); iter != templateMap.end()) { modifiedSize -= macro.size() + 3; modifiedSize += iter->second.size(); @@ -342,24 +342,24 @@ bool MaterialCompiler::run(const Config& config) { ssize_t endCursor = cursor; while (buffer[endCursor] != '}') ++endCursor; // At this point, cursor points to the F in ${FOO} and endCursor points to the }. - std::string_view macro(&buffer[cursor], endCursor - cursor); + std::string_view const macro(&buffer[cursor], endCursor - cursor); const std::string& val = templateMap.find(macro)->second; for (size_t i = 0, n = val.size(); i < n; ++i, ++dstCursor) { modifiedBuffer[dstCursor] = val[i]; } cursor = endCursor; } - buffer.reset(modifiedBuffer.release()); + buffer = std::move(modifiedBuffer); size = modifiedSize; } - utils::Path materialFilePath = utils::Path(input->getName()).getAbsolutePath(); + utils::Path const materialFilePath = utils::Path(input->getName()).getAbsolutePath(); assert(materialFilePath.isFile()); if (config.rawShaderMode()) { const std::string extension = materialFilePath.getExtension(); glslang::InitializeProcess(); - bool success = compileRawShader(buffer.get(), size, config.isDebug(), config.getOutput(), + bool const success = compileRawShader(buffer.get(), size, config.isDebug(), config.getOutput(), extension.c_str()); glslang::FinalizeProcess(); return success; @@ -414,7 +414,7 @@ bool MaterialCompiler::run(const Config& config) { js.adopt(); // Write builder.build() to output. - Package package = builder.build(js); + Package const package = builder.build(js); js.emancipate(); MaterialBuilder::shutdown(); @@ -468,9 +468,9 @@ bool MaterialCompiler::parseMaterialAsJSON(const char* buffer, size_t size, } // Retrieve function member pointer - MaterialConfigProcessorJSON p = mConfigProcessorJSON.at(key); + MaterialConfigProcessorJSON const p = mConfigProcessorJSON.at(key); // Call it. - bool ok = (*this.*p)(entry.second, builder); + bool const ok = (*this.*p)(entry.second, builder); if (!ok) { std::cerr << "Error while processing block with key:'" << key << "'" << std::endl; return false; @@ -539,7 +539,7 @@ bool MaterialCompiler::parseMaterial(const char* buffer, size_t size, return false; } } else if (lexeme.getType() == MaterialType::BLOCK) { - MaterialConfigProcessor processor = mConfigProcessor.at(identifier); + MaterialConfigProcessor const processor = mConfigProcessor.at(identifier); if (!(*this.*processor)(lexeme, builder)) { std::cerr << "Error while processing block with key:'" << identifier << "'" << std::endl; @@ -559,7 +559,7 @@ bool MaterialCompiler::compileRawShader(const char* glsl, size_t size, bool isDe const EShLanguage shLang = !strcmp(ext, "vs") ? EShLangVertex : EShLangFragment; // Add a terminating null by making a copy of the GLSL string. - std::string nullTerminated(glsl, size); + std::string const nullTerminated(glsl, size); glsl = nullTerminated.c_str(); TShader tShader(shLang); @@ -571,7 +571,7 @@ bool MaterialCompiler::compileRawShader(const char* glsl, size_t size, bool isDe tShader.setAutoMapBindings(true); - bool parseOk = tShader.parse(&DefaultTBuiltInResource, version, false, msg); + bool const parseOk = tShader.parse(&DefaultTBuiltInResource, version, false, msg); if (!parseOk) { std::cerr << "ERROR: Unable to parse " << ext << ":" << std::endl; std::cerr << tShader.getInfoLog() << std::endl; @@ -582,7 +582,7 @@ bool MaterialCompiler::compileRawShader(const char* glsl, size_t size, bool isDe // SPIR-V types TProgram program; program.addShader(&tShader); - bool linkOk = program.link(msg); + bool const linkOk = program.link(msg); if (!linkOk) { std::cerr << "ERROR: link failed " << std::endl << tShader.getInfoLog() << std::endl; return false; @@ -592,7 +592,7 @@ bool MaterialCompiler::compileRawShader(const char* glsl, size_t size, bool isDe SpvOptions options; GlslangToSpv(*tShader.getIntermediate(), spirv, &options); - if (spirv.size() == 0) { + if (spirv.empty()) { std::cerr << "SPIRV blob is empty." << std::endl; return false; }