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();