diff --git a/.github/workflows/presubmit.yml b/.github/workflows/presubmit.yml
index 28479f236d..e4fa3c129c 100644
--- a/.github/workflows/presubmit.yml
+++ b/.github/workflows/presubmit.yml
@@ -77,9 +77,22 @@ jobs:
run: |
cd build/web && printf "y" | ./build.sh presubmit
+ validate-docs:
+ name: validate-docs
+ runs-on: ubuntu-22.04-4core
+ steps:
+ - uses: actions/checkout@v4.1.6
+ with:
+ fetch-depth: 0
+ - name: Check for manual edits to /docs
+ run: |
+ echo "${{ github.event.pull_request.head.sha }} -- ${{ github.event.pull_request.head.sha }}"
+ # disable for now
+ # bash docs_src/build/presubmit_check.sh ${{ github.event.pull_request.head.sha }}
+
test-renderdiff:
name: test-renderdiff
- runs-on: ubuntu-22.04-32core
+ runs-on: ubuntu-22.04-16core
steps:
- uses: actions/checkout@v4.1.6
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b8462d29f1..f9de5b2a5e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -457,10 +457,19 @@ if (NOT WEBGL)
set(GC_SECTIONS "-Wl,--gc-sections")
endif()
+# Prevents stacks from being made for executable by explicitly adding this linker flag. Otherwise,
+# it generates warnings newly introduced as of GNU LD 2.39. Modern security practices strongly
+# recommend marking the stack as non-executable using the -z noexecstack linker flag to prevent
+# stack-based buffer overflow exploits.
+# See: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=ffcf9c5700e49c0aee42dcba9a12ba21338e8136
+if (LINUX)
+ set(NO_EXEC_STACK "-Wl,-z,noexecstack")
+endif()
+
set(B_SYMBOLIC_FUNCTIONS "-Wl,-Bsymbolic-functions")
if (ANDROID)
-set(BINARY_ALIGNMENT "-Wl,-z,max-page-size=16384")
+ set(BINARY_ALIGNMENT "-Wl,-z,max-page-size=16384")
endif()
if (APPLE)
@@ -475,7 +484,7 @@ if (APPLE)
set(CMAKE_CXX_ARCHIVE_CREATE " qc -S ")
endif()
-set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GC_SECTIONS}")
+set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GC_SECTIONS} ${NO_EXEC_STACK}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${GC_SECTIONS} ${B_SYMBOLIC_FUNCTIONS} ${BINARY_ALIGNMENT}")
if (WEBGL_PTHREADS)
diff --git a/CODE_STYLE.md b/CODE_STYLE.md
index 0a1e785726..41233f2792 100644
--- a/CODE_STYLE.md
+++ b/CODE_STYLE.md
@@ -121,9 +121,21 @@ private:
- other headers are sorted in reverse order of their layering, that is, lower layer headers last
- within a layer, headers are sorted alphabetically
- strive for implementing one class per file
-- `STL` limited in public headers to:
- - `type_traits`
+- `STL` limited in **filament** public headers to:
+ - `array`
+ - `initializer_list`
+ - `iterator`
- `limits`
+ - `optional`
+ - `type_traits`
+ - `utility`
+ - `variant`
+
+For **libfilament** the rule of thumb is that STL headers that don't generate code are allowed (e.g. `type_traits`),
+conversely containers and algorithms are not allowed. There are exceptions such as `array`. See above for the full list.
+- The following `STL` headers are banned entirely, from public and private headers as well as implementation files:
+ - `iostream`
+
*Sorting the headers is important to help catching missing `#include` directives.*
diff --git a/README.md b/README.md
index 625dd40c3a..914a1f3dba 100644
--- a/README.md
+++ b/README.md
@@ -31,7 +31,7 @@ repositories {
}
dependencies {
- implementation 'com.google.android.filament:filament-android:1.56.7'
+ implementation 'com.google.android.filament:filament-android:1.56.8'
}
```
@@ -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.7'
+pod 'Filament', '~> 1.56.8'
```
## 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/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/cpp/RenderableManager.cpp b/android/filament-android/src/main/cpp/RenderableManager.cpp
index 4f38e46f82..d9b56e02fb 100644
--- a/android/filament-android/src/main/cpp/RenderableManager.cpp
+++ b/android/filament-android/src/main/cpp/RenderableManager.cpp
@@ -459,6 +459,13 @@ Java_com_google_android_filament_RenderableManager_nSetMaterialInstanceAt(JNIEnv
materialInstance);
}
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_android_filament_RenderableManager_nClearMaterialInstanceAt(JNIEnv*, jclass,
+ jlong nativeRenderableManager, jint i, jint primitiveIndex) {
+ RenderableManager *rm = (RenderableManager *) nativeRenderableManager;
+ rm->clearMaterialInstanceAt((RenderableManager::Instance) i, (size_t) primitiveIndex);
+}
+
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_RenderableManager_nGetMaterialInstanceAt(JNIEnv*, jclass,
jlong nativeRenderableManager, jint i, jint primitiveIndex) {
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..392497461b 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());
+ boolean unused = 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/android/filament-android/src/main/java/com/google/android/filament/RenderableManager.java b/android/filament-android/src/main/java/com/google/android/filament/RenderableManager.java
index 0da9a0d6e7..81053197c5 100644
--- a/android/filament-android/src/main/java/com/google/android/filament/RenderableManager.java
+++ b/android/filament-android/src/main/java/com/google/android/filament/RenderableManager.java
@@ -869,6 +869,13 @@ public class RenderableManager {
nSetMaterialInstanceAt(mNativeObject, i, primitiveIndex, materialInstance.getNativeObject());
}
+ /**
+ * Clears the material instance for the given primitive.
+ */
+ public void clearMaterialInstanceAt(@EntityInstance int i, @IntRange(from = 0) int primitiveIndex) {
+ nClearMaterialInstanceAt(mNativeObject, i, primitiveIndex);
+ }
+
/**
* Creates a MaterialInstance Java wrapper object for a particular material instance.
*/
@@ -1012,6 +1019,7 @@ public class RenderableManager {
private static native void nGetAxisAlignedBoundingBox(long nativeRenderableManager, int i, float[] center, float[] halfExtent);
private static native int nGetPrimitiveCount(long nativeRenderableManager, int i);
private static native void nSetMaterialInstanceAt(long nativeRenderableManager, int i, int primitiveIndex, long nativeMaterialInstance);
+ private static native void nClearMaterialInstanceAt(long nativeRenderableManager, int i, int primitiveIndex);
private static native long nGetMaterialInstanceAt(long nativeRenderableManager, int i, int primitiveIndex);
private static native void nSetGeometryAt(long nativeRenderableManager, int i, int primitiveIndex, int primitiveType, long nativeVertexBuffer, long nativeIndexBuffer, int offset, int count);
private static native void nSetBlendOrderAt(long nativeRenderableManager, int i, int primitiveIndex, int blendOrder);
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/android/gradle.properties b/android/gradle.properties
index d1baf95447..6687f3ef9b 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
-VERSION_NAME=1.56.7
+VERSION_NAME=1.56.8
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
diff --git a/build/linux/ci-common.sh b/build/linux/ci-common.sh
index eb758bfe0e..bc3abd0fc2 100755
--- a/build/linux/ci-common.sh
+++ b/build/linux/ci-common.sh
@@ -1,16 +1,16 @@
#!/bin/bash
# version of clang we want to use
-GITHUB_CLANG_VERSION=14
+export GITHUB_CLANG_VERSION=14
# version of CMake to use instead of the default one
-CMAKE_VERSION=3.19.5
+export GITHUB_CMAKE_VERSION=3.19.5
# version of ninja to use
-NINJA_VERSION=1.10.2
+export GITHUB_NINJA_VERSION=1.10.2
# Steps for GitHub Workflows
if [[ "$GITHUB_WORKFLOW" ]]; then
# Install ninja
- wget -q https://github.com/ninja-build/ninja/releases/download/v$NINJA_VERSION/ninja-linux.zip
+ wget -q https://github.com/ninja-build/ninja/releases/download/v$GITHUB_NINJA_VERSION/ninja-linux.zip
unzip -q ninja-linux.zip
export PATH="$PWD:$PATH"
@@ -18,9 +18,9 @@ if [[ "$GITHUB_WORKFLOW" ]]; then
mkdir -p cmake
cd cmake
- sudo wget https://github.com/Kitware/CMake/releases/download/v$CMAKE_VERSION/cmake-$CMAKE_VERSION-Linux-x86_64.sh
- sudo chmod +x ./cmake-$CMAKE_VERSION-Linux-x86_64.sh
- sudo ./cmake-$CMAKE_VERSION-Linux-x86_64.sh --skip-license > /dev/null
+ sudo wget https://github.com/Kitware/CMake/releases/download/v$GITHUB_CMAKE_VERSION/cmake-$GITHUB_CMAKE_VERSION-Linux-x86_64.sh
+ sudo chmod +x ./cmake-$GITHUB_CMAKE_VERSION-Linux-x86_64.sh
+ sudo ./cmake-$GITHUB_CMAKE_VERSION-Linux-x86_64.sh --skip-license > /dev/null
sudo update-alternatives --install /usr/bin/cmake cmake $(pwd)/bin/cmake 1000 --force
cd ..
diff --git a/docs_src/build/checks.py b/docs_src/build/checks.py
new file mode 100644
index 0000000000..738e858f08
--- /dev/null
+++ b/docs_src/build/checks.py
@@ -0,0 +1,140 @@
+# Copyright (C) 2025 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This script contains several checks on the current commit, each corresponds to `possible_conditions`
+# in the main function below
+# - Direct (non-filamentbot) edits of /docs
+# - Edits to sources of READMEs that are duplicated to /docs
+# or edits to /docs_src sources
+# - Commit message has DOCS_BYPASS
+# - Commit message has DOCS_FORCE
+# - Commit message has DOCS_ALLOW_DIRECT_EDITS
+
+import json
+import sys
+import os
+
+from utils import execute, ArgParseImpl
+
+CUR_DIR = os.path.dirname(os.path.abspath(__file__))
+ROOT_DIR = os.path.join(CUR_DIR, '../../')
+
+def get_last_commit_hash():
+ res, ret = execute('git rev-parse HEAD', cwd=ROOT_DIR)
+ assert res == 0, 'Failed to get the last commit hash'
+ return ret.strip()
+
+def get_edited_files(commit_hash):
+ INSERT = '#####?????'
+ res, ret = execute(f'git show --name-only --pretty=%b{INSERT} {commit_hash}')
+ assert res == 0, 'Failed to get edited filed'
+ files = []
+ _, after = ret.split(INSERT)
+ for r in filter(lambda a: len(a) > 0, after.split('\n')):
+ if r.startswith('commit'):
+ break
+ files.append(r)
+ return files
+
+# Returns True if there were no direct edits to '/docs'
+def check_no_direct_edits(commit_hash, printing=True):
+ bad = [f'\t{f}' for f in get_edited_files(commit_hash) if f.startswith('docs/')]
+ if printing and len(bad) > 0:
+ print(f'Found edits to /docs:\n' + '\n'.join(bad))
+ return len(bad) == 0
+
+# Returns True if docs sources have been modified
+def check_has_source_edits(commit_hash, printing=True):
+ config = {}
+ with open(f'{CUR_DIR}/duplicates.json') as config_txt:
+ config = json.loads(config_txt.read())
+ source_files = set(config.keys())
+ edited_files = set(get_edited_files(commit_hash))
+ overlap = [f'\t{f}' for f in list(source_files & edited_files)]
+ if printing and len(overlap) > 0:
+ print(f'Found edited source files:\n' + '\n'.join(overlap))
+ return len(overlap) > 0
+
+# Returns true in a given TAG is found in the commit msg
+def commit_msg_has_tag(commit_hash, tag, printing=True):
+ res, ret = execute(f'git log --pretty=%B {commit_hash}', cwd=ROOT_DIR)
+ for l in ret.split('\n'):
+ if tag == l.strip():
+ if printing:
+ print(f'Found tag={tag} in commit message')
+ return True
+ return False
+
+if __name__ == "__main__":
+ parser = ArgParseImpl()
+
+ TAG_DOCS_BYPASS = 'DOCS_BYPASS'
+ TAG_DOCS_FORCE = 'DOCS_FORCE'
+ TAG_DOCS_ALLOW_DIRECT_EDITS = 'DOCS_ALLOW_DIRECT_EDITS'
+
+ possible_conditions = {
+ 'no_direct_edits':
+ check_no_direct_edits,
+ 'source_edits':
+ check_has_source_edits,
+ 'commit_docs_bypass':
+ lambda h: commit_msg_has_tag(h, TAG_DOCS_BYPASS),
+ 'commit_docs_force':
+ lambda h: commit_msg_has_tag(h, TAG_DOCS_FORCE),
+ 'commit_docs_allow_direct_edits':
+ lambda h: commit_msg_has_tag(h, TAG_DOCS_ALLOW_DIRECT_EDITS),
+ }
+
+ possible_str = ', '.join(list(possible_conditions.keys()))
+ parser.add_argument(
+ '--do-and',
+ type=str,
+ help=(
+ f'A conjunction of boolean conditions. Possible values are={possible_str}. '
+ 'Negation is done with `-`'
+ )
+ )
+ parser.add_argument(
+ '--do-or',
+ type=str,
+ help=(
+ f'A disjunction of boolean conditions. Possible values are={possible_str}. '
+ 'Negation is done with `-`'
+ )
+ )
+
+ args, _ = parser.parse_known_args(sys.argv[1:len(sys.argv) - 1])
+ commit_hash = sys.argv[-1]
+
+ assert not (args.do_and and args.do_or), "Must not supply both '--do-and' and '--do-or'"
+ assert args.do_and or args.do_or, "Must supply argument '--do-and' or '--do-or'"
+ conds = args.do_and.split(',') if args.do_and else args.do_or.split(',')
+ conds = [c.strip() for c in conds]
+ assert all(
+ [c in possible_conditions.keys() for c in
+ [(c.replace('-', '') if c.startswith('-') else c) for c in conds]]),\
+ f"Not all conditions are valid names. Only {possible_str} are accepted"
+
+ res = []
+ for cond in conds:
+ if cond.startswith('-'):
+ f = lambda: not possible_conditions[cond.replace('-', '')]()
+ else:
+ f = possible_conditions[cond]
+ res.append(f(commit_hash))
+
+ if args.do_and:
+ exit(0 if all(res) else 1)
+ else:
+ exit(0 if any(res) else 1)
diff --git a/docs_src/build/presubmit_check.sh b/docs_src/build/presubmit_check.sh
new file mode 100644
index 0000000000..21bc09a8f3
--- /dev/null
+++ b/docs_src/build/presubmit_check.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/bash
+
+# Copyright (C) 2025 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+COMMIT_HASH=$1
+python3 docs_src/build/checks.py --do-or="no_direct_edits,commit_docs_allow_direct_edits" $COMMIT_HASH ||\
+ (echo "Direct edits to /docs are not allowed. Please see /docs_src/README.md if you need to bypass this check." && exit 1)
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/backend/CMakeLists.txt b/filament/backend/CMakeLists.txt
index 89c29cf53e..208aec0ee0 100644
--- a/filament/backend/CMakeLists.txt
+++ b/filament/backend/CMakeLists.txt
@@ -139,11 +139,11 @@ if (FILAMENT_SUPPORTS_METAL)
src/metal/MetalEnums.mm
src/metal/MetalExternalImage.mm
src/metal/MetalHandles.mm
- src/metal/MetalPlatform.mm
src/metal/MetalShaderCompiler.mm
src/metal/MetalState.mm
src/metal/MetalTimerQuery.mm
src/metal/MetalUtils.mm
+ src/metal/PlatformMetal.mm
)
set(METAL_CPP_SRCS
diff --git a/filament/backend/include/backend/DriverEnums.h b/filament/backend/include/backend/DriverEnums.h
index ea4c41dfd3..2b68ced9c1 100644
--- a/filament/backend/include/backend/DriverEnums.h
+++ b/filament/backend/include/backend/DriverEnums.h
@@ -33,9 +33,9 @@
#include