Cleanup shader generation

- refactor the code so that all defines are generated in the same place
- generate common_type after all defines are generated
- protect (with defines) structures and UBOs that are not needed, based
  on the variant
This commit is contained in:
Mathias Agopian
2023-04-10 23:01:52 -07:00
committed by Mathias Agopian
parent de845d2885
commit 968c2c40fa
9 changed files with 402 additions and 307 deletions

View File

@@ -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**]

View File

@@ -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

View File

@@ -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<Va
shaderModel, targetApi, targetLanguage, info, v.variant, mInterpolation);
} else if (v.stage == backend::ShaderStage::COMPUTE) {
shader = sg.createComputeProgram(
shaderModel, targetApi, targetLanguage, info, v.variant);
shaderModel, targetApi, targetLanguage, info);
}
#ifdef FILAMAT_LITE
@@ -848,13 +852,16 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector<Va
config.glsl.subpassInputToColorLocation.emplace_back(0, 0);
}
bool ok = postProcessor.process(shader, config, pGlsl, pSpirv, pMsl);
bool const ok = postProcessor.process(shader, config, pGlsl, pSpirv, pMsl);
#else
bool ok = true;
#endif
if (!ok) {
showErrorMessage(mMaterialName.c_str_safe(), v.variant, targetApi, v.stage, shader);
cancelJobs = true;
if (mPrintShaders) {
slog.e << shader << io::endl;
}
return;
}
@@ -866,7 +873,7 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector<Va
// NOTE: Everything below touches shared structures protected by a lock
// NOTE: do not execute expensive work from here on!
std::unique_lock<Mutex> lock(entriesLock);
std::unique_lock<Mutex> 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);
}
}

View File

@@ -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<int, float, bool> 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;

View File

@@ -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

View File

@@ -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<MaterialBuilder::Property>(i), properties[i]);
CodeGenerator::generateMaterialProperty(out,
static_cast<MaterialBuilder::Property>(i), properties[i]);
}
// synthetic defines
bool hasTBN =
bool const hasTBN =
properties[static_cast<int>(MaterialBuilder::Property::ANISOTROPY)] ||
properties[static_cast<int>(MaterialBuilder::Property::NORMAL)] ||
properties[static_cast<int>(MaterialBuilder::Property::BENT_NORMAL)] ||
properties[static_cast<int>(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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -18,6 +18,7 @@
#include <memory>
#include <iostream>
#include <utility>
#include <filamat/MaterialBuilder.h>
@@ -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<JsonishObject> json = parser.parse();
std::unique_ptr<JsonishObject> 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;
}