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.
This commit is contained in:
committed by
Mathias Agopian
parent
1a8550e8e0
commit
ceeccde92c
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "sca/GLSLTools.h"
|
||||
|
||||
#include <utils/Log.h>
|
||||
#include <filament/MaterialEnums.h>
|
||||
|
||||
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
|
||||
|
||||
@@ -50,6 +50,7 @@ public:
|
||||
struct Config {
|
||||
filament::backend::ShaderType shaderType;
|
||||
filament::backend::ShaderModel shaderModel;
|
||||
filament::MaterialDomain domain;
|
||||
bool hasFramebufferFetch;
|
||||
struct {
|
||||
std::vector<std::pair<uint32_t, uint32_t>> subpassInputToColorLocation;
|
||||
|
||||
@@ -726,7 +726,8 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector<Va
|
||||
GLSLPostProcessor::Config config{
|
||||
.shaderType = v.stage,
|
||||
.shaderModel = shaderModel,
|
||||
.glsl = {}
|
||||
.domain = mMaterialDomain,
|
||||
.glsl = {},
|
||||
};
|
||||
|
||||
config.hasFramebufferFetch = mEnableFramebufferFetch;
|
||||
|
||||
@@ -109,8 +109,13 @@ UniformInterfaceBlock const& UibGenerator::getPerViewUib() noexcept {
|
||||
.add("vsmLightBleedReduction", 1, UniformInterfaceBlock::Type::FLOAT)
|
||||
.add("vsmReserved0", 1, UniformInterfaceBlock::Type::FLOAT)
|
||||
|
||||
.add("lodBias", 1, UniformInterfaceBlock::Type::FLOAT)
|
||||
.add("reserved1", 1, UniformInterfaceBlock::Type::FLOAT)
|
||||
.add("reserved2", 1, UniformInterfaceBlock::Type::FLOAT)
|
||||
.add("reserved3", 1, UniformInterfaceBlock::Type::FLOAT)
|
||||
|
||||
// bring PerViewUib to 2 KiB
|
||||
.add("padding2", 59, UniformInterfaceBlock::Type::FLOAT4)
|
||||
.add("padding2", 58, UniformInterfaceBlock::Type::FLOAT4)
|
||||
.build();
|
||||
return uib;
|
||||
}
|
||||
|
||||
@@ -359,4 +359,91 @@ void getFunctionParameters(TIntermAggregate* func, std::vector<FunctionParameter
|
||||
}
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
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
|
||||
|
||||
@@ -71,5 +71,10 @@ struct FunctionParameter {
|
||||
void getFunctionParameters(glslang::TIntermAggregate* func, std::vector<FunctionParameter>& 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user