From 1dae41c607e008800657dfa5cfe590cb02265719 Mon Sep 17 00:00:00 2001
From: Powei Feng
Date: Mon, 27 Jan 2025 11:51:48 -0800
Subject: [PATCH 1/8] matdbg: fix two bugs with formatting (#8388)
- return original source when on an unsupported platform
- check clang-format is available and return original source.
---
libs/matdbg/src/SourceFormatter.cpp | 42 ++++++++++++++++++-----------
1 file changed, 27 insertions(+), 15 deletions(-)
diff --git a/libs/matdbg/src/SourceFormatter.cpp b/libs/matdbg/src/SourceFormatter.cpp
index c068a34f4b..fe7c3f88ed 100644
--- a/libs/matdbg/src/SourceFormatter.cpp
+++ b/libs/matdbg/src/SourceFormatter.cpp
@@ -25,14 +25,32 @@ namespace filament::matdbg {
#if defined(__linux__) || defined(__APPLE__)
std::string SourceFormatter::format(char const* source) {
- std::string const TMP_FILENAME = "/tmp/matdbg-tmp-src.cpp";
+ char output[1024];
- std::string original(source);
- FILE* fp;
- fp = fopen(TMP_FILENAME.c_str(), "w");
- if (!fp) {
- return original;
+ // First check if clang-format is available.
+ FILE* fp = popen("clang-format -version", "r");
+
+ // Need to drain the output
+ while (fgets(output, 1024, fp) != NULL) {}
+
+ int status = pclose(fp);
+ if (!fp || !WEXITSTATUS(status)) {
+ std::call_once(mClangWarningFlag, []() {
+ utils::slog.w << "[matdbg] unable to run clang-format to format shader file. "
+ << "Please make sure it's installed." << utils::io::endl;
+ });
+ return source;
}
+
+ // Write the source to a temp file for formatting
+ char const* TMP_FILENAME = "/tmp/matdbg-tmp-src.cpp";
+ fp = fopen(TMP_FILENAME, "w");
+ if (!fp) {
+ return source;
+ }
+
+ // Unknown if the input is 0-terminated so we put it in a string first.
+ std::string original(source);
fputs(original.c_str(), fp);
fflush(fp);
pclose(fp);
@@ -45,22 +63,16 @@ std::string SourceFormatter::format(char const* source) {
"}'";
fp = popen(("clang-format " + CLANG_FORMAT_OPTIONS + "< " + TMP_FILENAME).c_str(), "r");
-
if (!fp) {
- std::call_once(mClangWarningFlag, []() {
- utils::slog.w << "[matdbg] unable to run clang-format to format shader file. "
- << "Please make sure it's installed.";
- });
return original;
}
- char output[1024];
std::stringstream outStream;
while (fgets(output, 1024, fp) != NULL) {
outStream << output;
}
- int status = pclose(fp);
+ status = pclose(fp);
if (WEXITSTATUS(status)) {
utils::slog.w << "[matdbg] clang-format failed with code=" << WEXITSTATUS(status)
<< utils::io::endl;
@@ -69,11 +81,11 @@ std::string SourceFormatter::format(char const* source) {
}
#else
std::string SourceFormatter::format(char const* source) {
- std::call_once(mClangWarningFlag, []() {
+ std::call_once(mClangWarningFlag, []() {
utils::slog.w <<"[matdbg]: source formatting is not available on this platform" <<
utils::io::endl;
});
- return "";
+ return source;
}
#endif
From 5fd84db44775c5cdd7064881dc3b3976cac96506 Mon Sep 17 00:00:00 2001
From: John Bampton
Date: Mon, 27 Jan 2025 00:00:41 +1000
Subject: [PATCH 2/8] docs: update `ImageDecoder.h`; fix spelling
---
libs/imageio/include/imageio/ImageDecoder.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libs/imageio/include/imageio/ImageDecoder.h b/libs/imageio/include/imageio/ImageDecoder.h
index cd341c49d8..4573e0b2c8 100644
--- a/libs/imageio/include/imageio/ImageDecoder.h
+++ b/libs/imageio/include/imageio/ImageDecoder.h
@@ -33,7 +33,7 @@ public:
SRGB
};
- // Returns linear floating-point data, or a non-valid image if an error occured.
+ // Returns linear floating-point data, or a non-valid image if an error occurred.
static LinearImage decode(std::istream& stream, const std::string& sourceName,
ColorSpace sourceSpace = ColorSpace::SRGB);
From 68b3d9ba5427c2a442ba32a70a48cf26063ff4c8 Mon Sep 17 00:00:00 2001
From: Mathias Agopian
Date: Mon, 27 Jan 2025 21:44:56 -0800
Subject: [PATCH 3/8] mistakenly enabled the Shadow Atlas feature
---
filament/src/details/Engine.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/filament/src/details/Engine.h b/filament/src/details/Engine.h
index da83a726a6..d52907dc76 100644
--- a/filament/src/details/Engine.h
+++ b/filament/src/details/Engine.h
@@ -716,7 +716,7 @@ public:
&features.backend.opengl.assert_native_window_is_valid, true },
{ "engine.shadows.use_shadow_atlas",
"Uses an array of atlases to store shadow maps.",
- &features.engine.shadows.use_shadow_atlas, true },
+ &features.engine.shadows.use_shadow_atlas, false },
{ "features.engine.debug.assert_material_instance_in_use",
"Assert when a MaterialInstance is destroyed while it is in use by RenderableManager.",
&features.engine.debug.assert_material_instance_in_use, false }
From 5b3343fcc21b11aaa1dfb13bf5e6449de4fb7cac Mon Sep 17 00:00:00 2001
From: Mathias Agopian
Date: Wed, 29 Jan 2025 11:55:23 -0800
Subject: [PATCH 4/8] Fix ShadowMapManager ShadowMap alignment (#8398)
---
filament/src/ShadowMapManager.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/filament/src/ShadowMapManager.h b/filament/src/ShadowMapManager.h
index a6dc21cab3..ba606c6eb4 100644
--- a/filament/src/ShadowMapManager.h
+++ b/filament/src/ShadowMapManager.h
@@ -230,7 +230,7 @@ private:
// Inline storage for all our ShadowMap objects, we can't easily use a std::array<> directly.
// Because ShadowMap doesn't have a default ctor, and we avoid out-of-line allocations.
// Each ShadowMap is currently 88 bytes (total of ~12KB for 128 shadow maps)
- using ShadowMapStorage = std::aligned_storage::type;
+ using ShadowMapStorage = std::aligned_storage_t;
using ShadowMapCacheContainer = std::array;
ShadowMapCacheContainer mShadowMapCache;
uint32_t mDirectionalShadowMapCount = 0;
From 48a2c6483b523b97bed76e54706a48c11ec05ca2 Mon Sep 17 00:00:00 2001
From: Mathias Agopian
Date: Sat, 25 Jan 2025 00:38:18 -0800
Subject: [PATCH 5/8] Add support for SGSR 1.0
SGSR stands for Snapdragon Game Super Resolution. It is an efficient
upscaler for mobile.
Split the upscaling passes into multiple methods in PostProcessManager.
Also, add a way to preserve the alpha channel in the FXAA pass.
---
.../com/google/android/filament/View.java | 4 +-
filament/CMakeLists.txt | 7 +
filament/include/filament/Options.h | 4 +-
filament/src/PostProcessManager.cpp | 222 ++++++++++++++----
filament/src/PostProcessManager.h | 19 +-
filament/src/details/Renderer.cpp | 23 +-
.../materials/colorGrading/colorGrading.mat | 6 +-
filament/src/materials/sgsr/LICENSE.txt | 29 +++
filament/src/materials/sgsr/sgsr1.mat | 80 +++++++
.../src/materials/sgsr/sgsr1_shader_mobile.fs | 132 +++++++++++
10 files changed, 458 insertions(+), 68 deletions(-)
create mode 100644 filament/src/materials/sgsr/LICENSE.txt
create mode 100644 filament/src/materials/sgsr/sgsr1.mat
create mode 100644 filament/src/materials/sgsr/sgsr1_shader_mobile.fs
diff --git a/android/filament-android/src/main/java/com/google/android/filament/View.java b/android/filament-android/src/main/java/com/google/android/filament/View.java
index 0bcd1299b7..bcf6f5378f 100644
--- a/android/filament-android/src/main/java/com/google/android/filament/View.java
+++ b/android/filament-android/src/main/java/com/google/android/filament/View.java
@@ -1420,10 +1420,10 @@ public class View {
/**
* Upscaling quality
* LOW: bilinear filtered blit. Fastest, poor quality
- * MEDIUM: AMD FidelityFX FSR1 w/ mobile optimizations
+ * MEDIUM: Qualcomm Snapdragon Game Super Resolution (SGSR) 1.0
* HIGH: AMD FidelityFX FSR1 w/ mobile optimizations
* ULTRA: AMD FidelityFX FSR1
- * FSR1 require a well anti-aliased (MSAA or TAA), noise free scene.
+ * FSR1 and SGSR require a well anti-aliased (MSAA or TAA), noise free scene. Avoid FXAA and dithering.
*
* The default upscaling quality is set to LOW.
*/
diff --git a/filament/CMakeLists.txt b/filament/CMakeLists.txt
index d218a39170..9f0364f94e 100644
--- a/filament/CMakeLists.txt
+++ b/filament/CMakeLists.txt
@@ -252,6 +252,7 @@ set(MATERIAL_SRCS
src/materials/fsr/fsr_easu_mobile.mat
src/materials/fsr/fsr_easu_mobileF.mat
src/materials/fsr/fsr_rcas.mat
+ src/materials/sgsr/sgsr1.mat
src/materials/resolveDepth.mat
src/materials/separableGaussianBlur.mat
src/materials/skybox.mat
@@ -504,6 +505,12 @@ add_custom_command(
APPEND
)
+add_custom_command(
+ OUTPUT "${MATERIAL_DIR}/sgsr1.filamat"
+ DEPENDS src/materials/sgsr/sgsr1_shader_mobile.fs
+ APPEND
+)
+
add_custom_command(
OUTPUT "${MATERIAL_DIR}/separableGaussianBlur.filamat"
DEPENDS src/materials/separableGaussianBlur.vs
diff --git a/filament/include/filament/Options.h b/filament/include/filament/Options.h
index 93bba80cd8..dc06143dd4 100644
--- a/filament/include/filament/Options.h
+++ b/filament/include/filament/Options.h
@@ -86,10 +86,10 @@ struct DynamicResolutionOptions {
/**
* Upscaling quality
* LOW: bilinear filtered blit. Fastest, poor quality
- * MEDIUM: AMD FidelityFX FSR1 w/ mobile optimizations
+ * MEDIUM: Qualcomm Snapdragon Game Super Resolution (SGSR) 1.0
* HIGH: AMD FidelityFX FSR1 w/ mobile optimizations
* ULTRA: AMD FidelityFX FSR1
- * FSR1 require a well anti-aliased (MSAA or TAA), noise free scene.
+ * FSR1 and SGSR require a well anti-aliased (MSAA or TAA), noise free scene. Avoid FXAA and dithering.
*
* The default upscaling quality is set to LOW.
*/
diff --git a/filament/src/PostProcessManager.cpp b/filament/src/PostProcessManager.cpp
index b7a51aae0b..d9ab8b0c16 100644
--- a/filament/src/PostProcessManager.cpp
+++ b/filament/src/PostProcessManager.cpp
@@ -311,6 +311,7 @@ static const PostProcessManager::StaticMaterialInfo sMaterialList[] = {
{ "fsr_easu_mobile", MATERIAL(FSR_EASU_MOBILE) },
{ "fsr_easu_mobileF", MATERIAL(FSR_EASU_MOBILEF) },
{ "fsr_rcas", MATERIAL(FSR_RCAS) },
+ { "sgsr1", MATERIAL(SGSR1) },
{ "debugShadowCascades", MATERIAL(DEBUGSHADOWCASCADES) },
{ "resolveDepth", MATERIAL(RESOLVEDEPTH) },
{ "shadowmap", MATERIAL(SHADOWMAP) },
@@ -2328,7 +2329,7 @@ void PostProcessManager::colorGradingPrepareSubpass(DriverApi& driver,
mi->setParameter("vignette", vignetteParameters);
mi->setParameter("vignetteColor", vignetteOptions.color);
mi->setParameter("dithering", colorGradingConfig.dithering);
- mi->setParameter("fxaa", colorGradingConfig.fxaa);
+ mi->setParameter("outputLuminance", colorGradingConfig.outputLuminance);
mi->setParameter("temporalNoise", temporalNoise);
mi->commit(driver);
@@ -2544,7 +2545,7 @@ FrameGraphId PostProcessManager::colorGrading(FrameGraph& fg,
mi->setParameter("bloom", bloomParameters);
mi->setParameter("vignette", vignetteParameters);
mi->setParameter("vignetteColor", vignetteOptions.color);
- mi->setParameter("fxaa", colorGradingConfig.fxaa);
+ mi->setParameter("outputLuminance", colorGradingConfig.outputLuminance);
mi->setParameter("temporalNoise", temporalNoise);
mi->setParameter("viewport", float4{
float(vp.left) / input.width,
@@ -2562,7 +2563,7 @@ FrameGraphId PostProcessManager::colorGrading(FrameGraph& fg,
FrameGraphId PostProcessManager::fxaa(FrameGraph& fg,
FrameGraphId const input, filament::Viewport const& vp,
- TextureFormat const outFormat, bool const translucent) noexcept {
+ TextureFormat const outFormat, bool const preserveAlphaChannel) noexcept {
struct PostProcessFXAA {
FrameGraphId input;
@@ -2587,7 +2588,7 @@ FrameGraphId PostProcessManager::fxaa(FrameGraph& fg,
auto const& material = getPostProcessMaterial("fxaa");
- PostProcessVariant const variant = translucent ?
+ PostProcessVariant const variant = preserveAlphaChannel ?
PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE;
FMaterialInstance* const mi =
@@ -2920,20 +2921,171 @@ FrameGraphId PostProcessManager::rcas(
}
FrameGraphId PostProcessManager::upscale(FrameGraph& fg, bool translucent,
- DynamicResolutionOptions dsrOptions, FrameGraphId const input,
- filament::Viewport const& vp, FrameGraphTexture::Descriptor const& outDesc,
- SamplerMagFilter filter) noexcept {
-
+ bool sourceHasLuminance, DynamicResolutionOptions dsrOptions,
+ FrameGraphId const input, filament::Viewport const& vp,
+ FrameGraphTexture::Descriptor const& outDesc, SamplerMagFilter filter) noexcept {
// The code below cannot handle sub-resources
assert_invariant(fg.getSubResourceDescriptor(input).layer == 0);
assert_invariant(fg.getSubResourceDescriptor(input).level == 0);
- const bool lowQualityFallback = translucent && dsrOptions.quality != QualityLevel::LOW;
+ const bool lowQualityFallback = translucent;
if (lowQualityFallback) {
- // FidelityFX-FSR doesn't support the alpha channel currently
+ // FidelityFX-FSR nor SGSR support the source alpha channel currently
dsrOptions.quality = QualityLevel::LOW;
}
+ if (dsrOptions.quality == QualityLevel::LOW) {
+ return upscaleBilinear(fg, translucent, dsrOptions, input, vp, outDesc, filter);
+ }
+ if (dsrOptions.quality == QualityLevel::MEDIUM) {
+ return upscaleSGSR1(fg, sourceHasLuminance, dsrOptions, input, vp, outDesc);
+ }
+ return upscaleFSR1(fg, dsrOptions, input, vp, outDesc);
+}
+
+FrameGraphId PostProcessManager::upscaleBilinear(FrameGraph& fg, bool translucent,
+ DynamicResolutionOptions dsrOptions, FrameGraphId const input,
+ filament::Viewport const& vp, FrameGraphTexture::Descriptor const& outDesc,
+ SamplerMagFilter filter) noexcept {
+
+ struct QuadBlitData {
+ FrameGraphId input;
+ FrameGraphId output;
+ };
+
+ auto const& ppQuadBlit = fg.addPass(dsrOptions.enabled ? "upscaling" : "compositing",
+ [&](FrameGraph::Builder& builder, auto& data) {
+ data.input = builder.sample(input);
+ data.output = builder.createTexture("upscaled output", outDesc);
+ data.output = builder.write(data.output, FrameGraphTexture::Usage::COLOR_ATTACHMENT);
+ builder.declareRenderPass(builder.getName(data.output), {
+ .attachments = { .color = { data.output } },
+ .clearFlags = TargetBufferFlags::DEPTH });
+ },
+ [this, vp, translucent, filter](FrameGraphResources const& resources,
+ auto const& data, DriverApi& driver) {
+ bindPostProcessDescriptorSet(driver);
+
+ // helper to enable blending
+ auto enableTranslucentBlending = [](PipelineState& pipeline) {
+ pipeline.rasterState.blendFunctionSrcRGB = BlendFunction::ONE;
+ pipeline.rasterState.blendFunctionSrcAlpha = BlendFunction::ONE;
+ pipeline.rasterState.blendFunctionDstRGB = BlendFunction::ONE_MINUS_SRC_ALPHA;
+ pipeline.rasterState.blendFunctionDstAlpha = BlendFunction::ONE_MINUS_SRC_ALPHA;
+ };
+
+ auto color = resources.getTexture(data.input);
+ auto const& inputDesc = resources.getDescriptor(data.input);
+
+ // --------------------------------------------------------------------------------
+ // set uniforms
+
+ auto& material = getPostProcessMaterial("blitLow");
+ FMaterialInstance* const mi =
+ PostProcessMaterial::getMaterialInstance(mEngine, material);
+ mi->setParameter("color", color, {
+ .filterMag = filter
+ });
+
+ mi->setParameter("levelOfDetail", 0.0f);
+
+ mi->setParameter("viewport", float4{
+ float(vp.left) / inputDesc.width,
+ float(vp.bottom) / inputDesc.height,
+ float(vp.width) / inputDesc.width,
+ float(vp.height) / inputDesc.height
+ });
+ mi->commit(driver);
+ mi->use(driver);
+
+ auto out = resources.getRenderPassInfo();
+
+ auto pipeline = getPipelineState(material.getMaterial(mEngine));
+ if (translucent) {
+ enableTranslucentBlending(pipeline);
+ }
+ renderFullScreenQuad(out, pipeline, driver);
+ });
+
+ auto output = ppQuadBlit->output;
+
+ // if we had to take the low quality fallback, we still do the "sharpen pass"
+ if (dsrOptions.sharpness > 0.0f) {
+ output = rcas(fg, dsrOptions.sharpness, output, outDesc, translucent);
+ }
+
+ // we rely on automatic culling of unused render passes
+ return output;
+}
+
+FrameGraphId PostProcessManager::upscaleSGSR1(FrameGraph& fg, bool sourceHasLuminance,
+ DynamicResolutionOptions dsrOptions, FrameGraphId const input,
+ filament::Viewport const&, FrameGraphTexture::Descriptor const& outDesc) noexcept {
+
+ struct QuadBlitData {
+ FrameGraphId input;
+ FrameGraphId output;
+ };
+
+ auto const& ppQuadBlit = fg.addPass(dsrOptions.enabled ? "upscaling" : "compositing",
+ [&](FrameGraph::Builder& builder, auto& data) {
+ data.input = builder.sample(input);
+ data.output = builder.createTexture("upscaled output", outDesc);
+ data.output = builder.write(data.output, FrameGraphTexture::Usage::COLOR_ATTACHMENT);
+ builder.declareRenderPass(builder.getName(data.output), {
+ .attachments = { .color = { data.output } },
+ .clearFlags = TargetBufferFlags::DEPTH });
+ },
+ [this, sourceHasLuminance](FrameGraphResources const& resources,
+ auto const& data, DriverApi& driver) {
+ bindPostProcessDescriptorSet(driver);
+
+ auto color = resources.getTexture(data.input);
+ auto const& inputDesc = resources.getDescriptor(data.input);
+
+ // --------------------------------------------------------------------------------
+ // set uniforms
+
+ auto const& material = getPostProcessMaterial("sgsr1");
+
+ PostProcessVariant const variant = sourceHasLuminance ?
+ PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE;
+
+ FMaterialInstance* const mi =
+ PostProcessMaterial::getMaterialInstance(mEngine, material, variant);
+
+ mi->setParameter("color", color, {
+ // The SGSR documentation doesn't clarify if LINEAR or NEAREST should be used. The
+ // sample code uses NEAREST, but that doesn't seem right, since it would mean the
+ // LERP mode would not be a LERP, and the non-edges would be sampled as NEAREST.
+ .filterMag = SamplerMagFilter::LINEAR
+ });
+
+ mi->setParameter("viewport", float4{
+ 1.0f / inputDesc.width,
+ 1.0f / inputDesc.height,
+ float(inputDesc.width),
+ float(inputDesc.height),
+ });
+
+ mi->commit(driver);
+ mi->use(driver);
+
+ auto out = resources.getRenderPassInfo();
+ commitAndRenderFullScreenQuad(driver, out, mi, variant);
+
+ });
+
+ auto output = ppQuadBlit->output;
+
+ // we rely on automatic culling of unused render passes
+ return output;
+}
+
+FrameGraphId PostProcessManager::upscaleFSR1(FrameGraph& fg,
+ DynamicResolutionOptions dsrOptions, FrameGraphId const input,
+ filament::Viewport const& vp, FrameGraphTexture::Descriptor const& outDesc) noexcept {
+
const bool twoPassesEASU = mWorkaroundSplitEasu &&
(dsrOptions.quality == QualityLevel::MEDIUM
|| dsrOptions.quality == QualityLevel::HIGH);
@@ -2964,7 +3116,7 @@ FrameGraphId PostProcessManager::upscale(FrameGraph& fg, bool
.attachments = { .color = { data.output }, .depth = { data.depth }},
.clearFlags = TargetBufferFlags::DEPTH });
},
- [this, twoPassesEASU, dsrOptions, vp, translucent, filter](FrameGraphResources const& resources,
+ [this, twoPassesEASU, dsrOptions, vp](FrameGraphResources const& resources,
auto const& data, DriverApi& driver) {
bindPostProcessDescriptorSet(driver);
@@ -2989,14 +3141,6 @@ FrameGraphId PostProcessManager::upscale(FrameGraph& fg, bool
float2{ inputDesc.width, inputDesc.height });
};
- // helper to enable blending
- auto enableTranslucentBlending = [](PipelineState& pipeline) {
- pipeline.rasterState.blendFunctionSrcRGB = BlendFunction::ONE;
- pipeline.rasterState.blendFunctionSrcAlpha = BlendFunction::ONE;
- pipeline.rasterState.blendFunctionDstRGB = BlendFunction::ONE_MINUS_SRC_ALPHA;
- pipeline.rasterState.blendFunctionDstAlpha = BlendFunction::ONE_MINUS_SRC_ALPHA;
- };
-
auto color = resources.getTexture(data.input);
auto const& inputDesc = resources.getDescriptor(data.input);
auto const& outputDesc = resources.getDescriptor(data.output);
@@ -3023,29 +3167,21 @@ FrameGraphId PostProcessManager::upscale(FrameGraph& fg, bool
}
{ // just a scope to not leak local variables
- const std::string_view blitterNames[4] = {
- "blitLow", "fsr_easu_mobile", "fsr_easu_mobile", "fsr_easu" };
- unsigned const index = std::min(3u, unsigned(dsrOptions.quality));
+ const std::string_view blitterNames[2] = { "fsr_easu_mobile", "fsr_easu" };
+ unsigned const index = std::min(1u, unsigned(dsrOptions.quality) - 2);
easuMaterial = &getPostProcessMaterial(blitterNames[index]);
FMaterialInstance* const mi =
PostProcessMaterial::getMaterialInstance(mEngine, *easuMaterial);
- if (dsrOptions.quality != QualityLevel::LOW) {
- setEasuUniforms(mi, inputDesc, outputDesc);
- }
+
+ setEasuUniforms(mi, inputDesc, outputDesc);
+
mi->setParameter("color", color, {
- .filterMag = (dsrOptions.quality == QualityLevel::LOW) ?
- filter : SamplerMagFilter::LINEAR
+ .filterMag = SamplerMagFilter::LINEAR
});
- if (blitterNames[index] != "blitLow") {
- mi->setParameter("resolution",
- float4{outputDesc.width, outputDesc.height, 1.0f / outputDesc.width,
- 1.0f / outputDesc.height});
- }
-
- if (blitterNames[index] == "blitLow") {
- mi->setParameter("levelOfDetail", 0.0f);
- }
+ mi->setParameter("resolution",
+ float4{outputDesc.width, outputDesc.height, 1.0f / outputDesc.width,
+ 1.0f / outputDesc.height});
mi->setParameter("viewport", float4{
float(vp.left) / inputDesc.width,
@@ -3066,29 +3202,19 @@ FrameGraphId PostProcessManager::upscale(FrameGraph& fg, bool
auto pipeline0 = getPipelineState(splitEasuMaterial->getMaterial(mEngine));
auto pipeline1 = getPipelineState(easuMaterial->getMaterial(mEngine));
pipeline1.rasterState.depthFunc = SamplerCompareFunc::NE;
- if (translucent) {
- enableTranslucentBlending(pipeline0);
- enableTranslucentBlending(pipeline1);
- }
driver.beginRenderPass(out.target, out.params);
driver.draw(pipeline0, mFullScreenQuadRph, 0, 3, 1);
driver.draw(pipeline1, mFullScreenQuadRph, 0, 3, 1);
driver.endRenderPass();
} else {
auto pipeline = getPipelineState(easuMaterial->getMaterial(mEngine));
- if (translucent) {
- enableTranslucentBlending(pipeline);
- }
renderFullScreenQuad(out, pipeline, driver);
}
});
auto output = ppQuadBlit->output;
-
- // if we had to take the low quality fallback, we still do the "sharpen pass"
- if (dsrOptions.sharpness > 0.0f &&
- (dsrOptions.quality != QualityLevel::LOW || lowQualityFallback)) {
- output = rcas(fg, dsrOptions.sharpness, output, outDesc, translucent);
+ if (dsrOptions.sharpness > 0.0f) {
+ output = rcas(fg, dsrOptions.sharpness, output, outDesc, false);
}
// we rely on automatic culling of unused render passes
diff --git a/filament/src/PostProcessManager.h b/filament/src/PostProcessManager.h
index c435cdccd9..677cec30cb 100644
--- a/filament/src/PostProcessManager.h
+++ b/filament/src/PostProcessManager.h
@@ -89,7 +89,7 @@ public:
bool asSubpass{};
bool customResolve{};
bool translucent{};
- bool fxaa{};
+ bool outputLuminance{}; // Whether to output luminance in the alpha channel. Ignored by the TRANSLUCENT variant.
bool dithering{};
backend::TextureFormat ldrFormat{};
};
@@ -227,7 +227,7 @@ public:
// Anti-aliasing
FrameGraphId fxaa(FrameGraph& fg,
FrameGraphId input, Viewport const& vp,
- backend::TextureFormat outFormat, bool translucent) noexcept;
+ backend::TextureFormat outFormat, bool preserveAlphaChannel) noexcept;
// Temporal Anti-aliasing
void TaaJitterCamera(
@@ -251,12 +251,25 @@ public:
// high quality upscaler
// - when translucent, reverts to LINEAR
- // - doens't handle sub-resouces
+ // - doesn't handle sub-resouces
FrameGraphId upscale(FrameGraph& fg, bool translucent,
+ bool sourceHasLuminance, DynamicResolutionOptions dsrOptions,
+ FrameGraphId input, Viewport const& vp,
+ FrameGraphTexture::Descriptor const& outDesc, backend::SamplerMagFilter filter) noexcept;
+
+ FrameGraphId upscaleBilinear(FrameGraph& fg, bool translucent,
DynamicResolutionOptions dsrOptions, FrameGraphId input,
Viewport const& vp, FrameGraphTexture::Descriptor const& outDesc,
backend::SamplerMagFilter filter) noexcept;
+ FrameGraphId upscaleFSR1(FrameGraph& fg,
+ DynamicResolutionOptions dsrOptions, FrameGraphId input,
+ filament::Viewport const& vp, FrameGraphTexture::Descriptor const& outDesc) noexcept;
+
+ FrameGraphId upscaleSGSR1(FrameGraph& fg, bool sourceHasLuminance,
+ DynamicResolutionOptions dsrOptions, FrameGraphId input,
+ filament::Viewport const& vp, FrameGraphTexture::Descriptor const& outDesc) noexcept;
+
FrameGraphId rcas(
FrameGraph& fg,
float sharpness,
diff --git a/filament/src/details/Renderer.cpp b/filament/src/details/Renderer.cpp
index 6057c92a52..186c6249c7 100644
--- a/filament/src/details/Renderer.cpp
+++ b/filament/src/details/Renderer.cpp
@@ -681,6 +681,9 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
hasColorGrading &&
!bloomOptions.enabled && !dofOptions.enabled && !taaOptions.enabled;
+ // whether we're scaled at all
+ bool scaled = any(notEqual(scale, float2(1.0f)));
+
// asSubpass is disabled with TAA (although it's supported) because performance was degraded
// on qualcomm hardware -- we might need a backend dependent toggle at some point
const PostProcessManager::ColorGradingConfig colorGradingConfig{
@@ -695,18 +698,15 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
hasColorGrading &&
!engine.debug.renderer.disable_subpasses,
.translucent = needsAlphaChannel,
- .fxaa = hasFXAA,
+ .outputLuminance = hasFXAA || scaled, // ignored by translucent variants (false)
.dithering = hasDithering,
- .ldrFormat = (hasColorGrading && hasFXAA) ?
+ .ldrFormat = (hasColorGrading && (hasFXAA || scaled)) ?
TextureFormat::RGBA8 : getLdrFormat(needsAlphaChannel)
};
// by construction (msaaSampleCount) both asSubpass and customResolve can't be true
assert_invariant(colorGradingConfig.asSubpass + colorGradingConfig.customResolve < 2);
- // whether we're scaled at all
- bool scaled = any(notEqual(scale, float2(1.0f)));
-
// vp is the user defined viewport within the View
filament::Viewport const& vp = view.getViewport();
@@ -1351,8 +1351,9 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
}
if (hasFXAA) {
- input = ppm.fxaa(fg, input, xvp, colorGradingConfig.ldrFormat,
- !hasColorGrading || needsAlphaChannel);
+ bool const preserveAlphaChannel = needsAlphaChannel ||
+ (hasColorGrading && colorGradingConfig.outputLuminance);
+ input = ppm.fxaa(fg, input, xvp, colorGradingConfig.ldrFormat, preserveAlphaChannel);
// the padded buffer is resolved now
xvp.left = xvp.bottom = 0;
svp = xvp;
@@ -1360,9 +1361,11 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
if (scaled) {
mightNeedFinalBlit = false;
auto viewport = DEBUG_DYNAMIC_SCALING ? xvp : vp;
- input = ppm.upscale(fg, needsAlphaChannel, dsrOptions, input, xvp, {
- .width = viewport.width, .height = viewport.height,
- .format = colorGradingConfig.ldrFormat }, SamplerMagFilter::LINEAR);
+ bool const sourceHasLuminance = !needsAlphaChannel &&
+ (hasColorGrading && colorGradingConfig.outputLuminance);
+ input = ppm.upscale(fg, needsAlphaChannel, sourceHasLuminance, dsrOptions, input, xvp, {
+ .width = viewport.width, .height = viewport.height,
+ .format = colorGradingConfig.ldrFormat }, SamplerMagFilter::LINEAR);
xvp.left = xvp.bottom = 0;
svp = xvp;
}
diff --git a/filament/src/materials/colorGrading/colorGrading.mat b/filament/src/materials/colorGrading/colorGrading.mat
index 7667b42d9b..83712beafe 100644
--- a/filament/src/materials/colorGrading/colorGrading.mat
+++ b/filament/src/materials/colorGrading/colorGrading.mat
@@ -41,7 +41,7 @@ material {
},
{
type : int,
- name : fxaa
+ name : outputLuminance
},
{
type : float,
@@ -166,10 +166,10 @@ void postProcess(inout PostProcessInputs postProcess) {
color = dither(color, materialParams.temporalNoise);
}
- // kill alpha computations when opaque / fxaa luminance
+ // kill alpha computations when opaque / luminance
#if POST_PROCESS_OPAQUE
color.a = 1.0;
- if (materialParams.fxaa > 0) {
+ if (materialParams.outputLuminance > 0) {
color.a = luminance(color.rgb);
}
#endif
diff --git a/filament/src/materials/sgsr/LICENSE.txt b/filament/src/materials/sgsr/LICENSE.txt
new file mode 100644
index 0000000000..d9d513c758
--- /dev/null
+++ b/filament/src/materials/sgsr/LICENSE.txt
@@ -0,0 +1,29 @@
+Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+SPDX-License-Identifier: BSD-3-Clause
\ No newline at end of file
diff --git a/filament/src/materials/sgsr/sgsr1.mat b/filament/src/materials/sgsr/sgsr1.mat
new file mode 100644
index 0000000000..38fe23fc02
--- /dev/null
+++ b/filament/src/materials/sgsr/sgsr1.mat
@@ -0,0 +1,80 @@
+material {
+ name : sgsr1,
+ parameters : [
+ {
+ type : sampler2d,
+ name : color,
+ precision: medium
+ },
+ {
+ type : float4,
+ name : viewport,
+ precision: high
+ }
+ ],
+ variables : [
+ vertex
+ ],
+ depthWrite : false,
+ depthCulling : false,
+ domain: postprocess
+}
+
+vertex {
+ void postProcessVertex(inout PostProcessVertexInputs postProcess) {
+ postProcess.normalizedUV = uvToRenderTargetUV(postProcess.normalizedUV);
+ postProcess.vertex.xy = postProcess.normalizedUV;
+ }
+}
+
+fragment {
+
+ void dummy(){}
+
+ precision mediump float;
+ precision highp int;
+
+#if defined(FILAMENT_HAS_FEATURE_TEXTURE_GATHER)
+ #define gather textureGather
+#else
+ vec4 gather(const mediump sampler2D color, highp vec2 p, const int comp) {
+ highp ivec2 i = ivec2(p * materialParams.viewport.zw - 0.5);
+ vec4 d;
+ d[0] = texelFetchOffset(color, i, 0, ivec2(0, 1))[comp];
+ d[1] = texelFetchOffset(color, i, 0, ivec2(1, 1))[comp];
+ d[2] = texelFetchOffset(color, i, 0, ivec2(1, 0))[comp];
+ d[3] = texelFetchOffset(color, i, 0, ivec2(0, 0))[comp];
+ return d;
+ }
+#endif
+
+/*
+* Operation modes:
+* RGBA -> 1
+* RGBY -> 3
+* LERP -> 4
+*/
+
+// SGSR cannot support translucency;
+// So we hijack the POST_PROCESS variant to select whether a luminance channel is present
+#if POST_PROCESS_OPAQUE
+# define OperationMode 1
+#else
+# define OperationMode 3
+#endif
+
+/*
+* If set, will use edge direction to improve visual quality
+* Expect a minimal cost increase
+*/
+#define UseEdgeDirection
+#define EdgeThreshold 8.0 / 255.0
+#define EdgeSharpness 2.0
+
+#include "sgsr1_shader_mobile.fs"
+
+ void postProcess(inout PostProcessInputs postProcess) {
+ highp vec4 vp[1] = vec4[1]( materialParams.viewport );
+ postProcess.color = sgsr(materialParams_color, variable_vertex.xy, vp);
+ }
+}
diff --git a/filament/src/materials/sgsr/sgsr1_shader_mobile.fs b/filament/src/materials/sgsr/sgsr1_shader_mobile.fs
new file mode 100644
index 0000000000..edc937f4ad
--- /dev/null
+++ b/filament/src/materials/sgsr/sgsr1_shader_mobile.fs
@@ -0,0 +1,132 @@
+//============================================================================================================
+//
+//
+// Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
+// SPDX-License-Identifier: BSD-3-Clause
+//
+//============================================================================================================
+
+////////////////////////
+// USER CONFIGURATION //
+////////////////////////
+
+float fastLanczos2(float x)
+{
+ float wA = x-4.0;
+ float wB = x*wA-wA;
+ wA *= wA;
+ return wB*wA;
+}
+
+#if defined(UseEdgeDirection)
+vec2 weightY(float dx, float dy, float c, vec3 data)
+#else
+vec2 weightY(float dx, float dy, float c, float data)
+#endif
+{
+#if defined(UseEdgeDirection)
+ float std = data.x;
+ vec2 dir = data.yz;
+
+ float edgeDis = ((dx*dir.y)+(dy*dir.x));
+ float x = (((dx*dx)+(dy*dy))+((edgeDis*edgeDis)*((clamp(((c*c)*std),0.0,1.0)*0.7)+-1.0)));
+#else
+ float std = data;
+ float x = ((dx*dx)+(dy*dy))* 0.55 + clamp(abs(c)*std, 0.0, 1.0);
+#endif
+
+ float w = fastLanczos2(x);
+ return vec2(w, w * c);
+}
+
+vec2 edgeDirection(vec4 left, vec4 right)
+{
+ vec2 dir;
+ float RxLz = (right.x + (-left.z));
+ float RwLy = (right.w + (-left.y));
+ vec2 delta;
+ delta.x = (RxLz + RwLy);
+ delta.y = (RxLz + (-RwLy));
+ float lengthInv = inversesqrt((delta.x * delta.x+ 3.075740e-05) + (delta.y * delta.y));
+ dir.x = (delta.x * lengthInv);
+ dir.y = (delta.y * lengthInv);
+ return dir;
+}
+
+vec4 sgsr(mediump sampler2D ps0, highp vec2 in_TEXCOORD0, highp vec4 ViewportInfo[1])
+{
+ vec4 color;
+ if(OperationMode == 1)
+ color.xyz = textureLod(ps0,in_TEXCOORD0.xy,0.0).xyz;
+ else
+ color.xyzw = textureLod(ps0,in_TEXCOORD0.xy,0.0).xyzw;
+
+#if OperationMode != 4
+ if (OperationMode!=4)
+ {
+ highp vec2 imgCoord = ((in_TEXCOORD0.xy*ViewportInfo[0].zw)+vec2(-0.5,0.5));
+ highp vec2 imgCoordPixel = floor(imgCoord);
+ highp vec2 coord = (imgCoordPixel*ViewportInfo[0].xy);
+ vec2 pl = (imgCoord+(-imgCoordPixel));
+ vec4 left = gather(ps0,coord, OperationMode);
+
+ float edgeVote = abs(left.z - left.y) + abs(color[OperationMode] - left.y) + abs(color[OperationMode] - left.z) ;
+ if(edgeVote > EdgeThreshold)
+ {
+ coord.x += ViewportInfo[0].x;
+
+ vec4 right = gather(ps0,coord + vec2(ViewportInfo[0].x, 0.0), OperationMode);
+ vec4 upDown;
+ upDown.xy = gather(ps0,coord + vec2(0.0, -ViewportInfo[0].y),OperationMode).wz;
+ upDown.zw = gather(ps0,coord+ vec2(0.0, ViewportInfo[0].y), OperationMode).yx;
+
+ float mean = (left.y+left.z+right.x+right.w)*0.25;
+ left = left - vec4(mean);
+ right = right - vec4(mean);
+ upDown = upDown - vec4(mean);
+ color.w = color[OperationMode] - mean;
+
+ float sum = (((((abs(left.x)+abs(left.y))+abs(left.z))+abs(left.w)) +
+ (((abs(right.x)+abs(right.y))+abs(right.z))+abs(right.w))) +
+ (((abs(upDown.x)+abs(upDown.y))+abs(upDown.z))+abs(upDown.w)));
+
+#if defined(UseEdgeDirection)
+ float sumMean = 1.014185e+01 / sum;
+ float std = (sumMean * sumMean);
+ vec3 data = vec3(std, edgeDirection(left, right));
+#else
+ // taken from sgsr sample
+ float data = 2.181818 / sum;
+#endif
+
+ vec2 aWY = weightY(pl.x, pl.y+1.0, upDown.x,data);
+ aWY += weightY(pl.x-1.0, pl.y+1.0, upDown.y,data);
+ aWY += weightY(pl.x-1.0, pl.y-2.0, upDown.z,data);
+ aWY += weightY(pl.x, pl.y-2.0, upDown.w,data);
+ aWY += weightY(pl.x+1.0, pl.y-1.0, left.x,data);
+ aWY += weightY(pl.x, pl.y-1.0, left.y,data);
+ aWY += weightY(pl.x, pl.y, left.z,data);
+ aWY += weightY(pl.x+1.0, pl.y, left.w,data);
+ aWY += weightY(pl.x-1.0, pl.y-1.0, right.x,data);
+ aWY += weightY(pl.x-2.0, pl.y-1.0, right.y,data);
+ aWY += weightY(pl.x-2.0, pl.y, right.z,data);
+ aWY += weightY(pl.x-1.0, pl.y, right.w,data);
+
+ float finalY = aWY.y/aWY.x;
+ float maxY = max(max(left.y,left.z),max(right.x,right.w));
+ float minY = min(min(left.y,left.z),min(right.x,right.w));
+ float deltaY = clamp(EdgeSharpness*finalY, minY, maxY) -color.w;
+
+ //smooth high contrast input
+ deltaY = clamp(deltaY, -23.0 / 255.0, 23.0 / 255.0);
+
+ color.x = clamp(color.x+deltaY, 0.0, 1.0);
+ color.y = clamp(color.y+deltaY, 0.0, 1.0);
+ color.z = clamp(color.z+deltaY, 0.0, 1.0);
+ }
+ }
+#endif
+
+ color.w = 1.0; //assume alpha channel is not used
+ return color;
+}
\ No newline at end of file
From 4465e6c7f6eb6f7a81f21bc0db880782e89fb53d Mon Sep 17 00:00:00 2001
From: Evan Mezeske
Date: Mon, 27 Jan 2025 11:34:44 -0700
Subject: [PATCH 6/8] Remove noexcept from UserPanicHandler::call() so that
panic handlers can throw. Without this change, throwing inside the user panic
handler calls terminate(). Note that the docs for setPanicHandler()
explicitly say that it's okay for the handler to throw, which is not true
prior to this change.
---
libs/utils/src/Panic.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libs/utils/src/Panic.cpp b/libs/utils/src/Panic.cpp
index 1b8921ac06..e0aec064fa 100644
--- a/libs/utils/src/Panic.cpp
+++ b/libs/utils/src/Panic.cpp
@@ -43,7 +43,7 @@ class UserPanicHandler {
struct CallBack {
Panic::PanicHandlerCallback handler = nullptr;
void* user = nullptr;
- void call(Panic const& panic) const noexcept {
+ void call(Panic const& panic) const {
if (UTILS_UNLIKELY(handler)) {
handler(user, panic);
}
@@ -64,7 +64,7 @@ public:
return data;
}
- void call(Panic const& panic) const noexcept {
+ void call(Panic const& panic) const {
getCallback().call(panic);
}
From 41f7dc384b0b37941f5943fa2166df1a65aa0bbe Mon Sep 17 00:00:00 2001
From: Mathias Agopian
Date: Thu, 23 Jan 2025 14:24:16 -0800
Subject: [PATCH 7/8] add a version of Engine::flushAndWait that takes a
timeout
The old version that doesn't take a timeout now always waits forever;
before it waited for a few seconds on Android debug builds.
The new version has an explicit timeout that works on all platforms and
returns success status.
FIXES=[384043020]
---
.../filament-android/src/main/cpp/Engine.cpp | 6 +--
.../com/google/android/filament/Engine.java | 25 ++++++++++-
filament/include/filament/Engine.h | 19 +++++++++
filament/src/Engine.cpp | 4 ++
filament/src/details/Engine.cpp | 42 +++++--------------
filament/src/details/Engine.h | 1 +
6 files changed, 60 insertions(+), 37 deletions(-)
diff --git a/android/filament-android/src/main/cpp/Engine.cpp b/android/filament-android/src/main/cpp/Engine.cpp
index 56aecc66dd..d6e941209b 100644
--- a/android/filament-android/src/main/cpp/Engine.cpp
+++ b/android/filament-android/src/main/cpp/Engine.cpp
@@ -392,11 +392,11 @@ Java_com_google_android_filament_Engine_nIsValidSwapChain(JNIEnv*, jclass,
return (jboolean)engine->isValid((SwapChain*)nativeSwapChain);
}
-extern "C" JNIEXPORT void JNICALL
+extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_Engine_nFlushAndWait(JNIEnv*, jclass,
- jlong nativeEngine) {
+ jlong nativeEngine, jlong timeout) {
Engine* engine = (Engine*) nativeEngine;
- engine->flushAndWait();
+ return engine->flushAndWait((uint64_t)timeout);
}
extern "C" JNIEXPORT void JNICALL
diff --git a/android/filament-android/src/main/java/com/google/android/filament/Engine.java b/android/filament-android/src/main/java/com/google/android/filament/Engine.java
index 1e49bf54a3..e73e82944c 100644
--- a/android/filament-android/src/main/java/com/google/android/filament/Engine.java
+++ b/android/filament-android/src/main/java/com/google/android/filament/Engine.java
@@ -1271,7 +1271,28 @@ public class Engine {
* {@link android.view.SurfaceHolder.Callback#surfaceDestroyed surfaceDestroyed}.
*/
public void flushAndWait() {
- nFlushAndWait(getNativeObject());
+ flushAndWait(Fence.WAIT_FOR_EVER);
+ }
+
+ /**
+ * Kicks the hardware thread (e.g. the OpenGL, Vulkan or Metal thread) and blocks until
+ * all commands to this point are executed. Note that does guarantee that the
+ * hardware is actually finished.
+ *
+ * A timeout can be specified, if for some reason this flushAndWait doesn't complete before the timeout, it will
+ * return false, true otherwise.
+ *
+ * This is typically used right after destroying the SwapChain,
+ * in cases where a guarantee about the SwapChain destruction is needed in a
+ * timely fashion, such as when responding to Android's
+ * android.view.SurfaceHolder.Callback.surfaceDestroyed
+ *
+ * @param timeout A timeout in nanoseconds
+ * @return true if successful, false if flushAndWait timed out, in which case it wasn't successful and commands
+ * might still be executing on both the CPU and GPU sides.
+ */
+ public boolean flushAndWait(long timeout) {
+ return nFlushAndWait(getNativeObject(), timeout);
}
/**
@@ -1437,7 +1458,7 @@ public class Engine {
private static native boolean nIsValidRenderTarget(long nativeEngine, long nativeTarget);
private static native boolean nIsValidSwapChain(long nativeEngine, long nativeSwapChain);
private static native void nDestroyEntity(long nativeEngine, int entity);
- private static native void nFlushAndWait(long nativeEngine);
+ private static native boolean nFlushAndWait(long nativeEngine, long timeout);
private static native void nFlush(long nativeEngine);
private static native boolean nIsPaused(long nativeEngine);
private static native void nSetPaused(long nativeEngine, boolean paused);
diff --git a/filament/include/filament/Engine.h b/filament/include/filament/Engine.h
index 8fb44af5dc..5092e16c38 100644
--- a/filament/include/filament/Engine.h
+++ b/filament/include/filament/Engine.h
@@ -970,6 +970,25 @@ public:
*/
void flushAndWait();
+ /**
+ * Kicks the hardware thread (e.g. the OpenGL, Vulkan or Metal thread) and blocks until
+ * all commands to this point are executed. Note that does guarantee that the
+ * hardware is actually finished.
+ *
+ * A timeout can be specified, if for some reason this flushAndWait doesn't complete before the timeout, it will
+ * return false, true otherwise.
+ *
+ * This is typically used right after destroying the SwapChain,
+ * in cases where a guarantee about the SwapChain destruction is needed in a
+ * timely fashion, such as when responding to Android's
+ * android.view.SurfaceHolder.Callback.surfaceDestroyed
+ *
+ * @param timeout A timeout in nanoseconds
+ * @return true if successful, false if flushAndWait timed out, in which case it wasn't successful and commands
+ * might still be executing on both the CPU and GPU sides.
+ */
+ bool flushAndWait(uint64_t timeout);
+
/**
* Kicks the hardware thread (e.g. the OpenGL, Vulkan or Metal thread) but does not wait
* for commands to be either executed or the hardware finished.
diff --git a/filament/src/Engine.cpp b/filament/src/Engine.cpp
index 5f1af80aaf..455067739c 100644
--- a/filament/src/Engine.cpp
+++ b/filament/src/Engine.cpp
@@ -338,6 +338,10 @@ void Engine::flushAndWait() {
downcast(this)->flushAndWait();
}
+bool Engine::flushAndWait(uint64_t timeout) {
+ return downcast(this)->flushAndWait(timeout);
+}
+
void Engine::flush() {
downcast(this)->flush();
}
diff --git a/filament/src/details/Engine.cpp b/filament/src/details/Engine.cpp
index 1cc9a951be..2116fae4c1 100644
--- a/filament/src/details/Engine.cpp
+++ b/filament/src/details/Engine.cpp
@@ -665,50 +665,28 @@ void FEngine::flush() {
}
void FEngine::flushAndWait() {
- FILAMENT_CHECK_PRECONDITION(!mCommandBufferQueue.isPaused())
- << "Cannot call flushAndWait() when rendering thread is paused!";
+ flushAndWait(FENCE_WAIT_FOR_EVER);
+}
-#if defined(__ANDROID__)
+bool FEngine::flushAndWait(uint64_t timeout) {
+ FILAMENT_CHECK_PRECONDITION(!mCommandBufferQueue.isPaused())
+ << "Cannot call Engine::flushAndWait() when rendering thread is paused!";
// first make sure we've not terminated filament
FILAMENT_CHECK_PRECONDITION(!mCommandBufferQueue.isExitRequested())
- << "calling Engine::flushAndWait() after Engine::shutdown()!";
-
-#endif
+ << "Calling Engine::flushAndWait() after Engine::shutdown()!";
// enqueue finish command -- this will stall in the driver until the GPU is done
getDriverApi().finish();
-#if defined(__ANDROID__) && !defined(NDEBUG)
-
- // then create a fence that will trigger when we're past the finish() above
- size_t tryCount = 8;
- FFence* fence = FEngine::createFence();
- UTILS_NOUNROLL
- do {
- FenceStatus status = fence->wait(FFence::Mode::FLUSH,250000000u);
- // if the fence didn't trigger after 250ms, check that the command queue thread is still
- // running (otherwise indicating a precondition violation).
- if (UTILS_UNLIKELY(status == FenceStatus::TIMEOUT_EXPIRED)) {
- FILAMENT_CHECK_PRECONDITION(!mCommandBufferQueue.isExitRequested())
- << "called Engine::shutdown() WHILE in Engine::flushAndWait()!";
- tryCount--;
- FILAMENT_CHECK_POSTCONDITION(tryCount) << "flushAndWait() failed inexplicably after 2s";
- // if the thread is still running, maybe we just need to give it more time
- continue;
- }
- break;
- } while (true);
+ FFence* fence = createFence();
+ FenceStatus const status = fence->wait(FFence::Mode::FLUSH, timeout);
destroy(fence);
-#else
-
- FFence::waitAndDestroy(createFence(), FFence::Mode::FLUSH);
-
-#endif
-
// finally, execute callbacks that might have been scheduled
getDriver().purge();
+
+ return status == FenceStatus::CONDITION_SATISFIED;
}
// -----------------------------------------------------------------------------------------------
diff --git a/filament/src/details/Engine.h b/filament/src/details/Engine.h
index d52907dc76..28376a5b6b 100644
--- a/filament/src/details/Engine.h
+++ b/filament/src/details/Engine.h
@@ -394,6 +394,7 @@ public:
void setPaused(bool paused);
void flushAndWait();
+ bool flushAndWait(uint64_t timeout);
// flush the current buffer
void flush();
From f1c1aa155bd5530ca9374a3f9a90060fc6af02df Mon Sep 17 00:00:00 2001
From: Benjamin Doherty
Date: Wed, 29 Jan 2025 16:41:10 -0800
Subject: [PATCH 8/8] Release Filament 1.56.7
---
README.md | 4 ++--
RELEASE_NOTES.md | 3 +++
android/gradle.properties | 2 +-
ios/CocoaPods/Filament.podspec | 4 ++--
web/filament-js/package.json | 2 +-
5 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/README.md b/README.md
index 5cd0c006c5..625dd40c3a 100644
--- a/README.md
+++ b/README.md
@@ -31,7 +31,7 @@ repositories {
}
dependencies {
- implementation 'com.google.android.filament:filament-android:1.56.6'
+ implementation 'com.google.android.filament:filament-android:1.56.7'
}
```
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
iOS projects can use CocoaPods to install the latest release:
```shell
-pod 'Filament', '~> 1.56.6'
+pod 'Filament', '~> 1.56.7'
```
## Documentation
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index ffccaa339a..09643b5d20 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -7,6 +7,9 @@ A new header is inserted each time a *tag* is created.
Instead, if you are authoring a PR for the main branch, add your release note to
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
+## v1.56.8
+
+
## v1.56.7
diff --git a/android/gradle.properties b/android/gradle.properties
index e4f778ef79..d1baf95447 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
-VERSION_NAME=1.56.6
+VERSION_NAME=1.56.7
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
diff --git a/ios/CocoaPods/Filament.podspec b/ios/CocoaPods/Filament.podspec
index 1133525c5a..e5e319aab0 100644
--- a/ios/CocoaPods/Filament.podspec
+++ b/ios/CocoaPods/Filament.podspec
@@ -1,12 +1,12 @@
Pod::Spec.new do |spec|
spec.name = "Filament"
- spec.version = "1.56.6"
+ spec.version = "1.56.7"
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
spec.homepage = "https://google.github.io/filament"
spec.authors = "Google LLC."
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
spec.platform = :ios, "11.0"
- spec.source = { :http => "https://github.com/google/filament/releases/download/v1.56.6/filament-v1.56.6-ios.tgz" }
+ spec.source = { :http => "https://github.com/google/filament/releases/download/v1.56.7/filament-v1.56.7-ios.tgz" }
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
spec.pod_target_xcconfig = {
diff --git a/web/filament-js/package.json b/web/filament-js/package.json
index 3a8340976c..36a97d6c37 100644
--- a/web/filament-js/package.json
+++ b/web/filament-js/package.json
@@ -1,6 +1,6 @@
{
"name": "filament",
- "version": "1.56.6",
+ "version": "1.56.7",
"description": "Real-time physically based rendering engine",
"main": "filament.js",
"module": "filament.js",