From ceeccde92c765c46c0cf965a81275dab09c90efa Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Tue, 14 Sep 2021 17:25:25 -0700 Subject: [PATCH] Implement lod bias for user materials A lod bias can be applied to textures when dynamic resolution is enabled. A proper lod bias is calculated and applied for quality levels HIGH and ULTRA. Lod Bias is implemented in glslang, which mean it's ignored when glslang is not used, which currently happens with OpenGL backends with optimization turned off (which includes filament LITE). This may be fixed in the future. --- RELEASE_NOTES.md | 3 + filament/src/PerViewUniforms.cpp | 10 +++ filament/src/PerViewUniforms.h | 2 + filament/src/Renderer.cpp | 2 + filament/src/View.cpp | 5 ++ filament/src/details/View.h | 1 + .../include/private/filament/UibStructs.h | 7 +- libs/filamat/src/GLSLPostProcessor.cpp | 7 ++ libs/filamat/src/GLSLPostProcessor.h | 1 + libs/filamat/src/MaterialBuilder.cpp | 3 +- libs/filamat/src/UibGenerator.cpp | 7 +- libs/filamat/src/sca/ASTHelpers.cpp | 87 +++++++++++++++++++ libs/filamat/src/sca/ASTHelpers.h | 5 ++ libs/filamat/src/sca/GLSLTools.cpp | 6 ++ libs/filamat/src/sca/GLSLTools.h | 2 + libs/filamat/src/shaders/ShaderGenerator.cpp | 2 + shaders/src/depth_main.fs | 2 + shaders/src/main.fs | 2 + 18 files changed, 151 insertions(+), 3 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 8a101f8e11..4f1d13b4e1 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -5,6 +5,9 @@ A new header is inserted each time a *tag* is created. ## v1.12.6 (currently main branch) +- engine: Added concept of lod bias to materials. + [⚠️ **Materials need to be rebuilt to access this new feature**]. + ## v1.12.5 - engine: Fix, BGRA ordering respected for external images with OpenGL on iOS. diff --git a/filament/src/PerViewUniforms.cpp b/filament/src/PerViewUniforms.cpp index 947e3f96bf..aa7f032f7c 100644 --- a/filament/src/PerViewUniforms.cpp +++ b/filament/src/PerViewUniforms.cpp @@ -87,6 +87,16 @@ void PerViewUniforms::prepareCamera(const CameraInfo& camera) noexcept { s.clipControl = mClipControl; } +void PerViewUniforms::prepareUpscaler(math::float2 scale, + DynamicResolutionOptions const& options) noexcept { + auto& s = mPerViewUb.edit(); + if (options.quality >= QualityLevel::HIGH) { + s.lodBias = std::log2(std::min(scale.x, scale.y)); + } else { + s.lodBias = 0.0f; + } +} + void PerViewUniforms::prepareExposure(float ev100) noexcept { const float exposure = Exposure::exposure(ev100); auto& s = mPerViewUb.edit(); diff --git a/filament/src/PerViewUniforms.h b/filament/src/PerViewUniforms.h index 9173ff4811..bc24e7a264 100644 --- a/filament/src/PerViewUniforms.h +++ b/filament/src/PerViewUniforms.h @@ -31,6 +31,7 @@ namespace filament { struct FogOptions; +struct DynamicResolutionOptions; struct AmbientOcclusionOptions; struct VsmShadowOptions; @@ -53,6 +54,7 @@ public: void terminate(FEngine& engine); void prepareCamera(const CameraInfo& camera) noexcept; + void prepareUpscaler(math::float2 scale, DynamicResolutionOptions const& options) noexcept; void prepareViewport(const filament::Viewport& viewport) noexcept; void prepareTime(FEngine& engine, math::float4 const& userTime) noexcept; void prepareExposure(float ev100) noexcept; diff --git a/filament/src/Renderer.cpp b/filament/src/Renderer.cpp index 71b7112c6c..fb28d7f4be 100644 --- a/filament/src/Renderer.cpp +++ b/filament/src/Renderer.cpp @@ -258,6 +258,8 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) { view.prepare(engine, driver, arena, svp, getShaderUserTime()); + view.prepareUpscaler(scale); + // start froxelization immediately, it has no dependencies JobSystem::Job* jobFroxelize = nullptr; if (view.hasDynamicLighting()) { diff --git a/filament/src/View.cpp b/filament/src/View.cpp index 876528281a..95c5271639 100644 --- a/filament/src/View.cpp +++ b/filament/src/View.cpp @@ -554,6 +554,11 @@ UTILS_NOINLINE }); } +void FView::prepareUpscaler(float2 scale) const noexcept { + SYSTRACE_CALL(); + mPerViewUniforms.prepareUpscaler(scale, mDynamicResolution); +} + void FView::prepareCamera(const CameraInfo& camera) const noexcept { SYSTRACE_CALL(); mPerViewUniforms.prepareCamera(camera); diff --git a/filament/src/details/View.h b/filament/src/details/View.h index fd78e465ff..c2d4066ddb 100644 --- a/filament/src/details/View.h +++ b/filament/src/details/View.h @@ -159,6 +159,7 @@ public: return mName.c_str(); } + void prepareUpscaler(math::float2 scale) const noexcept; void prepareCamera(const CameraInfo& camera) const noexcept; void prepareViewport(const Viewport& viewport) const noexcept; void prepareShadowing(FEngine& engine, backend::DriverApi& driver, diff --git a/libs/filabridge/include/private/filament/UibStructs.h b/libs/filabridge/include/private/filament/UibStructs.h index b42787246d..e61a4e5ec5 100644 --- a/libs/filabridge/include/private/filament/UibStructs.h +++ b/libs/filabridge/include/private/filament/UibStructs.h @@ -128,8 +128,13 @@ struct PerViewUib { // NOLINT(cppcoreguidelines-pro-type-member-init) float vsmLightBleedReduction; float vsmReserved0; + float lodBias; + float reserved1; + float reserved2; + float reserved3; + // bring PerViewUib to 2 KiB - math::float4 padding2[59]; + math::float4 padding2[58]; }; // 2 KiB == 128 float4s diff --git a/libs/filamat/src/GLSLPostProcessor.cpp b/libs/filamat/src/GLSLPostProcessor.cpp index b2eb53c1dd..6c9de50f25 100644 --- a/libs/filamat/src/GLSLPostProcessor.cpp +++ b/libs/filamat/src/GLSLPostProcessor.cpp @@ -30,6 +30,7 @@ #include "sca/GLSLTools.h" #include +#include using namespace glslang; using namespace spirv_cross; @@ -203,6 +204,12 @@ bool GLSLPostProcessor::process(const std::string& inputShader, Config const& co return false; } + // add texture lod bias + if (config.shaderType == filament::backend::FRAGMENT && + config.domain == filament::MaterialDomain::SURFACE) { + GLSLTools::textureLodBias(tShader); + } + program.addShader(&tShader); // Even though we only have a single shader stage, linking is still necessary to finalize // SPIR-V types diff --git a/libs/filamat/src/GLSLPostProcessor.h b/libs/filamat/src/GLSLPostProcessor.h index 8096e8a098..dd9e749102 100644 --- a/libs/filamat/src/GLSLPostProcessor.h +++ b/libs/filamat/src/GLSLPostProcessor.h @@ -50,6 +50,7 @@ public: struct Config { filament::backend::ShaderType shaderType; filament::backend::ShaderModel shaderModel; + filament::MaterialDomain domain; bool hasFramebufferFetch; struct { std::vector> subpassInputToColorLocation; diff --git a/libs/filamat/src/MaterialBuilder.cpp b/libs/filamat/src/MaterialBuilder.cpp index 71c21d8181..194cdca168 100644 --- a/libs/filamat/src/MaterialBuilder.cpp +++ b/libs/filamat/src/MaterialBuilder.cpp @@ -726,7 +726,8 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector +class TraverserAdapter: public TIntermTraverser { + F closure; +public: + explicit TraverserAdapter(F closure) + : TIntermTraverser(true, false, false, false), + closure(closure) { + } + bool visitAggregate(TVisit visit, TIntermAggregate* node) override { + return closure(visit, node); + } +}; + +void textureLodBias(TIntermediate* intermediate, TIntermNode* root, + const char* lodBiasSymbolName) { + // we need to run this only from the user's main entry point + + // First, find the "lodBias" symbol + TIntermSymbol* pIntermSymbolLodBias = nullptr; + TraverserAdapter findLodBiasSymbol( + [&, done = false](TVisit visit, TIntermAggregate* node) mutable { + if (node->getOp() == glslang::EOpSequence) { + return !done; + } + if (node->getOp() == glslang::EOpLinkerObjects) { + for (TIntermNode* item : node->getSequence()) { + TIntermSymbol* symbol = item->getAsSymbolNode(); + if (symbol && symbol->getBasicType() == TBasicType::EbtFloat) { + if (symbol->getName() == lodBiasSymbolName) { + pIntermSymbolLodBias = symbol; + done = true; + break; + } + } + } + } + return false; + }); + root->traverse(&findLodBiasSymbol); + + if (!pIntermSymbolLodBias) { + // something went wrong + utils::slog.e << "lod bias ignored because \"" << lodBiasSymbolName << "\" was not found!" << utils::io::endl; + return; + } + + // add lod bias to texture calls + TraverserAdapter addLodBiasToTextureCalls( + [&](TVisit visit, TIntermAggregate* node) { + // skip everything that's not a texture() call + if (node->getOp() != glslang::EOpTexture) { + return true; + } + + TIntermSequence& sequence = node->getSequence(); + + // first check that we have the correct sampler + TIntermTyped* pTyped = sequence[0]->getAsTyped(); + if (!pTyped) { + return false; + } + + TSampler const& sampler = pTyped->getType().getSampler(); + if (sampler.isArrayed() && sampler.isShadow()) { + // sampler2DArrayShadow is not supported + return false; + } + + // Then add the lod bias to the texture() call + if (sequence.size() == 2) { + // we only have 2 parameters, add the 3rd one + TIntermSymbol* symbol = intermediate->addSymbol(*pIntermSymbolLodBias); + sequence.push_back(symbol); + } else if (sequence.size() == 3) { + // load bias is already specified + TIntermSymbol* symbol = intermediate->addSymbol(*pIntermSymbolLodBias); + TIntermTyped* pAdd = intermediate->addBinaryMath(TOperator::EOpAdd, + sequence[2]->getAsTyped(), symbol, + node->getLoc()); + sequence[2] = pAdd; + } + + return false; + }); + root->traverse(&addLodBiasToTextureCalls); +} + } // namespace ASTHelpers diff --git a/libs/filamat/src/sca/ASTHelpers.h b/libs/filamat/src/sca/ASTHelpers.h index 7fb11eaccf..5e76389434 100644 --- a/libs/filamat/src/sca/ASTHelpers.h +++ b/libs/filamat/src/sca/ASTHelpers.h @@ -71,5 +71,10 @@ struct FunctionParameter { void getFunctionParameters(glslang::TIntermAggregate* func, std::vector& output) noexcept; +// add lod bias to texture() calls +void textureLodBias(glslang::TIntermediate* intermediate, TIntermNode* root, + const char* lodBiasSymbolName); + + } // namespace ASTutils #endif //TNT_SCAHELPERS_H_H diff --git a/libs/filamat/src/sca/GLSLTools.cpp b/libs/filamat/src/sca/GLSLTools.cpp index f439d0921a..4bf7f64624 100644 --- a/libs/filamat/src/sca/GLSLTools.cpp +++ b/libs/filamat/src/sca/GLSLTools.cpp @@ -359,4 +359,10 @@ void GLSLTools::prepareShaderParser(MaterialBuilder::TargetApi targetApi, glslan } } +void GLSLTools::textureLodBias(TShader& shader) { + TIntermediate* intermediate = shader.getIntermediate(); + TIntermNode* root = intermediate->getTreeRoot(); + ASTUtils::textureLodBias(intermediate, root, "filament_lodBias"); +} + } // namespace filamat diff --git a/libs/filamat/src/sca/GLSLTools.h b/libs/filamat/src/sca/GLSLTools.h index e37bb60a39..e9908ff54c 100644 --- a/libs/filamat/src/sca/GLSLTools.h +++ b/libs/filamat/src/sca/GLSLTools.h @@ -150,6 +150,8 @@ public: static void prepareShaderParser(MaterialBuilder::TargetApi targetApi, glslang::TShader& shader, EShLanguage language, int version, MaterialBuilder::Optimization optimization); + static void textureLodBias(glslang::TShader& shader); + private: diff --git a/libs/filamat/src/shaders/ShaderGenerator.cpp b/libs/filamat/src/shaders/ShaderGenerator.cpp index 7d6dfdf397..efb08bd55b 100644 --- a/libs/filamat/src/shaders/ShaderGenerator.cpp +++ b/libs/filamat/src/shaders/ShaderGenerator.cpp @@ -434,6 +434,8 @@ std::string ShaderGenerator::createFragmentProgram(filament::backend::ShaderMode material.samplerBindings.getBlockOffset(BindingPoints::PER_MATERIAL_INSTANCE), material.sib); + fs << "float filament_lodBias;\n"; + // shading code cg.generateCommon(fs, ShaderType::FRAGMENT); cg.generateGetters(fs, ShaderType::FRAGMENT); diff --git a/shaders/src/depth_main.fs b/shaders/src/depth_main.fs index 4d6d9c4076..0565ec6ca4 100644 --- a/shaders/src/depth_main.fs +++ b/shaders/src/depth_main.fs @@ -7,6 +7,8 @@ layout(location = 0) out vec4 fragColor; //------------------------------------------------------------------------------ void main() { + filament_lodBias = frameUniforms.lodBias; + #if defined(BLEND_MODE_MASKED) || (defined(BLEND_MODE_TRANSPARENT) && defined(HAS_TRANSPARENT_SHADOW)) MaterialInputs inputs; initMaterial(inputs); diff --git a/shaders/src/main.fs b/shaders/src/main.fs index 53be5174e3..fbe3601542 100644 --- a/shaders/src/main.fs +++ b/shaders/src/main.fs @@ -17,6 +17,8 @@ void blendPostLightingColor(const MaterialInputs material, inout vec4 color) { #endif void main() { + filament_lodBias = frameUniforms.lodBias; + // See shading_parameters.fs // Computes global variables we need to evaluate material and lighting computeShadingParams();