Compare commits
24
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7017bde04d | ||
|
|
7701e7a65a | ||
|
|
65a91832a8 | ||
|
|
acb47ffed5 | ||
|
|
13c0304d84 | ||
|
|
febdf3974c | ||
|
|
390acec928 | ||
|
|
ff806f8c3e | ||
|
|
06c4faabc3 | ||
|
|
92aec16fa3 | ||
|
|
f1ffb783d8 | ||
|
|
b708300586 | ||
|
|
f88d757d06 | ||
|
|
4d96f188d1 | ||
|
|
2d943f40bb | ||
|
|
92c058a736 | ||
|
|
ba819bcfca | ||
|
|
e22f1adfa7 | ||
|
|
f2bca03360 | ||
|
|
5f07d701f0 | ||
|
|
496a50bc89 | ||
|
|
6ccb6c4cce | ||
|
|
42c78fd0a9 | ||
|
|
3d0e2923ae |
@@ -1,25 +0,0 @@
|
||||
name: Android
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- release
|
||||
- rc/**
|
||||
|
||||
jobs:
|
||||
build-android:
|
||||
name: build-android
|
||||
# We intentially use a larger runner here to enable larger disk space
|
||||
# (standard linux runner will fail on disk space and faster build time).
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- name: Run Android Continuous
|
||||
uses: ./.github/actions/android-continuous
|
||||
with:
|
||||
build-abi: armeabi-v7a,arm64-v8a,x86_64
|
||||
@@ -1,29 +0,0 @@
|
||||
name: iOS
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- release
|
||||
- rc/**
|
||||
|
||||
jobs:
|
||||
build-ios:
|
||||
name: build-ios
|
||||
runs-on: macos-14-xlarge
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/mac-prereq
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/ios && printf "y" | ./build.sh continuous
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: filament-ios
|
||||
path: out/filament-release-ios.tgz
|
||||
- name: Build iOS samples
|
||||
run: |
|
||||
cd build/ios && ./build-samples.sh continuous
|
||||
@@ -1,26 +0,0 @@
|
||||
name: Linux
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- release
|
||||
- rc/**
|
||||
|
||||
jobs:
|
||||
build-linux:
|
||||
name: build-linux
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/linux && printf "y" | ./build.sh continuous
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: filament-linux
|
||||
path: out/filament-release-linux.tgz
|
||||
@@ -1,29 +0,0 @@
|
||||
name: macOS
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- release
|
||||
- rc/**
|
||||
|
||||
jobs:
|
||||
build-mac:
|
||||
name: build-mac
|
||||
runs-on: macos-14-xlarge
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/mac-prereq
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/mac && printf "y" | ./build.sh continuous
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: filament-mac
|
||||
path: out/filament-release-darwin.tgz
|
||||
- name: Check public headers
|
||||
run: |
|
||||
test/check-headers/test.sh out/release/filament/include
|
||||
@@ -0,0 +1,59 @@
|
||||
name: 'Postsubmit Tasks'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
update-renderdiff-goldens:
|
||||
name: update-renderdiff-goldens
|
||||
runs-on: 'ubuntu-24.04-4core'
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- id: get_commit_msg
|
||||
uses: ./.github/actions/get-commit-msg
|
||||
- name: Prerequisites
|
||||
run: pip install tifffile numpy
|
||||
- name: Run update script
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.FILAMENTBOT_TOKEN }}
|
||||
COMMIT_MESSAGE: ${{ steps.get_commit_msg.outputs.msg }}
|
||||
run: |
|
||||
GOLDEN_BRANCH=$(echo "${COMMIT_MESSAGE}" | python3 test/renderdiff/src/commit_msg.py)
|
||||
COMMIT_HASH="${{ steps.get_commit_msg.outputs.hash }}"
|
||||
if [[ "${GOLDEN_BRANCH}" != "main" ]]; then
|
||||
git config --global user.email "filament.bot@gmail.com"
|
||||
git config --global user.name "Filament Bot"
|
||||
git config --global credential.helper cache
|
||||
echo "branch==${GOLDEN_BRANCH}"
|
||||
echo "hash==${COMMIT_HASH}"
|
||||
python3 test/renderdiff/src/update_golden.py --branch=${GOLDEN_BRANCH} \
|
||||
--merge-to-main --filament-tag=${COMMIT_HASH} --golden-repo-token=${GH_TOKEN}
|
||||
fi
|
||||
|
||||
update-docs:
|
||||
name: update-docs
|
||||
runs-on: 'ubuntu-24.04-4core'
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- id: get_commit_msg
|
||||
uses: ./.github/actions/get-commit-msg
|
||||
- name: Prerequisites
|
||||
run: pip install selenium
|
||||
- name: Run update script
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.FILAMENTBOT_TOKEN }}
|
||||
run: |
|
||||
bash docs_src/build/install_mdbook.sh && source ~/.bashrc
|
||||
COMMIT_HASH="${{ steps.get_commit_msg.outputs.hash }}"
|
||||
git config --global user.email "filament.bot@gmail.com"
|
||||
git config --global user.name "Filament Bot"
|
||||
git config --global credential.helper cache
|
||||
bash docs_src/build/postsubmit.sh ${COMMIT_HASH} ${GH_TOKEN}
|
||||
@@ -1,59 +1,115 @@
|
||||
name: 'Post-submit tasks'
|
||||
name: 'Postsubmit CI'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- release
|
||||
- rc/**
|
||||
|
||||
jobs:
|
||||
update-renderdiff-goldens:
|
||||
name: update-renderdiff-goldens
|
||||
runs-on: 'ubuntu-24.04-4core'
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- id: get_commit_msg
|
||||
uses: ./.github/actions/get-commit-msg
|
||||
- name: Prerequisites
|
||||
run: pip install tifffile numpy
|
||||
- name: Run update script
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.FILAMENTBOT_TOKEN }}
|
||||
COMMIT_MESSAGE: ${{ steps.get_commit_msg.outputs.msg }}
|
||||
run: |
|
||||
GOLDEN_BRANCH=$(echo "${COMMIT_MESSAGE}" | python3 test/renderdiff/src/commit_msg.py)
|
||||
COMMIT_HASH="${{ steps.get_commit_msg.outputs.hash }}"
|
||||
if [[ "${GOLDEN_BRANCH}" != "main" ]]; then
|
||||
git config --global user.email "filament.bot@gmail.com"
|
||||
git config --global user.name "Filament Bot"
|
||||
git config --global credential.helper cache
|
||||
echo "branch==${GOLDEN_BRANCH}"
|
||||
echo "hash==${COMMIT_HASH}"
|
||||
python3 test/renderdiff/src/update_golden.py --branch=${GOLDEN_BRANCH} \
|
||||
--merge-to-main --filament-tag=${COMMIT_HASH} --golden-repo-token=${GH_TOKEN}
|
||||
fi
|
||||
build-android:
|
||||
name: build-android
|
||||
# We intentially use a larger runner here to enable larger disk space
|
||||
# (standard linux runner will fail on disk space and faster build time).
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
|
||||
update-docs:
|
||||
name: update-docs
|
||||
runs-on: 'ubuntu-24.04-4core'
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- id: get_commit_msg
|
||||
uses: ./.github/actions/get-commit-msg
|
||||
- name: Prerequisites
|
||||
run: pip install selenium
|
||||
- name: Run update script
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.FILAMENTBOT_TOKEN }}
|
||||
- name: Run Android Continuous
|
||||
uses: ./.github/actions/android-continuous
|
||||
with:
|
||||
build-abi: armeabi-v7a,arm64-v8a,x86_64
|
||||
|
||||
build-ios:
|
||||
name: build-ios
|
||||
runs-on: macos-14-xlarge
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/mac-prereq
|
||||
- name: Run build script
|
||||
run: |
|
||||
bash docs_src/build/install_mdbook.sh && source ~/.bashrc
|
||||
COMMIT_HASH="${{ steps.get_commit_msg.outputs.hash }}"
|
||||
git config --global user.email "filament.bot@gmail.com"
|
||||
git config --global user.name "Filament Bot"
|
||||
git config --global credential.helper cache
|
||||
bash docs_src/build/postsubmit.sh ${COMMIT_HASH} ${GH_TOKEN}
|
||||
cd build/ios && printf "y" | ./build.sh continuous
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: filament-ios
|
||||
path: out/filament-release-ios.tgz
|
||||
- name: Build iOS samples
|
||||
run: |
|
||||
cd build/ios && ./build-samples.sh continuous
|
||||
|
||||
build-linux:
|
||||
name: build-linux
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/linux && printf "y" | ./build.sh continuous
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: filament-linux
|
||||
path: out/filament-release-linux.tgz
|
||||
|
||||
build-mac:
|
||||
name: build-mac
|
||||
runs-on: macos-14-xlarge
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/mac-prereq
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/mac && printf "y" | ./build.sh continuous
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: filament-mac
|
||||
path: out/filament-release-darwin.tgz
|
||||
- name: Check public headers
|
||||
run: |
|
||||
test/check-headers/test.sh out/release/filament/include
|
||||
|
||||
build-web:
|
||||
name: build-web
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- uses: ./.github/actions/web-prereq
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/web && printf "y" | ./build.sh continuous
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: filament-web
|
||||
path: out/filament-release-web.tgz
|
||||
|
||||
build-windows:
|
||||
name: build-windows
|
||||
runs-on: windows-2022-32core
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- name: Run build script
|
||||
run: |
|
||||
build\windows\build-github.bat continuous
|
||||
shell: cmd
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: filament-windows
|
||||
path: out/filament-windows.tgz
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Presubmit
|
||||
name: 'Presubmit CI'
|
||||
|
||||
on:
|
||||
push:
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
name: Web
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- release
|
||||
- rc/**
|
||||
|
||||
jobs:
|
||||
build-web:
|
||||
name: build-web
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- uses: ./.github/actions/web-prereq
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/web && printf "y" | ./build.sh continuous
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: filament-web
|
||||
path: out/filament-release-web.tgz
|
||||
@@ -1,24 +0,0 @@
|
||||
name: Windows
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- release
|
||||
- rc/**
|
||||
|
||||
jobs:
|
||||
build-windows:
|
||||
name: build-windows
|
||||
runs-on: windows-2022-32core
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- name: Run build script
|
||||
run: |
|
||||
build\windows\build-github.bat continuous
|
||||
shell: cmd
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: filament-windows
|
||||
path: out/filament-windows.tgz
|
||||
+9
-1
@@ -367,14 +367,22 @@ endif()
|
||||
|
||||
if (LINUX)
|
||||
option(USE_STATIC_LIBCXX "Link against the static runtime libraries." ON)
|
||||
|
||||
# Add this step to support both glibc-based Linux distributions (e.g., Ubuntu, Debian)
|
||||
# and musl-based distributions (e.g., Alpine).
|
||||
include(CheckSymbolExists)
|
||||
check_symbol_exists(__GLIBC__ "features.h" CLANG_WITH_GLIBC)
|
||||
|
||||
if (${USE_STATIC_LIBCXX})
|
||||
if (FILAMENT_USING_GCC)
|
||||
link_libraries("-static-libgcc -static-libstdc++")
|
||||
else ()
|
||||
elseif (CLANG_WITH_GLIBC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
|
||||
link_libraries("-static-libgcc -static-libstdc++")
|
||||
link_libraries(libc++.a)
|
||||
link_libraries(libc++abi.a)
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.68.3'
|
||||
implementation 'com.google.android.filament:filament-android:1.68.4'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -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.68.3'
|
||||
pod 'Filament', '~> 1.68.4'
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -7,6 +7,11 @@ 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.68.5
|
||||
|
||||
- engine: "native" Streams are officially deprecated. Use "acquired" streams instead.
|
||||
- engine: add "engine.skip_frame_when_cpu_ahead_of_display" feature [b/474599530]
|
||||
|
||||
## v1.68.4
|
||||
|
||||
- gltfio: Add optional support for webp textures (EXT_texture_webp), controlled via FILAMENT_SUPPORTS_WEBP_TEXTURES cmake option
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
GROUP=com.google.android.filament
|
||||
VERSION_NAME=1.68.3
|
||||
VERSION_NAME=1.68.4
|
||||
|
||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||
|
||||
|
||||
Vendored
+3
-3
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<!-- Book generated using mdBook -->
|
||||
<meta charset="UTF-8">
|
||||
<title>Build for Android on Windows - Filament</title>
|
||||
<title>Android on Windows - Filament</title>
|
||||
|
||||
|
||||
<!-- Custom HTML head -->
|
||||
@@ -273,7 +273,7 @@ copy filament-android\build\outputs\aar\filament-android-release.aar ..\..\out\
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../build/maven_release.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../dup/contributing.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
@@ -287,7 +287,7 @@ copy filament-android\build\outputs\aar\filament-android-release.aar ..\..\out\
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../build/maven_release.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../dup/contributing.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
@@ -209,7 +209,7 @@ as possible. The current external dependencies of the runtime library include:</
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../build/maven_release.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../build/windows_android.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
@@ -223,7 +223,7 @@ as possible. The current external dependencies of the runtime library include:</
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../build/maven_release.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../build/windows_android.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
|
||||
+2
-2
@@ -253,7 +253,7 @@ add a link in <code>SUMMARY.md</code>, and perform the steps outlined in
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../notes/release_guide.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../release/branching.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
@@ -267,7 +267,7 @@ add a link in <code>SUMMARY.md</code>, and perform the steps outlined in
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../notes/release_guide.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../release/branching.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
|
||||
+2
-2
@@ -181,7 +181,7 @@ important for <code>matc</code> (material compiler).</p>
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.68.3'
|
||||
implementation 'com.google.android.filament:filament-android:1.68.4'
|
||||
}
|
||||
</code></pre>
|
||||
<p>Here are all the libraries available in the group <code>com.google.android.filament</code>:</p>
|
||||
@@ -196,7 +196,7 @@ dependencies {
|
||||
</div>
|
||||
<h3 id="ios"><a class="header" href="#ios">iOS</a></h3>
|
||||
<p>iOS projects can use CocoaPods to install the latest release:</p>
|
||||
<pre><code class="language-shell">pod 'Filament', '~> 1.68.3'
|
||||
<pre><code class="language-shell">pod 'Filament', '~> 1.68.4'
|
||||
</code></pre>
|
||||
<h2 id="documentation"><a class="header" href="#documentation">Documentation</a></h2>
|
||||
<ul>
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en" class="light sidebar-visible" dir="ltr">
|
||||
<head>
|
||||
<!-- Book generated using mdBook -->
|
||||
<meta charset="UTF-8">
|
||||
<title>backend - Filament</title>
|
||||
|
||||
|
||||
<!-- Custom HTML head -->
|
||||
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
<link rel="shortcut icon" href="../favicon.png">
|
||||
<link rel="stylesheet" href="../css/variables.css">
|
||||
<link rel="stylesheet" href="../css/general.css">
|
||||
<link rel="stylesheet" href="../css/chrome.css">
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
||||
|
||||
<!-- Highlight.js Stylesheets -->
|
||||
<link rel="stylesheet" href="../highlight.css">
|
||||
<link rel="stylesheet" href="../tomorrow-night.css">
|
||||
<link rel="stylesheet" href="../ayu-highlight.css">
|
||||
|
||||
<!-- Custom theme stylesheets -->
|
||||
|
||||
<!-- MathJax -->
|
||||
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||
|
||||
<!-- Provide site root to javascript -->
|
||||
<script>
|
||||
var path_to_root = "../";
|
||||
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="../toc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="body-container">
|
||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||||
<script>
|
||||
try {
|
||||
var theme = localStorage.getItem('mdbook-theme');
|
||||
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||||
|
||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||||
}
|
||||
|
||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||||
}
|
||||
} catch (e) { }
|
||||
</script>
|
||||
|
||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
||||
<script>
|
||||
var theme;
|
||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
||||
const html = document.documentElement;
|
||||
html.classList.remove('light')
|
||||
html.classList.add(theme);
|
||||
html.classList.add("js");
|
||||
</script>
|
||||
|
||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
||||
|
||||
<!-- Hide / unhide sidebar before it is displayed -->
|
||||
<script>
|
||||
var sidebar = null;
|
||||
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
||||
if (document.body.clientWidth >= 1080) {
|
||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||||
sidebar = sidebar || 'visible';
|
||||
} else {
|
||||
sidebar = 'hidden';
|
||||
}
|
||||
sidebar_toggle.checked = sidebar === 'visible';
|
||||
html.classList.remove('sidebar-visible');
|
||||
html.classList.add("sidebar-" + sidebar);
|
||||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<div style="display:flex;align-items:center;justify-content:center">
|
||||
<img class="flogo" src="../images/filament_logo_small.png"></img>
|
||||
</div>
|
||||
<!-- populated by js -->
|
||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
||||
<noscript>
|
||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
||||
</noscript>
|
||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
||||
<div class="sidebar-resize-indicator"></div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
||||
<div class="page">
|
||||
<div id="menu-bar-hover-placeholder"></div>
|
||||
<div id="menu-bar" class="menu-bar sticky">
|
||||
<div class="left-buttons">
|
||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||||
<i class="fa fa-bars"></i>
|
||||
</label>
|
||||
<!-- Filament: disable themes because the markdeep part does not look good for dark themes -->
|
||||
<!--
|
||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||||
<i class="fa fa-paint-brush"></i>
|
||||
</button>
|
||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||||
</ul>
|
||||
-->
|
||||
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||||
<i class="fa fa-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<h1 class="menu-title">Filament</h1>
|
||||
|
||||
<div class="right-buttons">
|
||||
<a href="https://github.com/google/filament" title="Git repository" aria-label="Git repository">
|
||||
<i id="git-repository-button" class="fa fa-github"></i>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="search-wrapper" class="hidden">
|
||||
<form id="searchbar-outer" class="searchbar-outer">
|
||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||||
</form>
|
||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||||
<div id="searchresults-header" class="searchresults-header"></div>
|
||||
<ul id="searchresults">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||||
<script>
|
||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div id="content" class="content">
|
||||
<main>
|
||||
<h1 id="backend-tests"><a class="header" href="#backend-tests">Backend Tests</a></h1>
|
||||
<p>This directory (<code>/test/backend</code>) contains scripts to run Filament's backend tests using a software
|
||||
rasterizer (Mesa). This is useful for running tests in a continuous integration environment where a
|
||||
GPU might not be available.</p>
|
||||
<p>The <code>test.sh</code> script will:</p>
|
||||
<ol>
|
||||
<li>Build Mesa if needed.</li>
|
||||
<li>Build the backend tests.</li>
|
||||
<li>Run the tests using the OpenGL and Vulkan backends with Mesa.</li>
|
||||
</ol>
|
||||
<h2 id="flags"><a class="header" href="#flags">Flags</a></h2>
|
||||
<p>The <code>test.sh</code> script accepts the following flags:</p>
|
||||
<ul>
|
||||
<li><code>--gtest_filter</code>: Filters the tests that are run. This is passed directly to the underlying
|
||||
gtest executable.</li>
|
||||
<li><code>--backend</code>: Specifies which backend to test. Can be <code>opengl</code>, <code>vulkan</code>, or a comma-separated
|
||||
list (e.g., <code>opengl,vulkan</code>). Defaults to both.</li>
|
||||
</ul>
|
||||
|
||||
</main>
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../notes/tests.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../dup/test_renderdiff.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
<div style="clear: both"></div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../notes/tests.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../dup/test_renderdiff.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
window.playground_copyable = true;
|
||||
</script>
|
||||
|
||||
|
||||
<script src="../elasticlunr.min.js"></script>
|
||||
<script src="../mark.min.js"></script>
|
||||
<script src="../searcher.js"></script>
|
||||
|
||||
<script src="../clipboard.min.js"></script>
|
||||
<script src="../highlight.js"></script>
|
||||
<script src="../book.js"></script>
|
||||
|
||||
<!-- Custom JS scripts -->
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -159,7 +159,8 @@
|
||||
<div id="content" class="content">
|
||||
<main>
|
||||
<h1 id="rendering-difference-test"><a class="header" href="#rendering-difference-test">Rendering Difference Test</a></h1>
|
||||
<p>This tool is a collections of scripts to run <code>gltf_viewer</code> and produce headless renderings.</p>
|
||||
<p>This tool (<code>/test/renderdiff</code>) is a collections of scripts to run <code>gltf_viewer</code> and produce headless
|
||||
renderings.</p>
|
||||
<p>This is mainly useful for continuous integration where GPUs are generally not available on cloud
|
||||
machines. To perform software rasterization, these scripts are centered around <a href="https://docs.mesa3d.org">Mesa</a>'s
|
||||
software rasterizers, but nothing bars us from using another rasterizer like <a href="https://github.com/google/swiftshader">SwiftShader</a>.
|
||||
@@ -251,7 +252,7 @@ git switch -c my-pr-branch-golden
|
||||
</code></pre>
|
||||
</li>
|
||||
<li>In the commit message of your working branch on <code>filament</code>, add the following line
|
||||
<pre><code>RDIFF_BBRANCH=my-pr-branch-golden
|
||||
<pre><code>RDIFF_BRANCH=my-pr-branch-golden
|
||||
</code></pre>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -292,7 +293,7 @@ the run number is <code>18023632663</code>.</p>
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../notes/tests.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../dup/test_backend.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
@@ -306,7 +307,7 @@ the run number is <code>18023632663</code>.</p>
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../notes/tests.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../dup/test_backend.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
@@ -165,7 +165,7 @@
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../dup/renderdiff.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../dup/test_renderdiff.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
@@ -179,7 +179,7 @@
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../dup/renderdiff.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../dup/test_renderdiff.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
|
||||
@@ -668,7 +668,7 @@ Values can be <strong>negative</strong> to change the orientation of the specula
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../notes/versioning.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../release/index.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
@@ -682,7 +682,7 @@ Values can be <strong>negative</strong> to change the orientation of the specula
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../notes/versioning.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../release/index.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
@@ -170,7 +170,7 @@ for in our Continuation Integration flow <a href="https://https://github.com/goo
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../dup/renderdiff.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../dup/test_backend.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
@@ -184,7 +184,7 @@ for in our Continuation Integration flow <a href="https://https://github.com/goo
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../dup/renderdiff.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../dup/test_backend.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
@@ -185,11 +185,11 @@ the <em>correct</em> fix in both the next release candidate branch <em>and</em>
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../notes/versioning.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../release/versioning.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../notes/release_guide.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../dup/docs.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
@@ -199,11 +199,11 @@ the <em>correct</em> fix in both the next release candidate branch <em>and</em>
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../notes/versioning.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../release/versioning.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../notes/release_guide.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../dup/docs.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
</nav>
|
||||
@@ -0,0 +1,249 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en" class="light sidebar-visible" dir="ltr">
|
||||
<head>
|
||||
<!-- Book generated using mdBook -->
|
||||
<meta charset="UTF-8">
|
||||
<title>CocoaPods - Filament</title>
|
||||
|
||||
|
||||
<!-- Custom HTML head -->
|
||||
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
<link rel="shortcut icon" href="../favicon.png">
|
||||
<link rel="stylesheet" href="../css/variables.css">
|
||||
<link rel="stylesheet" href="../css/general.css">
|
||||
<link rel="stylesheet" href="../css/chrome.css">
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
||||
|
||||
<!-- Highlight.js Stylesheets -->
|
||||
<link rel="stylesheet" href="../highlight.css">
|
||||
<link rel="stylesheet" href="../tomorrow-night.css">
|
||||
<link rel="stylesheet" href="../ayu-highlight.css">
|
||||
|
||||
<!-- Custom theme stylesheets -->
|
||||
|
||||
<!-- MathJax -->
|
||||
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||
|
||||
<!-- Provide site root to javascript -->
|
||||
<script>
|
||||
var path_to_root = "../";
|
||||
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="../toc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="body-container">
|
||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||||
<script>
|
||||
try {
|
||||
var theme = localStorage.getItem('mdbook-theme');
|
||||
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||||
|
||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||||
}
|
||||
|
||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||||
}
|
||||
} catch (e) { }
|
||||
</script>
|
||||
|
||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
||||
<script>
|
||||
var theme;
|
||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
||||
const html = document.documentElement;
|
||||
html.classList.remove('light')
|
||||
html.classList.add(theme);
|
||||
html.classList.add("js");
|
||||
</script>
|
||||
|
||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
||||
|
||||
<!-- Hide / unhide sidebar before it is displayed -->
|
||||
<script>
|
||||
var sidebar = null;
|
||||
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
||||
if (document.body.clientWidth >= 1080) {
|
||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||||
sidebar = sidebar || 'visible';
|
||||
} else {
|
||||
sidebar = 'hidden';
|
||||
}
|
||||
sidebar_toggle.checked = sidebar === 'visible';
|
||||
html.classList.remove('sidebar-visible');
|
||||
html.classList.add("sidebar-" + sidebar);
|
||||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<div style="display:flex;align-items:center;justify-content:center">
|
||||
<img class="flogo" src="../images/filament_logo_small.png"></img>
|
||||
</div>
|
||||
<!-- populated by js -->
|
||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
||||
<noscript>
|
||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
||||
</noscript>
|
||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
||||
<div class="sidebar-resize-indicator"></div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
||||
<div class="page">
|
||||
<div id="menu-bar-hover-placeholder"></div>
|
||||
<div id="menu-bar" class="menu-bar sticky">
|
||||
<div class="left-buttons">
|
||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||||
<i class="fa fa-bars"></i>
|
||||
</label>
|
||||
<!-- Filament: disable themes because the markdeep part does not look good for dark themes -->
|
||||
<!--
|
||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||||
<i class="fa fa-paint-brush"></i>
|
||||
</button>
|
||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||||
</ul>
|
||||
-->
|
||||
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||||
<i class="fa fa-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<h1 class="menu-title">Filament</h1>
|
||||
|
||||
<div class="right-buttons">
|
||||
<a href="https://github.com/google/filament" title="Git repository" aria-label="Git repository">
|
||||
<i id="git-repository-button" class="fa fa-github"></i>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="search-wrapper" class="hidden">
|
||||
<form id="searchbar-outer" class="searchbar-outer">
|
||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||||
</form>
|
||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||||
<div id="searchresults-header" class="searchresults-header"></div>
|
||||
<ul id="searchresults">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||||
<script>
|
||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div id="content" class="content">
|
||||
<main>
|
||||
<h1 id="filament-cocoapods"><a class="header" href="#filament-cocoapods">Filament CocoaPods</a></h1>
|
||||
<p><a href="https://cocoapods.org/">CocoaPods</a> is the dependency manager Filament uses for Apple platforms
|
||||
(macOS and iOS).</p>
|
||||
<h2 id="installation"><a class="header" href="#installation">Installation</a></h2>
|
||||
<p>On macOS, CocoaPods requires a modern Ruby environment. Avoid using the system Ruby; instead,
|
||||
install the latest Ruby version using <code>brew</code>, <code>port,</code> or use a manager like <code>rbenv</code> or <code>rvm</code>. Once
|
||||
Ruby is configured:</p>
|
||||
<pre><code class="language-bash">gem install cocoapods
|
||||
</code></pre>
|
||||
<h2 id="linting-the-podspec"><a class="header" href="#linting-the-podspec">Linting the Podspec</a></h2>
|
||||
<p>The Filament podspec is configured to fetch releases directly from GitHub. Before deployment,
|
||||
CocoaPods must <strong>lint</strong> the spec to validate that the library compiles and links correctly across
|
||||
all supported architectures.</p>
|
||||
<p>To run the linter locally:</p>
|
||||
<pre><code class="language-bash">cd ios/CocoaPods/
|
||||
pod spec lint
|
||||
</code></pre>
|
||||
<h3 id="debugging-failures"><a class="header" href="#debugging-failures">Debugging Failures</a></h3>
|
||||
<p>If the lint fails, use the <code>--verbose</code> flag to inspect the underlying <code>xcodebuild</code> output:</p>
|
||||
<pre><code class="language-bash">pod spec lint --verbose
|
||||
</code></pre>
|
||||
<h2 id="isolating-subspecs"><a class="header" href="#isolating-subspecs">Isolating Subspecs</a></h2>
|
||||
<p>Filament is partitioned into multiple <strong>subspecs</strong>. CocoaPods lints these individually. To
|
||||
accelerate debugging or isolate a specific build failure (e.g., <code>Filament/filament</code>), use the
|
||||
following command:</p>
|
||||
<pre><code class="language-bash">pod spec lint --no-clean --verbose --subspec=Filament/filament 2>&1 | tee lint_output.log
|
||||
</code></pre>
|
||||
<ul>
|
||||
<li><code>--no-clean</code>: Preserves the temporary Xcode workspace and build artifacts in <code>/var/folders/...</code>
|
||||
for inspection.</li>
|
||||
<li><code>--verbose</code>: Prints the full compiler and linker invocations.</li>
|
||||
<li><code>--subspec</code>: Limits the scope of the lint to a specific component.</li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<p><strong>Tip:</strong> To view all defined subspecs, grep the podspec file:
|
||||
<code>grep "spec.subspec" ios/CocoaPods/Filament.podspec</code></p>
|
||||
</blockquote>
|
||||
|
||||
</main>
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../release/index.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../release/maven.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
<div style="clear: both"></div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../release/index.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../release/maven.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
window.playground_copyable = true;
|
||||
</script>
|
||||
|
||||
|
||||
<script src="../elasticlunr.min.js"></script>
|
||||
<script src="../mark.min.js"></script>
|
||||
<script src="../searcher.js"></script>
|
||||
|
||||
<script src="../clipboard.min.js"></script>
|
||||
<script src="../highlight.js"></script>
|
||||
<script src="../book.js"></script>
|
||||
|
||||
<!-- Custom JS scripts -->
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<!-- Book generated using mdBook -->
|
||||
<meta charset="UTF-8">
|
||||
<title>Release Guide - Filament</title>
|
||||
<title>Github - Filament</title>
|
||||
|
||||
|
||||
<!-- Custom HTML head -->
|
||||
@@ -250,11 +250,11 @@ release (for example, v1.42.2).</p>
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../notes/branching.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../release/maven.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../dup/docs.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../release/versioning.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
@@ -264,11 +264,11 @@ release (for example, v1.42.2).</p>
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../notes/branching.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../release/maven.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../dup/docs.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../release/versioning.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
</nav>
|
||||
@@ -0,0 +1,215 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en" class="light sidebar-visible" dir="ltr">
|
||||
<head>
|
||||
<!-- Book generated using mdBook -->
|
||||
<meta charset="UTF-8">
|
||||
<title>Release - Filament</title>
|
||||
|
||||
|
||||
<!-- Custom HTML head -->
|
||||
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
<link rel="shortcut icon" href="../favicon.png">
|
||||
<link rel="stylesheet" href="../css/variables.css">
|
||||
<link rel="stylesheet" href="../css/general.css">
|
||||
<link rel="stylesheet" href="../css/chrome.css">
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
||||
|
||||
<!-- Highlight.js Stylesheets -->
|
||||
<link rel="stylesheet" href="../highlight.css">
|
||||
<link rel="stylesheet" href="../tomorrow-night.css">
|
||||
<link rel="stylesheet" href="../ayu-highlight.css">
|
||||
|
||||
<!-- Custom theme stylesheets -->
|
||||
|
||||
<!-- MathJax -->
|
||||
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||
|
||||
<!-- Provide site root to javascript -->
|
||||
<script>
|
||||
var path_to_root = "../";
|
||||
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
|
||||
</script>
|
||||
<!-- Start loading toc.js asap -->
|
||||
<script src="../toc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="body-container">
|
||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||||
<script>
|
||||
try {
|
||||
var theme = localStorage.getItem('mdbook-theme');
|
||||
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||||
|
||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||||
}
|
||||
|
||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||||
}
|
||||
} catch (e) { }
|
||||
</script>
|
||||
|
||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
||||
<script>
|
||||
var theme;
|
||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
||||
const html = document.documentElement;
|
||||
html.classList.remove('light')
|
||||
html.classList.add(theme);
|
||||
html.classList.add("js");
|
||||
</script>
|
||||
|
||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
||||
|
||||
<!-- Hide / unhide sidebar before it is displayed -->
|
||||
<script>
|
||||
var sidebar = null;
|
||||
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
||||
if (document.body.clientWidth >= 1080) {
|
||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||||
sidebar = sidebar || 'visible';
|
||||
} else {
|
||||
sidebar = 'hidden';
|
||||
}
|
||||
sidebar_toggle.checked = sidebar === 'visible';
|
||||
html.classList.remove('sidebar-visible');
|
||||
html.classList.add("sidebar-" + sidebar);
|
||||
</script>
|
||||
|
||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||
<div style="display:flex;align-items:center;justify-content:center">
|
||||
<img class="flogo" src="../images/filament_logo_small.png"></img>
|
||||
</div>
|
||||
<!-- populated by js -->
|
||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
||||
<noscript>
|
||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
||||
</noscript>
|
||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
||||
<div class="sidebar-resize-indicator"></div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div id="page-wrapper" class="page-wrapper">
|
||||
|
||||
<div class="page">
|
||||
<div id="menu-bar-hover-placeholder"></div>
|
||||
<div id="menu-bar" class="menu-bar sticky">
|
||||
<div class="left-buttons">
|
||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||||
<i class="fa fa-bars"></i>
|
||||
</label>
|
||||
<!-- Filament: disable themes because the markdeep part does not look good for dark themes -->
|
||||
<!--
|
||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||||
<i class="fa fa-paint-brush"></i>
|
||||
</button>
|
||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||||
</ul>
|
||||
-->
|
||||
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||||
<i class="fa fa-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<h1 class="menu-title">Filament</h1>
|
||||
|
||||
<div class="right-buttons">
|
||||
<a href="https://github.com/google/filament" title="Git repository" aria-label="Git repository">
|
||||
<i id="git-repository-button" class="fa fa-github"></i>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="search-wrapper" class="hidden">
|
||||
<form id="searchbar-outer" class="searchbar-outer">
|
||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||||
</form>
|
||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||||
<div id="searchresults-header" class="searchresults-header"></div>
|
||||
<ul id="searchresults">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||||
<script>
|
||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div id="content" class="content">
|
||||
<main>
|
||||
<h1 id="release"><a class="header" href="#release">Release</a></h1>
|
||||
<p>This is a collection of guides for releasing Filament on different distribution platforms, including
|
||||
Github, Maven, and CocoaPods.</p>
|
||||
|
||||
</main>
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../notes/material_properties.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../release/cocoapods.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
<div style="clear: both"></div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../notes/material_properties.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../release/cocoapods.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
window.playground_copyable = true;
|
||||
</script>
|
||||
|
||||
|
||||
<script src="../elasticlunr.min.js"></script>
|
||||
<script src="../mark.min.js"></script>
|
||||
<script src="../searcher.js"></script>
|
||||
|
||||
<script src="../clipboard.min.js"></script>
|
||||
<script src="../highlight.js"></script>
|
||||
<script src="../book.js"></script>
|
||||
|
||||
<!-- Custom JS scripts -->
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<!-- Book generated using mdBook -->
|
||||
<meta charset="UTF-8">
|
||||
<title>Maven Release - Filament</title>
|
||||
<title>Maven - Filament</title>
|
||||
|
||||
|
||||
<!-- Custom HTML head -->
|
||||
@@ -218,11 +218,11 @@ the <strong>Publish</strong> button to publish the artifacts. It typically takes
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../build/windows_android.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../release/cocoapods.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../dup/contributing.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../release/guide.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
@@ -232,11 +232,11 @@ the <strong>Publish</strong> button to publish the artifacts. It typically takes
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../build/windows_android.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../release/cocoapods.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../dup/contributing.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../release/guide.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
</nav>
|
||||
@@ -186,11 +186,11 @@ post-process materials. However for now these two numbers must be set to the sam
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../notes/material_properties.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../release/guide.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../notes/branching.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../release/branching.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
|
||||
@@ -200,11 +200,11 @@ post-process materials. However for now these two numbers must be set to the sam
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../notes/material_properties.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../release/guide.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<i class="fa fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<a rel="next prefetch" href="../notes/branching.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../release/branching.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<i class="fa fa-angle-right"></i>
|
||||
</a>
|
||||
</nav>
|
||||
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
@@ -49,6 +49,9 @@
|
||||
"libs/fgviewer/README.md": {
|
||||
"dest": "dup/fgviewer.md"
|
||||
},
|
||||
"ios/CocoaPods/README.md": {
|
||||
"dest": "release/cocoapods.md"
|
||||
},
|
||||
"tools/normal-blending/README.md": {
|
||||
"dest": "dup/normal_blending.md"
|
||||
},
|
||||
@@ -83,9 +86,12 @@
|
||||
"dest": "dup/docs.md"
|
||||
},
|
||||
"test/renderdiff/README.md": {
|
||||
"dest": "dup/renderdiff.md",
|
||||
"dest": "dup/test_renderdiff.md",
|
||||
"link_transforms": {
|
||||
"docs/images/": "../images/"
|
||||
}
|
||||
},
|
||||
"test/backend/README.md": {
|
||||
"dest": "dup/test_backend.md"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
- [Introduction](./dup/intro.md)
|
||||
- [Build](./dup/building.md)
|
||||
- [Build for Android on Windows](./build/windows_android.md)
|
||||
- [Maven Release](./build/maven_release.md)
|
||||
- [Android on Windows](./build/windows_android.md)
|
||||
- [Contribute](./dup/contributing.md)
|
||||
- [Coding Style](./dup/code_style.md)
|
||||
- [Core Concepts](./main/README.md)
|
||||
@@ -14,9 +13,12 @@
|
||||
- [Web Tutorial](./samples/web.md)
|
||||
- [Technical Notes](./notes/README.md)
|
||||
- [Material Properties](./notes/material_properties.md)
|
||||
- [Versioning](./notes/versioning.md)
|
||||
- [Branching](./notes/branching.md)
|
||||
- [Release Guide](./notes/release_guide.md)
|
||||
- [Release](./release/README.md)
|
||||
- [CocoaPods](./release/cocoapods.md)
|
||||
- [Maven](./release/maven.md)
|
||||
- [Github](./release/guide.md)
|
||||
- [Versioning](./release/versioning.md)
|
||||
- [Branching](./release/branching.md)
|
||||
- [Documentation](./dup/docs.md)
|
||||
- [Debugging](./notes/debugging.md)
|
||||
- [Metal](./notes/metal_debugging.md)
|
||||
@@ -28,7 +30,8 @@
|
||||
- [Performance analysis](./notes/performance_analysis.md)
|
||||
- [Framegraph](./notes/framegraph.md)
|
||||
- [Tests](./notes/tests.md)
|
||||
- [renderdiff](./dup/renderdiff.md)
|
||||
- [backend](./dup/test_backend.md)
|
||||
- [renderdiff](./dup/test_renderdiff.md)
|
||||
- [Libraries](./notes/libs.md)
|
||||
- [bluegl](./dup/bluegl.md)
|
||||
- [bluevk](./dup/bluevk.md)
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
# Release
|
||||
|
||||
This is a collection of guides for releasing Filament on different distribution platforms, including
|
||||
Github, Maven, and CocoaPods.
|
||||
@@ -28,7 +28,6 @@ set(SRCS
|
||||
src/BackendUtils.cpp
|
||||
src/BlobCacheKey.cpp
|
||||
src/Callable.cpp
|
||||
src/CallbackHandler.cpp
|
||||
src/CallbackManager.cpp
|
||||
src/CircularBuffer.cpp
|
||||
src/CommandBufferQueue.cpp
|
||||
|
||||
@@ -17,6 +17,14 @@
|
||||
#ifndef TNT_FILAMENT_BACKEND_CALLBACKHANDLER_H
|
||||
#define TNT_FILAMENT_BACKEND_CALLBACKHANDLER_H
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
// Disable the weak-vtables warning because we need the destructor to be inlined in the headers. It
|
||||
// is not optimal (for build), but we have clients that compile their libraries (filament) and app
|
||||
// in different rtti settings.
|
||||
#pragma clang diagnostic ignored "-Wweak-vtables"
|
||||
#endif
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
/**
|
||||
@@ -64,9 +72,13 @@ public:
|
||||
virtual void post(void* user, Callback callback) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~CallbackHandler();
|
||||
virtual ~CallbackHandler() = default;
|
||||
};
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // TNT_FILAMENT_BACKEND_CALLBACKHANDLER_H
|
||||
|
||||
@@ -1009,98 +1009,99 @@ enum class CompressedPixelDataType : uint16_t {
|
||||
*
|
||||
* @see Texture
|
||||
*/
|
||||
// The [index] comments indicate the corresponding uint16_t values.
|
||||
enum class TextureFormat : uint16_t {
|
||||
// 8-bits per element
|
||||
R8, R8_SNORM, R8UI, R8I, STENCIL8,
|
||||
R8, R8_SNORM, R8UI, R8I, STENCIL8, // [0 - 4]
|
||||
|
||||
// 16-bits per element
|
||||
R16F, R16UI, R16I,
|
||||
RG8, RG8_SNORM, RG8UI, RG8I,
|
||||
RGB565,
|
||||
RGB9_E5, // 9995 is actually 32 bpp but it's here for historical reasons.
|
||||
RGB5_A1,
|
||||
RGBA4,
|
||||
DEPTH16,
|
||||
R16F, R16UI, R16I, // [5 - 7]
|
||||
RG8, RG8_SNORM, RG8UI, RG8I, // [8 - 11]
|
||||
RGB565, // [12]
|
||||
RGB9_E5, // 9995 is actually 32 bpp but it's here for historical reasons. [13]
|
||||
RGB5_A1, // [14]
|
||||
RGBA4, // [15]
|
||||
DEPTH16, // [16]
|
||||
|
||||
// 24-bits per element
|
||||
RGB8, SRGB8, RGB8_SNORM, RGB8UI, RGB8I,
|
||||
DEPTH24,
|
||||
RGB8, SRGB8, RGB8_SNORM, RGB8UI, RGB8I, // [17 - 21]
|
||||
DEPTH24, // [22]
|
||||
|
||||
// 32-bits per element
|
||||
R32F, R32UI, R32I,
|
||||
RG16F, RG16UI, RG16I,
|
||||
R11F_G11F_B10F,
|
||||
RGBA8, SRGB8_A8,RGBA8_SNORM,
|
||||
UNUSED, // used to be rgbm
|
||||
RGB10_A2, RGBA8UI, RGBA8I,
|
||||
DEPTH32F, DEPTH24_STENCIL8, DEPTH32F_STENCIL8,
|
||||
R32F, R32UI, R32I, // [23 - 25]
|
||||
RG16F, RG16UI, RG16I, // [26 - 28]
|
||||
R11F_G11F_B10F, // [29]
|
||||
RGBA8, SRGB8_A8,RGBA8_SNORM, // [30 - 32]
|
||||
UNUSED, // used to be rgbm [33]
|
||||
RGB10_A2, RGBA8UI, RGBA8I, // [34 - 36]
|
||||
DEPTH32F, DEPTH24_STENCIL8, DEPTH32F_STENCIL8, // [37 - 39]
|
||||
|
||||
// 48-bits per element
|
||||
RGB16F, RGB16UI, RGB16I,
|
||||
RGB16F, RGB16UI, RGB16I, // [40 - 42]
|
||||
|
||||
// 64-bits per element
|
||||
RG32F, RG32UI, RG32I,
|
||||
RGBA16F, RGBA16UI, RGBA16I,
|
||||
RG32F, RG32UI, RG32I, // [43 - 45]
|
||||
RGBA16F, RGBA16UI, RGBA16I, // [46 - 48]
|
||||
|
||||
// 96-bits per element
|
||||
RGB32F, RGB32UI, RGB32I,
|
||||
RGB32F, RGB32UI, RGB32I, // [49 - 51]
|
||||
|
||||
// 128-bits per element
|
||||
RGBA32F, RGBA32UI, RGBA32I,
|
||||
RGBA32F, RGBA32UI, RGBA32I, // [52 - 54]
|
||||
|
||||
// compressed formats
|
||||
|
||||
// Mandatory in GLES 3.0 and GL 4.3
|
||||
EAC_R11, EAC_R11_SIGNED, EAC_RG11, EAC_RG11_SIGNED,
|
||||
ETC2_RGB8, ETC2_SRGB8,
|
||||
ETC2_RGB8_A1, ETC2_SRGB8_A1,
|
||||
ETC2_EAC_RGBA8, ETC2_EAC_SRGBA8,
|
||||
EAC_R11, EAC_R11_SIGNED, EAC_RG11, EAC_RG11_SIGNED, // [55 - 58]
|
||||
ETC2_RGB8, ETC2_SRGB8, // [59 - 60]
|
||||
ETC2_RGB8_A1, ETC2_SRGB8_A1, // [61 - 62]
|
||||
ETC2_EAC_RGBA8, ETC2_EAC_SRGBA8, // [63 - 64]
|
||||
|
||||
// Available everywhere except Android/iOS
|
||||
DXT1_RGB, DXT1_RGBA, DXT3_RGBA, DXT5_RGBA,
|
||||
DXT1_SRGB, DXT1_SRGBA, DXT3_SRGBA, DXT5_SRGBA,
|
||||
DXT1_RGB, DXT1_RGBA, DXT3_RGBA, DXT5_RGBA, // [65 - 68]
|
||||
DXT1_SRGB, DXT1_SRGBA, DXT3_SRGBA, DXT5_SRGBA, // [69 - 72]
|
||||
|
||||
// ASTC formats are available with a GLES extension
|
||||
RGBA_ASTC_4x4,
|
||||
RGBA_ASTC_5x4,
|
||||
RGBA_ASTC_5x5,
|
||||
RGBA_ASTC_6x5,
|
||||
RGBA_ASTC_6x6,
|
||||
RGBA_ASTC_8x5,
|
||||
RGBA_ASTC_8x6,
|
||||
RGBA_ASTC_8x8,
|
||||
RGBA_ASTC_10x5,
|
||||
RGBA_ASTC_10x6,
|
||||
RGBA_ASTC_10x8,
|
||||
RGBA_ASTC_10x10,
|
||||
RGBA_ASTC_12x10,
|
||||
RGBA_ASTC_12x12,
|
||||
SRGB8_ALPHA8_ASTC_4x4,
|
||||
SRGB8_ALPHA8_ASTC_5x4,
|
||||
SRGB8_ALPHA8_ASTC_5x5,
|
||||
SRGB8_ALPHA8_ASTC_6x5,
|
||||
SRGB8_ALPHA8_ASTC_6x6,
|
||||
SRGB8_ALPHA8_ASTC_8x5,
|
||||
SRGB8_ALPHA8_ASTC_8x6,
|
||||
SRGB8_ALPHA8_ASTC_8x8,
|
||||
SRGB8_ALPHA8_ASTC_10x5,
|
||||
SRGB8_ALPHA8_ASTC_10x6,
|
||||
SRGB8_ALPHA8_ASTC_10x8,
|
||||
SRGB8_ALPHA8_ASTC_10x10,
|
||||
SRGB8_ALPHA8_ASTC_12x10,
|
||||
SRGB8_ALPHA8_ASTC_12x12,
|
||||
RGBA_ASTC_4x4, // [73]
|
||||
RGBA_ASTC_5x4, // [74]
|
||||
RGBA_ASTC_5x5, // [75]
|
||||
RGBA_ASTC_6x5, // [76]
|
||||
RGBA_ASTC_6x6, // [77]
|
||||
RGBA_ASTC_8x5, // [78]
|
||||
RGBA_ASTC_8x6, // [79]
|
||||
RGBA_ASTC_8x8, // [80]
|
||||
RGBA_ASTC_10x5, // [81]
|
||||
RGBA_ASTC_10x6, // [82]
|
||||
RGBA_ASTC_10x8, // [83]
|
||||
RGBA_ASTC_10x10, // [84]
|
||||
RGBA_ASTC_12x10, // [85]
|
||||
RGBA_ASTC_12x12, // [86]
|
||||
SRGB8_ALPHA8_ASTC_4x4, // [87]
|
||||
SRGB8_ALPHA8_ASTC_5x4, // [88]
|
||||
SRGB8_ALPHA8_ASTC_5x5, // [89]
|
||||
SRGB8_ALPHA8_ASTC_6x5, // [90]
|
||||
SRGB8_ALPHA8_ASTC_6x6, // [91]
|
||||
SRGB8_ALPHA8_ASTC_8x5, // [92]
|
||||
SRGB8_ALPHA8_ASTC_8x6, // [93]
|
||||
SRGB8_ALPHA8_ASTC_8x8, // [94]
|
||||
SRGB8_ALPHA8_ASTC_10x5, // [95]
|
||||
SRGB8_ALPHA8_ASTC_10x6, // [96]
|
||||
SRGB8_ALPHA8_ASTC_10x8, // [97]
|
||||
SRGB8_ALPHA8_ASTC_10x10, // [98]
|
||||
SRGB8_ALPHA8_ASTC_12x10, // [99]
|
||||
SRGB8_ALPHA8_ASTC_12x12, // [100]
|
||||
|
||||
// RGTC formats available with a GLES extension
|
||||
RED_RGTC1, // BC4 unsigned
|
||||
SIGNED_RED_RGTC1, // BC4 signed
|
||||
RED_GREEN_RGTC2, // BC5 unsigned
|
||||
SIGNED_RED_GREEN_RGTC2, // BC5 signed
|
||||
RED_RGTC1, // BC4 unsigned [101]
|
||||
SIGNED_RED_RGTC1, // BC4 signed [102]
|
||||
RED_GREEN_RGTC2, // BC5 unsigned [103]
|
||||
SIGNED_RED_GREEN_RGTC2, // BC5 signed [104]
|
||||
|
||||
// BPTC formats available with a GLES extension
|
||||
RGB_BPTC_SIGNED_FLOAT, // BC6H signed
|
||||
RGB_BPTC_UNSIGNED_FLOAT,// BC6H unsigned
|
||||
RGBA_BPTC_UNORM, // BC7
|
||||
SRGB_ALPHA_BPTC_UNORM, // BC7 sRGB
|
||||
RGB_BPTC_SIGNED_FLOAT, // BC6H signed [105]
|
||||
RGB_BPTC_UNSIGNED_FLOAT,// BC6H unsigned [106]
|
||||
RGBA_BPTC_UNORM, // BC7 [107]
|
||||
SRGB_ALPHA_BPTC_UNORM, // BC7 sRGB [108]
|
||||
};
|
||||
|
||||
TextureType getTextureType(TextureFormat format) noexcept;
|
||||
|
||||
@@ -31,6 +31,10 @@
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
namespace utils {
|
||||
class FeatureFlagManager;
|
||||
}
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
class CallbackHandler;
|
||||
@@ -104,6 +108,11 @@ public:
|
||||
/** duration in nanosecond on the std::steady_clock */
|
||||
using duration_ns = int64_t;
|
||||
static constexpr time_point_ns INVALID = -1; //!< value not supported
|
||||
/**
|
||||
* The time delta [ns] between subsequent composition events.
|
||||
*/
|
||||
duration_ns compositeInterval;
|
||||
|
||||
/**
|
||||
* The timestamp [ns] since epoch of the next time the compositor will begin composition.
|
||||
* This is effectively the deadline for when the compositor must receive a newly queued
|
||||
@@ -111,11 +120,6 @@ public:
|
||||
*/
|
||||
time_point_ns compositeDeadline;
|
||||
|
||||
/**
|
||||
* The time delta [ns] between subsequent composition events.
|
||||
*/
|
||||
duration_ns compositeInterval;
|
||||
|
||||
/**
|
||||
* The time delta [ns] between the start of composition and the expected present time of
|
||||
* that composition. This can be used to estimate the latency of the actual present time.
|
||||
@@ -123,22 +127,9 @@ public:
|
||||
duration_ns compositeToPresentLatency;
|
||||
|
||||
/**
|
||||
* The timestamp [ns] since epoch of the system's expected presentation time.
|
||||
* INVALID if not supported.
|
||||
* Expected latency [ns] of frame presentation relative to vsync.
|
||||
*/
|
||||
time_point_ns expectedPresentTime;
|
||||
|
||||
/**
|
||||
* The timestamp [ns] since epoch of the current frame's start (i.e. vsync)
|
||||
* INVALID if not supported.
|
||||
*/
|
||||
time_point_ns frameTime;
|
||||
|
||||
/**
|
||||
* The timestamp [ns] since epoch of the current frame's deadline
|
||||
* INVALID if not supported.
|
||||
*/
|
||||
time_point_ns frameTimelineDeadline;
|
||||
duration_ns expectedPresentLatency;
|
||||
};
|
||||
|
||||
struct FrameTimestamps {
|
||||
@@ -278,6 +269,11 @@ public:
|
||||
};
|
||||
|
||||
struct DriverConfig {
|
||||
/**
|
||||
* Reference to the system's FeatureFlagManager. Can be nullptr.
|
||||
*/
|
||||
utils::FeatureFlagManager const * UTILS_NULLABLE featureFlagManager = nullptr;
|
||||
|
||||
/**
|
||||
* Size of handle arena in bytes. Setting to 0 indicates default value is to be used.
|
||||
* Driver clamps to valid values.
|
||||
|
||||
@@ -56,6 +56,16 @@ struct VulkanCmdFence;
|
||||
*/
|
||||
class VulkanPlatform : public Platform, utils::PrivateImplementation<VulkanPlatformPrivate> {
|
||||
public:
|
||||
/**
|
||||
* Encapsulates information required to instantiate a known external format,
|
||||
* typically for the purpose of preloading a pipeline cache for materials using
|
||||
* external formats for samplers.
|
||||
*/
|
||||
struct ExternalYcbcrFormat {
|
||||
uint64_t externalFormat;
|
||||
VkSamplerYcbcrModelConversion ycbcrModelConversion;
|
||||
VkSamplerYcbcrRange ycbcrRange;
|
||||
};
|
||||
|
||||
struct ExtensionHashFn {
|
||||
std::size_t operator()(utils::CString const& s) const noexcept {
|
||||
@@ -501,6 +511,17 @@ protected:
|
||||
*/
|
||||
bool isTransientAttachmentSupported() const noexcept;
|
||||
|
||||
/**
|
||||
* For pipeline cache prewarming, if external samplers are present, we need to build
|
||||
* the fake pipeline using the proper formats specified. Since there's no way to
|
||||
* get these at material build time, we allow the app to register them before
|
||||
* creating materials.
|
||||
*
|
||||
* @param format The format, containing the external format value which should be
|
||||
* extracted from an AHardwareBuffer.
|
||||
*/
|
||||
void registerPipelineCachePrewarmExternalFormat(const ExternalYcbcrFormat& format) noexcept;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Contains information about features that should be requested
|
||||
|
||||
@@ -81,7 +81,6 @@ public:
|
||||
bool queryFrameTimestamps(SwapChain const* swapchain, uint64_t frameId,
|
||||
FrameTimestamps* outFrameTimestamps) const noexcept override;
|
||||
|
||||
|
||||
protected:
|
||||
ExtensionSet getSwapchainInstanceExtensions() const override;
|
||||
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <backend/CallbackHandler.h>
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
// Define the virtual destructor here to avoid a compiler warning that we treat as an error.
|
||||
// "'CallbackHandler' has no out-of-line virtual method definitions; its vtable will be emitted in every translation unit"
|
||||
// The warning occurs when a class inherits from CallbackHandler.
|
||||
CallbackHandler::~CallbackHandler() = default;
|
||||
|
||||
} // namespace filament::backend
|
||||
@@ -19,17 +19,13 @@
|
||||
|
||||
#include <backend/PixelBufferDescriptor.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <math/scalar.h>
|
||||
#include <math/half.h>
|
||||
|
||||
#include <utils/debug.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/ostream.h>
|
||||
|
||||
namespace filament {
|
||||
namespace backend {
|
||||
@@ -80,7 +76,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// Converts a n-channel image of UBYTE, INT, UINT, HALF, or FLOAT to a different type.
|
||||
// Converts a n-channel image of UBYTE, INT, UINT, or FLOAT to a different type.
|
||||
template<typename dstComponentType, typename srcComponentType>
|
||||
static void reshapeImage(uint8_t* UTILS_RESTRICT dest, const uint8_t* UTILS_RESTRICT src,
|
||||
size_t srcBytesPerRow,
|
||||
@@ -95,8 +91,6 @@ public:
|
||||
UTILS_ASSUME(minChannelCount <= 4);
|
||||
dest += (dstRowOffset * dstBytesPerRow);
|
||||
const int inds[4] = { swizzle ? 2 : 0, 1, swizzle ? 0 : 2, 3 };
|
||||
|
||||
utils::slog.e <<"dstMaxValue=" << +dstMaxValue << utils::io::endl;
|
||||
for (size_t row = 0; row < height; ++row) {
|
||||
const srcComponentType* in = (const srcComponentType*) src;
|
||||
dstComponentType* out = (dstComponentType*)dest + (dstColumnOffset * dstChannelCount);
|
||||
@@ -125,7 +119,6 @@ public:
|
||||
static bool reshapeImage(PixelBufferDescriptor* UTILS_RESTRICT dst, PixelDataType srcType,
|
||||
uint32_t srcChannelCount, const uint8_t* UTILS_RESTRICT srcBytes, int srcBytesPerRow,
|
||||
int width, int height, bool swizzle) {
|
||||
using namespace utils;
|
||||
size_t dstChannelCount;
|
||||
switch (dst->format) {
|
||||
case PixelDataFormat::R_INTEGER: dstChannelCount = 1; break;
|
||||
@@ -136,9 +129,7 @@ public:
|
||||
case PixelDataFormat::RG: dstChannelCount = 2; break;
|
||||
case PixelDataFormat::RGB: dstChannelCount = 3; break;
|
||||
case PixelDataFormat::RGBA: dstChannelCount = 4; break;
|
||||
default:
|
||||
slog.e << "DataReshaper: unsupported dst->format: " << (int)dst->format << io::endl;
|
||||
return false;
|
||||
default: return false;
|
||||
}
|
||||
void (*reshaper)(uint8_t* dest, const uint8_t* src, size_t srcBytesPerRow,
|
||||
size_t srcChannelCount,
|
||||
@@ -164,10 +155,7 @@ public:
|
||||
case FLOAT: reshaper = reshapeImage<uint8_t, float>; break;
|
||||
case INT: reshaper = reshapeImage<uint8_t, int32_t>; break;
|
||||
case UINT: reshaper = reshapeImage<uint8_t, uint32_t>; break;
|
||||
case HALF: reshaper = reshapeImage<uint8_t, math::half>; break;
|
||||
default:
|
||||
slog.e << "DataReshaper: UBYTE dst, unsupported srcType: " << (int)srcType << io::endl;
|
||||
return false;
|
||||
default: return false;
|
||||
}
|
||||
break;
|
||||
case FLOAT:
|
||||
@@ -176,9 +164,7 @@ public:
|
||||
case FLOAT: reshaper = reshapeImage<float, float>; break;
|
||||
case INT: reshaper = reshapeImage<float, int32_t>; break;
|
||||
case UINT: reshaper = reshapeImage<float, uint32_t>; break;
|
||||
default:
|
||||
slog.e << "DataReshaper: FLOAT dst, unsupported srcType: " << (int)srcType << io::endl;
|
||||
return false;
|
||||
default: return false;
|
||||
}
|
||||
break;
|
||||
case INT:
|
||||
@@ -187,9 +173,7 @@ public:
|
||||
case FLOAT: reshaper = reshapeImage<int32_t, float>; break;
|
||||
case INT: reshaper = reshapeImage<int32_t, int32_t>; break;
|
||||
case UINT: reshaper = reshapeImage<int32_t, uint32_t>; break;
|
||||
default:
|
||||
slog.e << "DataReshaper: INT dst, unsupported srcType: " << (int)srcType << io::endl;
|
||||
return false;
|
||||
default: return false;
|
||||
}
|
||||
break;
|
||||
case UINT:
|
||||
@@ -198,21 +182,16 @@ public:
|
||||
case FLOAT: reshaper = reshapeImage<uint32_t, float>; break;
|
||||
case INT: reshaper = reshapeImage<uint32_t, int32_t>; break;
|
||||
case UINT: reshaper = reshapeImage<uint32_t, uint32_t>; break;
|
||||
default:
|
||||
slog.e << "DataReshaper: UINT dst, unsupported srcType: " << (int)srcType << io::endl;
|
||||
return false;
|
||||
default: return false;
|
||||
}
|
||||
break;
|
||||
case HALF:
|
||||
switch (srcType) {
|
||||
case HALF: reshaper = copyImage; break;
|
||||
default:
|
||||
slog.e << "DataReshaper: HALF dst, unsupported srcType: " << (int)srcType << io::endl;
|
||||
return false;
|
||||
default: return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
slog.e << "DataReshaper: unsupported dst->type: " << (int)dst->type << io::endl;
|
||||
return false;
|
||||
}
|
||||
uint8_t* dstBytes = (uint8_t*) dst->buffer;
|
||||
@@ -221,7 +200,6 @@ public:
|
||||
reshaper(dstBytes, srcBytes, srcBytesPerRow, srcChannelCount,
|
||||
dst->top, dst->left, dstBytesPerRow,
|
||||
dstChannelCount, width, height, swizzle);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -231,7 +209,6 @@ template<> inline int32_t getMaxValue() { return 0x7fffffff; }
|
||||
template<> inline uint32_t getMaxValue() { return 0xffffffff; }
|
||||
template<> inline uint16_t getMaxValue() { return 0x3c00; } // 0x3c00 is 1.0 in half-float.
|
||||
template<> inline uint8_t getMaxValue() { return 0xff; }
|
||||
template<> inline math::half getMaxValue() { return math::half(1.0f); }
|
||||
|
||||
} // namespace backend
|
||||
} // namespace filament
|
||||
|
||||
@@ -51,45 +51,39 @@ namespace filament::backend {
|
||||
|
||||
DriverBase::DriverBase(const Platform::DriverConfig& driverConfig) noexcept
|
||||
: mDriverConfig(driverConfig) {
|
||||
if constexpr (UTILS_HAS_THREADING) {
|
||||
// This thread services user callbacks
|
||||
mServiceThread = std::thread([this]() {
|
||||
JobSystem::setThreadName("ServiceThread");
|
||||
do {
|
||||
auto& serviceThreadCondition = mServiceThreadCondition;
|
||||
auto& serviceThreadCallbackQueue = mServiceThreadCallbackQueue;
|
||||
#if UTILS_HAS_THREADING
|
||||
// This thread services user callbacks
|
||||
mServiceThread = std::thread([this]() {
|
||||
JobSystem::setThreadName("ServiceThread");
|
||||
do {
|
||||
auto& serviceThreadCondition = mServiceThreadCondition;
|
||||
auto& serviceThreadCallbackQueue = mServiceThreadCallbackQueue;
|
||||
|
||||
// wait for some callbacks to dispatch
|
||||
std::unique_lock<std::mutex> lock(mServiceThreadLock);
|
||||
while (serviceThreadCallbackQueue.empty() && !mExitRequested) {
|
||||
serviceThreadCondition.wait(lock);
|
||||
}
|
||||
if (mExitRequested) {
|
||||
break;
|
||||
}
|
||||
// move the callbacks to a temporary vector
|
||||
auto callbacks(std::move(serviceThreadCallbackQueue));
|
||||
lock.unlock();
|
||||
// and make sure to call them without our lock held
|
||||
for (auto[handler, callback, user]: callbacks) {
|
||||
handler->post(user, callback);
|
||||
}
|
||||
} while (true);
|
||||
});
|
||||
}
|
||||
// wait for some callbacks to dispatch
|
||||
std::unique_lock<std::mutex> lock(mServiceThreadLock);
|
||||
while (serviceThreadCallbackQueue.empty() && !mExitRequested) {
|
||||
serviceThreadCondition.wait(lock);
|
||||
}
|
||||
if (mExitRequested) {
|
||||
break;
|
||||
}
|
||||
// move the callbacks to a temporary vector
|
||||
auto callbacks(std::move(serviceThreadCallbackQueue));
|
||||
lock.unlock();
|
||||
// and make sure to call them without our lock held
|
||||
for (auto[handler, callback, user]: callbacks) {
|
||||
handler->post(user, callback);
|
||||
}
|
||||
} while (true);
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
DriverBase::~DriverBase() noexcept {
|
||||
assert_invariant(mCallbacks.empty());
|
||||
assert_invariant(mServiceThreadCallbackQueue.empty());
|
||||
if constexpr (UTILS_HAS_THREADING) {
|
||||
// quit our service thread
|
||||
std::unique_lock<std::mutex> lock(mServiceThreadLock);
|
||||
mExitRequested = true;
|
||||
mServiceThreadCondition.notify_one();
|
||||
lock.unlock();
|
||||
mServiceThread.join();
|
||||
}
|
||||
#if UTILS_HAS_THREADING
|
||||
stopServiceThread();
|
||||
#endif
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -113,11 +107,14 @@ void DriverBase::CallbackData::release(CallbackData* data) {
|
||||
|
||||
|
||||
void DriverBase::scheduleCallback(CallbackHandler* handler, void* user, CallbackHandler::Callback callback) {
|
||||
if (handler && UTILS_HAS_THREADING) {
|
||||
#if UTILS_HAS_THREADING
|
||||
if (handler) {
|
||||
std::lock_guard<std::mutex> const lock(mServiceThreadLock);
|
||||
mServiceThreadCallbackQueue.emplace_back(handler, callback, user);
|
||||
mServiceThreadCondition.notify_one();
|
||||
} else {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
std::lock_guard<std::mutex> const lock(mPurgeLock);
|
||||
mCallbacks.emplace_back(user, callback);
|
||||
}
|
||||
@@ -185,6 +182,22 @@ void DriverBase::debugCommandEnd(CommandStream* cmds, bool synchronous,
|
||||
}
|
||||
}
|
||||
|
||||
#if UTILS_HAS_THREADING
|
||||
void DriverBase::stopServiceThread() noexcept {
|
||||
if (!mServiceThread.joinable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mServiceThreadLock);
|
||||
mExitRequested = true;
|
||||
}
|
||||
mServiceThreadCondition.notify_one();
|
||||
mServiceThread.join();
|
||||
assert_invariant(mServiceThreadCallbackQueue.empty());
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t Driver::getElementTypeSize(ElementType type) noexcept {
|
||||
switch (type) {
|
||||
case ElementType::BYTE: return sizeof(int8_t);
|
||||
|
||||
@@ -173,6 +173,8 @@ struct HwTimerQuery : public HwBase {
|
||||
|
||||
/*
|
||||
* Base class of all Driver implementations
|
||||
* If multithreading is supported, this class creates a `ServiceThread` responsible for executing
|
||||
* user handlers.
|
||||
*/
|
||||
|
||||
class DriverBase : public Driver {
|
||||
@@ -236,17 +238,25 @@ protected:
|
||||
void debugCommandBegin(CommandStream* cmds, bool synchronous, const char* methodName) noexcept override;
|
||||
void debugCommandEnd(CommandStream* cmds, bool synchronous, const char* methodName) noexcept override;
|
||||
|
||||
#if UTILS_HAS_THREADING
|
||||
// Stops the `ServiceThread`. This method is called during destruction but may be called
|
||||
// explicitly if earlier shutdown is needed. This method is idempotent.
|
||||
void stopServiceThread() noexcept;
|
||||
#endif
|
||||
|
||||
private:
|
||||
const Platform::DriverConfig mDriverConfig;
|
||||
|
||||
std::mutex mPurgeLock;
|
||||
std::vector<std::pair<void*, CallbackHandler::Callback>> mCallbacks;
|
||||
|
||||
#if UTILS_HAS_THREADING
|
||||
std::thread mServiceThread;
|
||||
std::mutex mServiceThreadLock;
|
||||
std::condition_variable mServiceThreadCondition;
|
||||
std::vector<std::tuple<CallbackHandler*, CallbackHandler::Callback, void*>> mServiceThreadCallbackQueue;
|
||||
bool mExitRequested = false;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -382,9 +382,18 @@ void OpenGLDriver::terminate() {
|
||||
delete mCurrentPushConstants;
|
||||
mCurrentPushConstants = nullptr;
|
||||
|
||||
// Flush all pending asynchronous tasks. Some tasks may end up posting follow-up operations to
|
||||
// the `ServiceThread` (e.g., via CountdownCallbackHandler or any user-provided handlers). So we
|
||||
// early stop the ServiceThread to ensure these are processed as well. Tasks posted to the main
|
||||
// thread (due to no user handler) during this process are handled later by `Driver::purge`
|
||||
// within `FEngine::shutdown`.
|
||||
if (getJobWorker()) {
|
||||
getJobWorker()->terminate();
|
||||
}
|
||||
#if UTILS_HAS_THREADING
|
||||
stopServiceThread();
|
||||
#endif
|
||||
|
||||
mContext.terminate();
|
||||
mPlatform.terminate();
|
||||
}
|
||||
|
||||
@@ -79,6 +79,7 @@ static void process_GOOGLE_cpp_style_line_directive(OpenGLContext const& context
|
||||
static void process_OVR_multiview2(OpenGLContext const& context, int32_t eyeCount, char* source,
|
||||
size_t len) noexcept;
|
||||
static std::string_view process_ARB_shading_language_packing(OpenGLContext& context) noexcept;
|
||||
static std::string_view process_countBits(OpenGLContext& context) noexcept;
|
||||
static std::array<std::string_view, 3> splitShaderSource(std::string_view source);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -779,6 +780,7 @@ void ShaderCompilerService::cancelPendingSynchronousProgram(program_token_t cons
|
||||
|
||||
// add support for ARB_shading_language_packing if needed
|
||||
auto const packingFunctions = process_ARB_shading_language_packing(context);
|
||||
auto const countBitsFunctions = process_countBits(context);
|
||||
|
||||
// split shader source, so we can insert the specialization constants and the packing
|
||||
// functions
|
||||
@@ -789,10 +791,10 @@ void ShaderCompilerService::cancelPendingSynchronousProgram(program_token_t cons
|
||||
version = "#version 310 es\n";
|
||||
}
|
||||
|
||||
std::array<std::string_view, 5> sources = {
|
||||
std::array<std::string_view, 6> sources = {
|
||||
version, prolog,
|
||||
{ specializationConstantString.data(), specializationConstantString.size() },
|
||||
packingFunctions,
|
||||
packingFunctions, countBitsFunctions,
|
||||
{ body.data(), body.size() - 1 } // null-terminated
|
||||
};
|
||||
|
||||
@@ -803,8 +805,8 @@ void ShaderCompilerService::cancelPendingSynchronousProgram(program_token_t cons
|
||||
[](std::string_view s) { return !s.empty(); });
|
||||
size_t const count = std::distance(sources.begin(), partitionPoint);
|
||||
|
||||
std::array<const char*, 5> shaderStrings;
|
||||
std::array<GLint, 5> lengths;
|
||||
std::array<const char*, 6> shaderStrings;
|
||||
std::array<GLint, 6> lengths;
|
||||
for (size_t j = 0; j < count; j++) {
|
||||
shaderStrings[j] = sources[j].data();
|
||||
lengths[j] = GLint(sources[j].size());
|
||||
@@ -1085,6 +1087,22 @@ UTILS_NOINLINE
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ std::string_view process_countBits(OpenGLContext& context) noexcept {
|
||||
using namespace std::literals;
|
||||
if (context.isAtLeastGL<4, 0>() || context.isAtLeastGLES<3, 1>()) {
|
||||
return ""sv;
|
||||
}
|
||||
return R"(
|
||||
// https://graphics.stanford.edu/%7Eseander/bithacks.html
|
||||
int bitCount(highp uint value) {
|
||||
value = value - ((value >> 1u) & 0x55555555u);
|
||||
value = (value & 0x33333333u) + ((value >> 2u) & 0x33333333u);
|
||||
return int(((value + (value >> 4u) & 0xF0F0F0Fu) * 0x1010101u) >> 24u);
|
||||
}
|
||||
)"sv;
|
||||
}
|
||||
|
||||
|
||||
// Tragically, OpenGL 4.1 doesn't support unpackHalf2x16 (appeared in 4.2) and
|
||||
// macOS doesn't support GL_ARB_shading_language_packing
|
||||
// Also GLES3.0 didn't have the full set of packing/unpacking functions
|
||||
|
||||
@@ -296,9 +296,18 @@ bool PlatformEGLAndroid::queryCompositorTiming(SwapChain const* swapchain,
|
||||
|
||||
AndroidFrameCallback::Timeline const preferredTimeline{
|
||||
mAndroidDetails.androidFrameCallback.getPreferredTimeline() };
|
||||
outCompositorTiming->frameTime = preferredTimeline.frameTime;
|
||||
outCompositorTiming->expectedPresentTime = preferredTimeline.expectedPresentTime;
|
||||
outCompositorTiming->frameTimelineDeadline = preferredTimeline.frameTimelineDeadline;
|
||||
// FIXME: expectedPresentLatency might reflect the previous frame's value because
|
||||
// the choreographer's callback can happen before (good) or after (bad) us.
|
||||
// This problem is mitigated by storing the latency instead of the deadline,
|
||||
// because it generally is constant frame to frame.
|
||||
if (UTILS_LIKELY(preferredTimeline.expectedPresentTime > preferredTimeline.frameTime)) {
|
||||
// latency can never be negative, let's be safe
|
||||
outCompositorTiming->expectedPresentLatency =
|
||||
preferredTimeline.expectedPresentTime - preferredTimeline.frameTime;
|
||||
} else {
|
||||
// fake a reasonable value (33ms)
|
||||
outCompositorTiming->expectedPresentLatency = 33'000'000;
|
||||
}
|
||||
outCompositorTiming->compositeDeadline = CompositorTiming::INVALID;
|
||||
outCompositorTiming->compositeInterval = CompositorTiming::INVALID;
|
||||
outCompositorTiming->compositeToPresentLatency = CompositorTiming::INVALID;
|
||||
|
||||
@@ -22,8 +22,9 @@
|
||||
|
||||
#include "vulkan/memory/ResourcePointer.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <utils/bitset.h>
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
#include <utils/Mutex.h>
|
||||
#include <utils/Slice.h>
|
||||
|
||||
@@ -90,6 +91,19 @@ public:
|
||||
return selectMemoryType(mMemoryProperties, types, reqs);
|
||||
}
|
||||
|
||||
/**
|
||||
* For pipeline cache prewarming, if external samplers are present, we need to build
|
||||
* the fake pipeline using the proper formats specified. Since there's no way to
|
||||
* get these at material build time, we allow the app to register them before
|
||||
* creating materials.
|
||||
*
|
||||
* @param format The format, containing the external format value which should be
|
||||
* extracted from an AHardwareBuffer.
|
||||
*/
|
||||
inline void addPipelineCachePrewarmExternalFormat(const VulkanPlatform::ExternalYcbcrFormat& format) {
|
||||
mPipelineCachePrewarmExternalFormats.push_back(format);
|
||||
}
|
||||
|
||||
inline fvkutils::VkFormatList const& getAttachmentDepthStencilFormats() const {
|
||||
return mDepthStencilFormats;
|
||||
}
|
||||
@@ -106,6 +120,18 @@ public:
|
||||
return mPhysicalDeviceProperties.properties.vendorID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a list of pre-registered external formats for prewarming the Vulkan
|
||||
* pipeline cache.
|
||||
*
|
||||
* @return A list containing an external format number, YCbCr color model conversion,
|
||||
* and YCbCr color range.
|
||||
*/
|
||||
inline const std::vector<VulkanPlatform::ExternalYcbcrFormat>&
|
||||
getPipelineCachePrewarmExternalFormats() const noexcept {
|
||||
return mPipelineCachePrewarmExternalFormats;
|
||||
}
|
||||
|
||||
inline VkExternalFenceHandleTypeFlags getFenceExportFlags() const noexcept {
|
||||
return mFenceExportFlags;
|
||||
}
|
||||
@@ -223,6 +249,8 @@ private:
|
||||
fvkutils::VkFormatList mDepthStencilFormats;
|
||||
fvkutils::VkFormatList mBlittableDepthStencilFormats;
|
||||
|
||||
std::vector<VulkanPlatform::ExternalYcbcrFormat> mPipelineCachePrewarmExternalFormats;
|
||||
|
||||
// For convenience so that VulkanPlatform can initialize the private fields.
|
||||
friend class VulkanPlatform;
|
||||
};
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include <utils/CString.h>
|
||||
#include <utils/ImmutableCString.h>
|
||||
#include <utils/Panic.h>
|
||||
#include <private/utils/FeatureFlagManager.h>
|
||||
|
||||
#ifndef NDEBUG
|
||||
#include <set> // For VulkanDriver::debugCommandBegin
|
||||
@@ -151,6 +152,28 @@ static CallbackHandler::Callback syncCallbackWrapper = [](void* userData) {
|
||||
cbData->cb(cbData->sync, cbData->userData);
|
||||
};
|
||||
|
||||
/**
|
||||
* Shorthand for converting a description for an external YCbCr format used for
|
||||
* pipeline cache prewarming to the params for the actual YCbCr conversion.
|
||||
*/
|
||||
inline VulkanYcbcrConversionCache::Params getYcbcrConversionParams(const VulkanPlatform::ExternalYcbcrFormat& format) {
|
||||
return VulkanYcbcrConversionCache::Params {
|
||||
.conversion = {
|
||||
.ycbcrModel = fvkutils::getYcbcrModelConversionFilament(format.ycbcrModelConversion),
|
||||
.r = fvkutils::getSwizzleFilament(VK_COMPONENT_SWIZZLE_R, 0),
|
||||
.g = fvkutils::getSwizzleFilament(VK_COMPONENT_SWIZZLE_G, 1),
|
||||
.b = fvkutils::getSwizzleFilament(VK_COMPONENT_SWIZZLE_B, 2),
|
||||
.a = fvkutils::getSwizzleFilament(VK_COMPONENT_SWIZZLE_A, 3),
|
||||
.ycbcrRange = fvkutils::getYcbcrRangeFilament(format.ycbcrRange),
|
||||
.xChromaOffset = fvkutils::getChromaLocationFilament(VK_CHROMA_LOCATION_MIDPOINT),
|
||||
.yChromaOffset = fvkutils::getChromaLocationFilament(VK_CHROMA_LOCATION_MIDPOINT),
|
||||
.chromaFilter = SamplerMagFilter::NEAREST,
|
||||
},
|
||||
.format = VK_FORMAT_UNDEFINED,
|
||||
.externalFormat = format.externalFormat,
|
||||
};
|
||||
}
|
||||
|
||||
}// anonymous namespace
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_DEBUG_UTILS)
|
||||
@@ -250,6 +273,10 @@ VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext& context,
|
||||
mStreamedImageManager(&mExternalImageManager),
|
||||
mIsSRGBSwapChainSupported(mPlatform->getCustomization().isSRGBSwapChainSupported),
|
||||
mIsMSAASwapChainSupported(false), // TODO: support MSAA swapchain
|
||||
mAcquireSwapChainInMakeCurrent(
|
||||
driverConfig.featureFlagManager ?
|
||||
driverConfig.featureFlagManager->features.backend.vulkan.enable_acquire_swapchain_in_make_current :
|
||||
false),
|
||||
mStereoscopicType(driverConfig.stereoscopicType),
|
||||
mStereoscopicEyeCount(driverConfig.stereoscopicEyeCount),
|
||||
mAsynchronousMode(driverConfig.asynchronousMode) {
|
||||
@@ -803,12 +830,18 @@ void VulkanDriver::createProgramR(Handle<HwProgram> ph, Program&& program, utils
|
||||
}
|
||||
|
||||
// If async prewarming is enabled, let's find the proper layout and build the pipeline.
|
||||
std::array<resource_ptr<VulkanDescriptorSetLayout>, MAX_DESCRIPTOR_SET_COUNT> layouts {};
|
||||
VulkanDescriptorSetLayout::DescriptorSetLayoutArray vkLayouts {};
|
||||
bool hasExternalSamplers = false;
|
||||
for (const auto& layoutBinding : program.getDescriptorSetLayouts()) {
|
||||
DescriptorSetLayout layoutDescription = layoutBinding.layout;
|
||||
auto layoutHandle = mResourceManager.allocHandle<VulkanDescriptorSetLayout>();
|
||||
auto layout = mDescriptorSetLayoutCache.createLayout(layoutHandle, std::move(layoutDescription));
|
||||
layouts[layoutBinding.set] = layout;
|
||||
vkLayouts[layoutBinding.set] = layout->getVkLayout();
|
||||
if (layout->bitmask.externalSampler.count() > 0) {
|
||||
hasExternalSamplers = true;
|
||||
}
|
||||
}
|
||||
|
||||
StereoscopicType stereoscopicType = mStereoscopicType;
|
||||
@@ -816,13 +849,51 @@ void VulkanDriver::createProgramR(Handle<HwProgram> ph, Program&& program, utils
|
||||
stereoscopicType = StereoscopicType::NONE;
|
||||
}
|
||||
|
||||
VkPipelineLayout layout = mPipelineLayoutCache.getLayout(vkLayouts, vprogram);
|
||||
// Base case - build the pipeline without any external samplers.
|
||||
mPipelineCache.asyncPrewarmCache(
|
||||
*vprogram.get(),
|
||||
layout,
|
||||
mPipelineLayoutCache.getLayout(vkLayouts, vprogram),
|
||||
stereoscopicType,
|
||||
mStereoscopicEyeCount,
|
||||
program.getPriorityQueue());
|
||||
|
||||
if (!hasExternalSamplers) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we have external samplers, let's do this again with the external samplers
|
||||
// specified.
|
||||
for (const auto& format : mContext.getPipelineCachePrewarmExternalFormats()) {
|
||||
// The values that seem to matter in terms of cache hits here are the model conversion,
|
||||
// and model range. We need some value for externalFormat that is known to support that
|
||||
// pair of values, but we need not find every possible externalFormat. As we test on
|
||||
// more devices, this may change.
|
||||
VkSamplerYcbcrConversion vkConversion = mYcbcrConversionCache.getConversion(
|
||||
getYcbcrConversionParams(format));
|
||||
VkSampler externalSampler = mSamplerCache.getSampler({.sampler = {}, .conversion = vkConversion});
|
||||
|
||||
// Update all layouts to use the external samplers.
|
||||
for (size_t i = 0; i < MAX_DESCRIPTOR_SET_COUNT; ++i) {
|
||||
if (!layouts[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// For cache prewarming, we don't need every single possible combination of external sampler
|
||||
// formats. It seems to be enough, in practicce, to simply run through a list of the types of
|
||||
// samplers that *might* appear. As long as the real pipeline is close enough to something that
|
||||
// the driver has seen before, we are able to get a cache hit.
|
||||
utils::FixedCapacityVector<VkSampler> externalSamplers (layouts[i]->bitmask.externalSampler.count(), externalSampler);
|
||||
vkLayouts[i] = mDescriptorSetLayoutCache.getVkLayout(
|
||||
layouts[i]->bitmask, layouts[i]->bitmask.externalSampler, externalSamplers);
|
||||
}
|
||||
|
||||
mPipelineCache.asyncPrewarmCache(
|
||||
*vprogram.get(),
|
||||
mPipelineLayoutCache.getLayout(vkLayouts, vprogram),
|
||||
stereoscopicType,
|
||||
mStereoscopicEyeCount,
|
||||
program.getPriorityQueue());
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanDriver::destroyProgram(Handle<HwProgram> ph) {
|
||||
@@ -2080,6 +2151,10 @@ void VulkanDriver::makeCurrent(Handle<HwSwapChain> drawSch, Handle<HwSwapChain>
|
||||
resource_ptr<VulkanSwapChain> swapChain =
|
||||
resource_ptr<VulkanSwapChain>::cast(&mResourceManager, drawSch);
|
||||
mCurrentSwapChain = swapChain;
|
||||
|
||||
if (mAcquireSwapChainInMakeCurrent) {
|
||||
acquireNextSwapchainImage();
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanDriver::commit(Handle<HwSwapChain> sch) {
|
||||
|
||||
@@ -205,6 +205,7 @@ private:
|
||||
|
||||
bool const mIsSRGBSwapChainSupported;
|
||||
bool const mIsMSAASwapChainSupported;
|
||||
bool const mAcquireSwapChainInMakeCurrent;
|
||||
backend::StereoscopicType const mStereoscopicType;
|
||||
uint8_t const mStereoscopicEyeCount;
|
||||
backend::AsynchronousMode const mAsynchronousMode;
|
||||
|
||||
@@ -265,24 +265,31 @@ void VulkanDescriptorSet::addNewSet(VkDescriptorSet vkSet, OnRecycle&& onRecycle
|
||||
|
||||
PushConstantDescription::PushConstantDescription(backend::Program const& program) {
|
||||
mRangeCount = 0;
|
||||
for (auto stage : { ShaderStage::VERTEX, ShaderStage::FRAGMENT, ShaderStage::COMPUTE }) {
|
||||
uint32_t offset = 0;
|
||||
|
||||
// The range is laid out so that the vertex constants are defined as the first set of bytes,
|
||||
// followed by fragment and compute. This means we need to keep track of the offset for each
|
||||
// stage. We do the bookeeping in mDescriptions.
|
||||
for (auto stage: { ShaderStage::VERTEX, ShaderStage::FRAGMENT, ShaderStage::COMPUTE }) {
|
||||
auto const& constants = program.getPushConstants(stage);
|
||||
if (constants.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto& description = mDescriptions[(uint8_t) stage];
|
||||
// We store the type of the constant for type-checking when writing.
|
||||
auto& types = mTypes[(uint8_t) stage];
|
||||
types.reserve(constants.size());
|
||||
std::for_each(constants.cbegin(), constants.cend(), [&types] (Program::PushConstant t) {
|
||||
types.push_back(t.type);
|
||||
});
|
||||
description.types.reserve(constants.size());
|
||||
std::for_each(constants.cbegin(), constants.cend(),
|
||||
[&description](Program::PushConstant t) { description.types.push_back(t.type); });
|
||||
|
||||
uint32_t const constantsSize = (uint32_t) constants.size() * ENTRY_SIZE;
|
||||
mRanges[mRangeCount++] = {
|
||||
.stageFlags = getVkStage(stage),
|
||||
.offset = 0,
|
||||
.size = (uint32_t) constants.size() * ENTRY_SIZE,
|
||||
.offset = offset,
|
||||
.size = constantsSize,
|
||||
};
|
||||
description.offset = offset;
|
||||
offset += constantsSize;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,7 +297,10 @@ void PushConstantDescription::write(VkCommandBuffer cmdbuf, VkPipelineLayout lay
|
||||
backend::ShaderStage stage, uint8_t index, backend::PushConstantVariant const& value) {
|
||||
|
||||
uint32_t binaryValue = 0;
|
||||
UTILS_UNUSED_IN_RELEASE auto const& types = mTypes[(uint8_t) stage];
|
||||
auto const& description = mDescriptions[(uint8_t) stage];
|
||||
UTILS_UNUSED_IN_RELEASE auto const& types = description.types;
|
||||
uint32_t const offset = description.offset;
|
||||
|
||||
if (std::holds_alternative<bool>(value)) {
|
||||
assert_invariant(types[index] == ConstantType::BOOL);
|
||||
bool const bval = std::get<bool>(value);
|
||||
@@ -304,7 +314,8 @@ void PushConstantDescription::write(VkCommandBuffer cmdbuf, VkPipelineLayout lay
|
||||
int const ival = std::get<int>(value);
|
||||
binaryValue = *reinterpret_cast<uint32_t const*>(&ival);
|
||||
}
|
||||
vkCmdPushConstants(cmdbuf, layout, getVkStage(stage), index * ENTRY_SIZE, ENTRY_SIZE,
|
||||
|
||||
vkCmdPushConstants(cmdbuf, layout, getVkStage(stage), offset + index * ENTRY_SIZE, ENTRY_SIZE,
|
||||
&binaryValue);
|
||||
}
|
||||
|
||||
|
||||
@@ -245,7 +245,13 @@ struct PushConstantDescription {
|
||||
private:
|
||||
static constexpr uint32_t ENTRY_SIZE = sizeof(uint32_t);
|
||||
|
||||
utils::FixedCapacityVector<backend::ConstantType> mTypes[Program::SHADER_TYPE_COUNT];
|
||||
struct ConstantDescription {
|
||||
utils::FixedCapacityVector<backend::ConstantType> types;
|
||||
uint32_t offset = 0;
|
||||
};
|
||||
|
||||
// Describes the constants in each shader stage.
|
||||
ConstantDescription mDescriptions[Program::SHADER_TYPE_COUNT];
|
||||
VkPushConstantRange mRanges[Program::SHADER_TYPE_COUNT];
|
||||
uint32_t mRangeCount;
|
||||
};
|
||||
|
||||
@@ -180,7 +180,12 @@ void VulkanPipelineCache::asyncPrewarmCache(const VulkanProgram& program,
|
||||
mCallbackManager.put(cmh);
|
||||
// We don't actually need this pipeline, we just wanted to force the driver to cache
|
||||
// the pipeline's information.
|
||||
vkDestroyPipeline(mDevice, pipeline, VKALLOC);
|
||||
if (pipeline != VK_NULL_HANDLE) {
|
||||
vkDestroyPipeline(mDevice, pipeline, VKALLOC);
|
||||
} else {
|
||||
FVK_LOGW << "Failed to create a pipeline during prewarming, draw-time pipeline "
|
||||
"creation may fail.";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ VkPipelineLayout VulkanPipelineLayoutCache::getLayout(
|
||||
|
||||
// build the push constant layout key
|
||||
uint32_t const pushConstantRangeCount = program->getPushConstantRangeCount();
|
||||
auto const& pushConstantRanges = program->getPushConstantRanges();
|
||||
auto pushConstantRanges = program->getPushConstantRanges();
|
||||
if (pushConstantRangeCount > 0) {
|
||||
assert_invariant(pushConstantRangeCount <= Program::SHADER_TYPE_COUNT);
|
||||
for (uint8_t i = 0; i < pushConstantRangeCount; ++i) {
|
||||
|
||||
@@ -798,6 +798,11 @@ bool VulkanPlatform::isTransientAttachmentSupported() const noexcept {
|
||||
return mImpl->mContext.isLazilyAllocatedMemorySupported();
|
||||
}
|
||||
|
||||
void VulkanPlatform::registerPipelineCachePrewarmExternalFormat(
|
||||
const ExternalYcbcrFormat& format) noexcept {
|
||||
mImpl->mContext.addPipelineCachePrewarmExternalFormat(format);
|
||||
}
|
||||
|
||||
VkInstance VulkanPlatform::createVkInstance(const VkInstanceCreateInfo& createInfo) noexcept {
|
||||
VkInstance instance = VK_NULL_HANDLE;
|
||||
VkResult result = vkCreateInstance(&createInfo, VKALLOC, &instance);
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/Panic.h>
|
||||
|
||||
#include <bluevk/BlueVK.h>
|
||||
@@ -538,9 +539,18 @@ bool VulkanPlatformAndroid::queryCompositorTiming(SwapChain const* swapchain,
|
||||
|
||||
AndroidFrameCallback::Timeline const preferredTimeline{
|
||||
mAndroidDetails.androidFrameCallback.getPreferredTimeline() };
|
||||
outCompositorTiming->frameTime = preferredTimeline.frameTime;
|
||||
outCompositorTiming->expectedPresentTime = preferredTimeline.expectedPresentTime;
|
||||
outCompositorTiming->frameTimelineDeadline = preferredTimeline.frameTimelineDeadline;
|
||||
// FIXME: expectedPresentLatency might reflect the previous frame's value because
|
||||
// the choreographer's callback can happen before (good) or after (bad) us.
|
||||
// This problem is mitigated by storing the latency instead of the deadline,
|
||||
// because it generally is constant frame to frame.
|
||||
if (UTILS_LIKELY(preferredTimeline.expectedPresentTime > preferredTimeline.frameTime)) {
|
||||
// latency can never be negative, let's be safe
|
||||
outCompositorTiming->expectedPresentLatency =
|
||||
preferredTimeline.expectedPresentTime - preferredTimeline.frameTime;
|
||||
} else {
|
||||
// fake a reasonable value (33ms)
|
||||
outCompositorTiming->expectedPresentLatency = 33'000'000;
|
||||
}
|
||||
outCompositorTiming->compositeDeadline = CompositorTiming::INVALID;
|
||||
outCompositorTiming->compositeInterval = CompositorTiming::INVALID;
|
||||
outCompositorTiming->compositeToPresentLatency = CompositorTiming::INVALID;
|
||||
|
||||
@@ -72,7 +72,13 @@ void main() {
|
||||
static const char* const triangleFs = R"(#version 450 core
|
||||
|
||||
layout(push_constant) uniform Constants {
|
||||
#if defined(TARGET_VULKAN_ENVIRONMENT)
|
||||
// offset here accounts for the size of the push constants in the vertex stage. Vulkan has one
|
||||
// block of memory for all stages to share.
|
||||
layout(offset=16) float red;
|
||||
#else
|
||||
float red;
|
||||
#endif
|
||||
bool padding; // test correct bool padding
|
||||
float green;
|
||||
float blue;
|
||||
@@ -104,8 +110,9 @@ void initPushConstants() {
|
||||
}
|
||||
|
||||
TEST_F(BackendTest, PushConstants) {
|
||||
SKIP_IF(SkipEnvironment(OperatingSystem::CI, Backend::VULKAN), "see b/453776664");
|
||||
SKIP_IF(Backend::WEBGPU, "Push constants not supported on WebGPU");
|
||||
// Test is flaky on CI (but does not repro locally).
|
||||
SKIP_IF(SkipEnvironment(OperatingSystem::CI, Backend::VULKAN), "b/453776664");
|
||||
|
||||
initPushConstants();
|
||||
|
||||
|
||||
@@ -44,8 +44,8 @@ public:
|
||||
math::float3 halfExtent = {};
|
||||
|
||||
/**
|
||||
* Whether the box is empty, i.e.: it's volume is null.
|
||||
* @return true if the volume of the box is null
|
||||
* Whether the box is empty, i.e.: its extents are zero.
|
||||
* @return true if the extents of the box are zero
|
||||
*/
|
||||
constexpr bool isEmpty() const noexcept {
|
||||
return length2(halfExtent) == 0;
|
||||
|
||||
@@ -311,7 +311,7 @@ public:
|
||||
|
||||
/** Sets an additional matrix that scales the projection matrix.
|
||||
*
|
||||
* This is useful to adjust the aspect ratio of the camera independent from its projection.
|
||||
* This is useful to adjust the aspect ratio of the camera independent of its projection.
|
||||
* First, pass an aspect of 1.0 to setProjection. Then set the scaling with the desired aspect
|
||||
* ratio:
|
||||
*
|
||||
|
||||
@@ -57,7 +57,7 @@ public:
|
||||
* Blocks the current thread until the Fence signals.
|
||||
*
|
||||
* @param mode Whether the command stream is flushed before waiting or not.
|
||||
* @param timeout Wait time out. Using a \p timeout of 0 is a way to query the state of the fence.
|
||||
* @param timeout Wait time out in nanoseconds. Using a \p timeout of 0 is a way to query the state of the fence.
|
||||
* A \p timeout value of FENCE_WAIT_FOR_EVER is used to disable the timeout.
|
||||
* @return FenceStatus::CONDITION_SATISFIED on success,
|
||||
* FenceStatus::TIMEOUT_EXPIRED if the time out expired or
|
||||
|
||||
@@ -51,6 +51,13 @@ class FMaterial;
|
||||
|
||||
class Engine;
|
||||
|
||||
/**
|
||||
* A Material defines the visual appearance of a surface.
|
||||
*
|
||||
* Materials are created from a binary blob generated by the material compiler (matc).
|
||||
* A Material is a template from which MaterialInstance objects can be created.
|
||||
*
|
||||
*/
|
||||
class UTILS_PUBLIC Material : public FilamentAPI {
|
||||
struct BuilderDetails;
|
||||
|
||||
|
||||
@@ -42,6 +42,13 @@ class TextureSampler;
|
||||
class UniformBuffer;
|
||||
class BufferInterfaceBlock;
|
||||
|
||||
/**
|
||||
* A MaterialInstance represents a specific instance of a Material.
|
||||
*
|
||||
* While a Material defines the shader code and the set of parameters, a MaterialInstance
|
||||
* holds the specific values for those parameters.
|
||||
*
|
||||
*/
|
||||
class UTILS_PUBLIC MaterialInstance : public FilamentAPI {
|
||||
template<size_t N>
|
||||
using StringLiteralHelper = const char[N];
|
||||
@@ -112,6 +119,13 @@ public:
|
||||
/**
|
||||
* Set a uniform by name
|
||||
*
|
||||
* Supported types:
|
||||
* - float, float2, float3, float4
|
||||
* - int, int2, int3, int4
|
||||
* - uint, uint2, uint3, uint4
|
||||
* - bool, bool2, bool3, bool4
|
||||
* - mat3f, mat4f
|
||||
*
|
||||
* @param name Name of the parameter as defined by Material. Cannot be nullptr.
|
||||
* @param nameLength Length in `char` of the name parameter.
|
||||
* @param value Value of the parameter to set.
|
||||
|
||||
@@ -217,7 +217,7 @@ public:
|
||||
/**
|
||||
* Specify the type of geometry for this renderable. DYNAMIC geometry has no restriction,
|
||||
* STATIC_BOUNDS geometry means that both the bounds and the world-space transform of the
|
||||
* the renderable are immutable.
|
||||
* renderable are immutable.
|
||||
* STATIC geometry has the same restrictions as STATIC_BOUNDS, but in addition disallows
|
||||
* skinning, morphing and changing the VertexBuffer or IndexBuffer in any way.
|
||||
* @param type type of geometry.
|
||||
|
||||
@@ -107,7 +107,7 @@ public:
|
||||
time_point_ns presentDeadline; //!< deadline for queuing a frame [ns]
|
||||
duration_ns displayPresentInterval; //!< display refresh rate [ns]
|
||||
duration_ns compositionToPresentLatency; //!< time between the start of composition and the expected present time [ns]
|
||||
time_point_ns expectedPresentTime; //!< system's expected presentation time since epoch [ns]
|
||||
duration_ns expectedPresentLatency; //!< system's expected presentation time since epoch [ns]
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -668,7 +668,7 @@ public:
|
||||
* Requests the next frameCount frames to be skipped. For Debugging.
|
||||
* @param frameCount number of frames to skip.
|
||||
*/
|
||||
void skipNextFrames(size_t frameCount) const noexcept;
|
||||
void skipNextFrames(size_t frameCount) noexcept;
|
||||
|
||||
/**
|
||||
* Remainder count of frame to be skipped
|
||||
|
||||
@@ -106,7 +106,7 @@ public:
|
||||
/**
|
||||
* Adds an Entity to the Scene.
|
||||
*
|
||||
* @param entity The entity is ignored if it doesn't have a Renderable or Light component.
|
||||
* @param entity The entity is ignored for rendering purposes if it doesn't have a Renderable or Light component.
|
||||
*
|
||||
* \attention
|
||||
* A given Entity object can only be added once to a Scene.
|
||||
|
||||
@@ -136,7 +136,7 @@ public:
|
||||
* priority (7) such that the Skybox is always rendered after the opaque objects,
|
||||
* to reduce overdraw when depth culling is enabled.
|
||||
*
|
||||
* @param priority clamped to the range [0..7], defaults to 4; 7 is lowest priority
|
||||
* @param priority clamped to the range [0..7], defaults to 7; 7 is lowest priority
|
||||
* (rendered last).
|
||||
*
|
||||
* @return Builder reference for chaining calls.
|
||||
|
||||
@@ -69,12 +69,11 @@ class Engine;
|
||||
* - Filament invokes low-level graphics commands on the \em{driver thread}.
|
||||
* - The thread that calls `beginFrame` is called the \em{main thread}.
|
||||
*
|
||||
* For ACQUIRED streams, there is no need to perform the copy because Filament explictly acquires
|
||||
* For ACQUIRED streams, there is no need to perform the copy because Filament explicitly acquires
|
||||
* the stream, then releases it later via a callback function. This configuration is especially
|
||||
* useful when the Vulkan backend is enabled.
|
||||
*
|
||||
* For NATIVE streams, Filament does not make any synchronization guarantee. However they are simple
|
||||
* to use and do not incur a copy. These are often appropriate in video applications.
|
||||
* NATIVE streams are deprecated because they are backend specific and do not make any synchronization guarantee.
|
||||
*
|
||||
* Please see `sample-stream-test` and `sample-hello-camera` for usage examples.
|
||||
*
|
||||
@@ -116,7 +115,9 @@ public:
|
||||
* be CLAMP_TO_EDGE.
|
||||
*
|
||||
* @return This Builder, for chaining calls.
|
||||
* @deprecated Use Stream::setAcquiredImage instead.
|
||||
*/
|
||||
UTILS_DEPRECATED
|
||||
Builder& stream(void* UTILS_NULLABLE stream) noexcept;
|
||||
|
||||
/**
|
||||
|
||||
@@ -399,7 +399,8 @@ public:
|
||||
* @param width Width of the sub-region to update.
|
||||
* @param height Height of the sub-region to update.
|
||||
* @param depth Depth of the sub-region to update.
|
||||
* @param buffer Client-side buffer containing the image to set.
|
||||
* @param buffer Client-side buffer containing the image to set. The driver will invoke
|
||||
* the callback associated with this buffer when the data has been consumed.
|
||||
*
|
||||
* @attention \p engine must be the instance passed to Builder::build()
|
||||
* @attention \p level must be less than getLevels().
|
||||
|
||||
@@ -38,12 +38,16 @@
|
||||
#include <filament/Engine.h>
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
#include <backend/CallbackHandler.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/Invocable.h>
|
||||
#include <utils/Panic.h>
|
||||
#include <utils/Slice.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
@@ -363,7 +367,7 @@ void Engine::flushAndWait() {
|
||||
downcast(this)->flushAndWait();
|
||||
}
|
||||
|
||||
bool Engine::flushAndWait(uint64_t timeout) {
|
||||
bool Engine::flushAndWait(uint64_t const timeout) {
|
||||
return downcast(this)->flushAndWait(timeout);
|
||||
}
|
||||
|
||||
|
||||
@@ -135,12 +135,7 @@ void FrameInfoManager::beginFrame(FSwapChain* swapChain, DriverApi& driver,
|
||||
front.presentDeadline = compositorTiming.compositeDeadline;
|
||||
front.displayPresentInterval = compositorTiming.compositeInterval;
|
||||
front.compositionToPresentLatency = compositorTiming.compositeToPresentLatency;
|
||||
front.expectedPresentTime = compositorTiming.expectedPresentTime;
|
||||
if (compositorTiming.frameTime != CompositorTiming::INVALID) {
|
||||
// of we have a vsync time from the compositor, ignore the one from the user
|
||||
front.vsync = FrameInfoImpl::time_point{
|
||||
std::chrono::nanoseconds(compositorTiming.frameTime) };
|
||||
}
|
||||
front.expectedPresentLatency = compositorTiming.expectedPresentLatency;
|
||||
}
|
||||
|
||||
if (mHasTimerQueries) {
|
||||
@@ -334,6 +329,7 @@ void FrameInfoManager::updateUserHistory(FSwapChain* swapChain, DriverApi& drive
|
||||
if (success) {
|
||||
assert_invariant(entry.displayPresent < 0 ||
|
||||
entry.displayPresent == frameTimestamps.displayPresentTime);
|
||||
|
||||
entry.displayPresent = frameTimestamps.displayPresentTime;
|
||||
}
|
||||
} else {
|
||||
@@ -366,8 +362,7 @@ void FrameInfoManager::updateUserHistory(FSwapChain* swapChain, DriverApi& drive
|
||||
.presentDeadline = entry.presentDeadline,
|
||||
.displayPresentInterval = entry.displayPresentInterval,
|
||||
.compositionToPresentLatency = entry.compositionToPresentLatency,
|
||||
.expectedPresentTime = entry.expectedPresentTime,
|
||||
|
||||
.expectedPresentLatency = entry.expectedPresentLatency
|
||||
});
|
||||
}
|
||||
std::swap(mUserFrameHistory, result);
|
||||
|
||||
@@ -80,8 +80,8 @@ struct FrameInfoImpl : public details::FrameInfo {
|
||||
CompositorTiming::duration_ns displayPresentInterval{ FrameTimestamps::INVALID };
|
||||
// time between the start of composition and the expected present time [ns]
|
||||
CompositorTiming::duration_ns compositionToPresentLatency{ FrameTimestamps::INVALID };
|
||||
// system's expected present time [ns]
|
||||
FrameTimestamps::time_point_ns expectedPresentTime{ FrameTimestamps::INVALID };
|
||||
// system's expected present latency from vsync [ns]
|
||||
CompositorTiming::duration_ns expectedPresentLatency{ FrameTimestamps::INVALID };
|
||||
|
||||
// the fence used for gpuFrameComplete
|
||||
backend::FenceHandle fence{};
|
||||
|
||||
@@ -50,7 +50,6 @@ void FrameSkipper::terminate(DriverApi& driver) noexcept {
|
||||
bool FrameSkipper::shouldRenderFrame(DriverApi& driver) const noexcept {
|
||||
|
||||
if (UTILS_UNLIKELY(mFrameToSkip)) {
|
||||
mFrameToSkip--;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -86,7 +85,7 @@ void FrameSkipper::submitFrame(DriverApi& driver) noexcept {
|
||||
fences[last] = driver.createFence();
|
||||
}
|
||||
|
||||
void FrameSkipper::skipNextFrames(size_t frameCount) const noexcept {
|
||||
void FrameSkipper::skipNextFrames(size_t frameCount) noexcept {
|
||||
frameCount = std::min(frameCount, size_t(std::numeric_limits<decltype(mFrameToSkip)>::max()));
|
||||
mFrameToSkip = uint16_t(frameCount);
|
||||
}
|
||||
|
||||
@@ -69,10 +69,17 @@ public:
|
||||
// Returns true if rendering can proceed. Always call submitFrame() when done.
|
||||
bool shouldRenderFrame(backend::DriverApi& driver) const noexcept;
|
||||
|
||||
// Call this when a frame is skipped (i.e. submitFrame() is NOT called)
|
||||
void frameSkipped() noexcept {
|
||||
if (mFrameToSkip) {
|
||||
mFrameToSkip--;
|
||||
}
|
||||
}
|
||||
|
||||
void submitFrame(backend::DriverApi& driver) noexcept;
|
||||
|
||||
// set frameCount frame to report as "skip". For debugging.
|
||||
void skipNextFrames(size_t frameCount) const noexcept;
|
||||
void skipNextFrames(size_t frameCount) noexcept;
|
||||
// return remaining number of frame to be skipped
|
||||
size_t getFrameToSkipCount() const noexcept;
|
||||
|
||||
@@ -80,7 +87,7 @@ private:
|
||||
using Container = std::array<backend::Handle<backend::HwFence>, MAX_FRAME_LATENCY>;
|
||||
Container mDelayedFences{};
|
||||
uint8_t const mLatency;
|
||||
mutable uint16_t mFrameToSkip{};
|
||||
uint16_t mFrameToSkip{};
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -13,22 +13,42 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "MaterialDefinition.h"
|
||||
|
||||
#include "Froxelizer.h"
|
||||
#include "MaterialParser.h"
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
#include <ds/ColorPassDescriptorSet.h>
|
||||
|
||||
#include <details/Engine.h>
|
||||
|
||||
#include <private/filament/EngineEnums.h>
|
||||
#include <private/filament/DescriptorSets.h>
|
||||
#include <private/filament/PushConstantInfo.h>
|
||||
|
||||
#include <filament/MaterialEnums.h>
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
#include <string_view>
|
||||
#include <utils/CString.h>
|
||||
#include <utils/bitset.h>
|
||||
#include <utils/debug.h>
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/Logger.h>
|
||||
#include <utils/Panic.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
|
||||
namespace filament {
|
||||
|
||||
using namespace backend;
|
||||
@@ -83,7 +103,7 @@ std::unique_ptr<MaterialDefinition> MaterialDefinition::create(FEngine& engine,
|
||||
uint32_t parsedCrc32 = 0;
|
||||
parser->getMaterialCrc32(&parsedCrc32);
|
||||
|
||||
uint32_t expectedCrc32 = parser->computeCrc32();
|
||||
uint32_t const expectedCrc32 = parser->computeCrc32();
|
||||
|
||||
if (parsedCrc32 != expectedCrc32) {
|
||||
CString name;
|
||||
@@ -131,9 +151,9 @@ std::unique_ptr<MaterialDefinition> MaterialDefinition::create(FEngine& engine,
|
||||
CString name;
|
||||
parser->getName(&name);
|
||||
LOG(WARNING) << "The stereoscopic type in the compiled material '"
|
||||
<< name.c_str_safe() << "' is " << (int) materialStereoscopicType
|
||||
<< name.c_str_safe() << "' is " << int(materialStereoscopicType)
|
||||
<< ", which is not compatible with the engine's setting "
|
||||
<< (int) engineStereoscopicType << ".";
|
||||
<< int(engineStereoscopicType) << ".";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -168,16 +188,16 @@ void MaterialDefinition::processMain() {
|
||||
uint8_t level = 1;
|
||||
mMaterialParser->getFeatureLevel(&level);
|
||||
assert_invariant(level <= 3);
|
||||
FeatureLevel featureLevel = FeatureLevel::FEATURE_LEVEL_1;
|
||||
FeatureLevel result = FeatureLevel::FEATURE_LEVEL_1;
|
||||
switch (FeatureLevel(level)) {
|
||||
case FeatureLevel::FEATURE_LEVEL_0:
|
||||
case FeatureLevel::FEATURE_LEVEL_1:
|
||||
case FeatureLevel::FEATURE_LEVEL_2:
|
||||
case FeatureLevel::FEATURE_LEVEL_3:
|
||||
featureLevel = FeatureLevel(level);
|
||||
result = FeatureLevel(level);
|
||||
break;
|
||||
}
|
||||
return featureLevel;
|
||||
return result;
|
||||
}();
|
||||
|
||||
UTILS_UNUSED_IN_RELEASE bool success;
|
||||
@@ -346,6 +366,8 @@ void MaterialDefinition::processBlendingMode() {
|
||||
}
|
||||
|
||||
void MaterialDefinition::processSpecializationConstants(FEngine& engine) {
|
||||
FEngine::DriverApi& driver = engine.getDriverApi();
|
||||
|
||||
// Older materials won't have a constants chunk, but that's okay.
|
||||
mMaterialParser->getConstants(&materialConstants);
|
||||
|
||||
@@ -364,18 +386,18 @@ void MaterialDefinition::processSpecializationConstants(FEngine& engine) {
|
||||
|
||||
specializationConstants
|
||||
[+ReservedSpecializationConstants::CONFIG_STATIC_TEXTURE_TARGET_WORKAROUND] =
|
||||
engine.getDriverApi().isWorkaroundNeeded(
|
||||
driver.isWorkaroundNeeded(
|
||||
Workaround::METAL_STATIC_TEXTURE_TARGET_ERROR);
|
||||
|
||||
specializationConstants[+ReservedSpecializationConstants::CONFIG_SRGB_SWAPCHAIN_EMULATION] =
|
||||
engine.getDriverApi().isWorkaroundNeeded(Workaround::EMULATE_SRGB_SWAPCHAIN);
|
||||
driver.isWorkaroundNeeded(Workaround::EMULATE_SRGB_SWAPCHAIN);
|
||||
|
||||
// The 16u below denotes the 16 bytes in a uvec4, which is how the froxel buffer is stored.
|
||||
specializationConstants[+ReservedSpecializationConstants::CONFIG_FROXEL_BUFFER_HEIGHT] =
|
||||
int(Froxelizer::getFroxelBufferByteCount(engine.getDriverApi()) / 16u);
|
||||
int(Froxelizer::getFroxelBufferByteCount(driver) / 16u);
|
||||
|
||||
specializationConstants[+ReservedSpecializationConstants::CONFIG_POWER_VR_SHADER_WORKAROUNDS] =
|
||||
engine.getDriverApi().isWorkaroundNeeded(Workaround::POWER_VR_SHADER_WORKAROUNDS);
|
||||
driver.isWorkaroundNeeded(Workaround::POWER_VR_SHADER_WORKAROUNDS);
|
||||
|
||||
specializationConstants[+ReservedSpecializationConstants::CONFIG_DEBUG_DIRECTIONAL_SHADOWMAP] =
|
||||
engine.debug.shadowmap.debug_directional_shadowmap;
|
||||
@@ -393,7 +415,7 @@ void MaterialDefinition::processSpecializationConstants(FEngine& engine) {
|
||||
specializationConstants[+ReservedSpecializationConstants::CONFIG_SHADOW_SAMPLING_METHOD] = 0;
|
||||
|
||||
specializationConstants[+ReservedSpecializationConstants::CONFIG_FROXEL_RECORD_BUFFER_HEIGHT] =
|
||||
int(Froxelizer::getFroxelRecordBufferByteCount(engine.getDriverApi()) / 16u);
|
||||
int(Froxelizer::getFroxelRecordBufferByteCount(driver) / 16u);
|
||||
|
||||
// Initialize the rest of the reserved constants with a dummy value.
|
||||
for (size_t i = CONFIG_NEXT_RESERVED_SPEC_CONSTANT; i < CONFIG_MAX_RESERVED_SPEC_CONSTANTS;
|
||||
@@ -426,23 +448,21 @@ void MaterialDefinition::processSpecializationConstants(FEngine& engine) {
|
||||
}
|
||||
|
||||
void MaterialDefinition::processPushConstants() {
|
||||
FixedCapacityVector<Program::PushConstant>& vertexConstants =
|
||||
pushConstants[uint8_t(ShaderStage::VERTEX)];
|
||||
FixedCapacityVector<Program::PushConstant>& fragmentConstants =
|
||||
pushConstants[uint8_t(ShaderStage::FRAGMENT)];
|
||||
FixedCapacityVector<Program::PushConstant>& vertexConstants = pushConstants[uint8_t(ShaderStage::VERTEX)];
|
||||
FixedCapacityVector<Program::PushConstant>& fragmentConstants = pushConstants[uint8_t(ShaderStage::FRAGMENT)];
|
||||
|
||||
CString structVarName;
|
||||
FixedCapacityVector<MaterialPushConstant> pushConstants;
|
||||
mMaterialParser->getPushConstants(&structVarName, &pushConstants);
|
||||
FixedCapacityVector<MaterialPushConstant> allPushConstants;
|
||||
mMaterialParser->getPushConstants(&structVarName, &allPushConstants);
|
||||
|
||||
vertexConstants.reserve(pushConstants.size());
|
||||
fragmentConstants.reserve(pushConstants.size());
|
||||
vertexConstants.reserve(allPushConstants.size());
|
||||
fragmentConstants.reserve(allPushConstants.size());
|
||||
|
||||
constexpr size_t MAX_NAME_LEN = 60;
|
||||
char buf[MAX_NAME_LEN];
|
||||
uint8_t vertexCount = 0, fragmentCount = 0;
|
||||
|
||||
std::for_each(pushConstants.cbegin(), pushConstants.cend(),
|
||||
std::for_each(allPushConstants.cbegin(), allPushConstants.cend(),
|
||||
[&](MaterialPushConstant const& constant) {
|
||||
snprintf(buf, sizeof(buf), "%s.%s", structVarName.c_str(), constant.name.c_str());
|
||||
|
||||
@@ -462,6 +482,9 @@ void MaterialDefinition::processPushConstants() {
|
||||
}
|
||||
|
||||
void MaterialDefinition::processDescriptorSets(FEngine& engine) {
|
||||
FEngine::DriverApi& driver = engine.getDriverApi();
|
||||
auto& descriptorSetLayoutFactory = engine.getDescriptorSetLayoutFactory();
|
||||
|
||||
UTILS_UNUSED_IN_RELEASE bool success;
|
||||
|
||||
success = mMaterialParser->getDescriptorBindings(&programDescriptorBindings);
|
||||
@@ -496,22 +519,22 @@ void MaterialDefinition::processDescriptorSets(FEngine& engine) {
|
||||
Program::DescriptorBindingsInfo& descriptors = programDescriptorBindings[+bindingPoint];
|
||||
descriptors.reserve(dsl.descriptors.size());
|
||||
for (auto const& entry: dsl.descriptors) {
|
||||
auto const& name = descriptor_sets::getDescriptorName(bindingPoint, entry.binding);
|
||||
descriptors.push_back({ name, entry.type, entry.binding });
|
||||
auto const& descriptorName = descriptor_sets::getDescriptorName(bindingPoint, entry.binding);
|
||||
descriptors.push_back({ descriptorName, entry.type, entry.binding });
|
||||
}
|
||||
}
|
||||
|
||||
this->descriptorSetLayout = {
|
||||
engine.getDescriptorSetLayoutFactory(),
|
||||
engine.getDriverApi(), this->descriptorSetLayoutDescription };
|
||||
descriptorSetLayoutFactory, driver,
|
||||
this->descriptorSetLayoutDescription };
|
||||
|
||||
this->perViewDescriptorSetLayout = {
|
||||
engine.getDescriptorSetLayoutFactory(),
|
||||
engine.getDriverApi(), this->perViewDescriptorSetLayoutDescription };
|
||||
descriptorSetLayoutFactory, driver,
|
||||
this->perViewDescriptorSetLayoutDescription };
|
||||
|
||||
this->perViewDescriptorSetLayoutVsm = {
|
||||
engine.getDescriptorSetLayoutFactory(),
|
||||
engine.getDriverApi(), this->perViewDescriptorSetLayoutVsmDescription };
|
||||
descriptorSetLayoutFactory, driver,
|
||||
this->perViewDescriptorSetLayoutVsmDescription };
|
||||
}
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -194,11 +194,11 @@ void PostProcessManager::PostProcessMaterial::loadMaterial(FEngine& engine) cons
|
||||
|
||||
UTILS_NOINLINE
|
||||
FMaterial* PostProcessManager::PostProcessMaterial::getMaterial(FEngine& engine,
|
||||
PostProcessVariant variant) const noexcept {
|
||||
DriverApi& driver, PostProcessVariant variant) const noexcept {
|
||||
if (UTILS_UNLIKELY(mSize)) {
|
||||
loadMaterial(engine);
|
||||
}
|
||||
mMaterial->prepareProgram(Variant{ Variant::type_t(variant) },
|
||||
mMaterial->prepareProgram(driver, Variant{ Variant::type_t(variant) },
|
||||
CompilerPriorityQueue::CRITICAL);
|
||||
return mMaterial;
|
||||
}
|
||||
@@ -362,6 +362,10 @@ void PostProcessManager::init() noexcept {
|
||||
mWorkaroundAllowReadOnlyAncillaryFeedbackLoop =
|
||||
driver.isWorkaroundNeeded(Workaround::ALLOW_READ_ONLY_ANCILLARY_FEEDBACK_LOOP);
|
||||
|
||||
mFeatureLevel = driver.getFeatureLevel();
|
||||
mDepthStencilResolveSupported = driver.isDepthStencilResolveSupported();
|
||||
mDepthStencilBlitSupported = driver.isDepthStencilBlitSupported(TextureFormat::DEPTH32F);
|
||||
|
||||
UTILS_NOUNROLL
|
||||
for (auto const& info: sMaterialListFeatureLevel0) {
|
||||
registerPostProcessMaterial(info.name, info);
|
||||
@@ -562,7 +566,7 @@ PostProcessManager::StructurePassOutput PostProcessManager::structure(FrameGraph
|
||||
// generate depth pass at the requested resolution
|
||||
auto const& structurePass = fg.addPass<StructurePassData>("Structure Pass",
|
||||
[&](FrameGraph::Builder& builder, auto& data) {
|
||||
bool const isES2 = mEngine.getDriverApi().getFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0;
|
||||
bool const isES2 = mFeatureLevel == FeatureLevel::FEATURE_LEVEL_0;
|
||||
data.depth = builder.createTexture("Structure Buffer", {
|
||||
.width = width, .height = height,
|
||||
.levels = uint8_t(levelCount),
|
||||
@@ -599,7 +603,7 @@ PostProcessManager::StructurePassOutput PostProcessManager::structure(FrameGraph
|
||||
passBuilder.variant(structureVariant);
|
||||
passBuilder.commandTypeFlags(RenderPass::CommandTypeFlags::SSAO);
|
||||
|
||||
RenderPass pass{ passBuilder.build(mEngine) };
|
||||
RenderPass pass{ passBuilder.build(mEngine, driver) };
|
||||
pass.finalize(mEngine, driver);
|
||||
auto const out = resources.getRenderPassInfo();
|
||||
driver.beginRenderPass(out.target, out.params);
|
||||
@@ -637,7 +641,7 @@ PostProcessManager::StructurePassOutput PostProcessManager::structure(FrameGraph
|
||||
|
||||
auto in = resources.getTexture(data.depth);
|
||||
auto& material = getPostProcessMaterial("mipmapDepth");
|
||||
FMaterial const* const ma = material.getMaterial(mEngine);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, driver);
|
||||
FMaterialInstance* const mi = getMaterialInstance(ma);
|
||||
// Only the depth texture is changing in the material instance (no UBO updates),
|
||||
// we do not move getMaterialInstance() inside the loop.
|
||||
@@ -672,7 +676,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::transparentPicking(FrameGrap
|
||||
};
|
||||
auto const& pickingRenderPass = fg.addPass<PickingRenderPassData>("Picking Render Pass",
|
||||
[&](FrameGraph::Builder& builder, auto& data) {
|
||||
bool const isFL0 = mEngine.getDriverApi().getFeatureLevel() ==
|
||||
bool const isFL0 = mFeatureLevel ==
|
||||
FeatureLevel::FEATURE_LEVEL_0;
|
||||
|
||||
// TODO: Specify the precision for picking pass
|
||||
@@ -711,7 +715,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::transparentPicking(FrameGrap
|
||||
passBuilder.variant(pickingVariant);
|
||||
passBuilder.commandTypeFlags(RenderPass::CommandTypeFlags::DEPTH);
|
||||
|
||||
RenderPass pass{ passBuilder.build(mEngine) };
|
||||
RenderPass pass{ passBuilder.build(mEngine, driver) };
|
||||
pass.finalize(mEngine, driver);
|
||||
driver.beginRenderPass(target, params);
|
||||
pass.getExecutor().execute(mEngine, driver);
|
||||
@@ -810,7 +814,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::ssr(FrameGraph& fg,
|
||||
// generate all our drawing commands, except blended objects.
|
||||
passBuilder.commandTypeFlags(RenderPass::CommandTypeFlags::SCREEN_SPACE_REFLECTIONS);
|
||||
|
||||
RenderPass pass{ passBuilder.build(mEngine) };
|
||||
RenderPass pass{ passBuilder.build(mEngine, driver) };
|
||||
pass.finalize(mEngine, driver);
|
||||
driver.beginRenderPass(out.target, out.params);
|
||||
pass.getExecutor().execute(mEngine, driver);
|
||||
@@ -1002,7 +1006,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::screenSpaceAmbientOcclusion(
|
||||
#endif
|
||||
auto& material = getPostProcessMaterial(materialName);
|
||||
|
||||
FMaterial* ma = material.getMaterial(mEngine);
|
||||
FMaterial* ma = material.getMaterial(mEngine, driver);
|
||||
bool dirty = false;
|
||||
setConstantParameter(ma, "useVisibilityBitmasks", options.gtao.useVisibilityBitmasks, dirty);
|
||||
setConstantParameter(ma, "linearThickness", options.gtao.linearThickness, dirty);
|
||||
@@ -1012,7 +1016,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::screenSpaceAmbientOcclusion(
|
||||
// with surface materials
|
||||
}
|
||||
|
||||
ma = material.getMaterial(mEngine);
|
||||
ma = material.getMaterial(mEngine, driver);
|
||||
FMaterialInstance* const mi = getMaterialInstance(ma);
|
||||
|
||||
// Set AO type specific material parameters
|
||||
@@ -1199,7 +1203,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::bilateralBlurPass(FrameGraph
|
||||
auto& material = config.bentNormals ?
|
||||
getPostProcessMaterial("bilateralBlurBentNormals") :
|
||||
getPostProcessMaterial("bilateralBlur");
|
||||
FMaterial const* const ma = material.getMaterial(mEngine);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, driver);
|
||||
FMaterialInstance* const mi = getMaterialInstance(ma);
|
||||
mi->setParameter("ssao", ssao, { /* only reads level 0 */ });
|
||||
mi->setParameter("axis", axis / float2{desc.width, desc.height});
|
||||
@@ -1368,7 +1372,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::gaussianBlurPass(FrameGraph&
|
||||
"separableGaussianBlur4L"sv : "separableGaussianBlur4"sv; break;
|
||||
}
|
||||
auto const& separableGaussianBlur = getPostProcessMaterial(materialName);
|
||||
auto ma = separableGaussianBlur.getMaterial(mEngine);
|
||||
auto ma = separableGaussianBlur.getMaterial(mEngine, driver);
|
||||
|
||||
const size_t kernelStorageSize = ma->reflect("kernel")->size;
|
||||
float2 kernel[64];
|
||||
@@ -1394,7 +1398,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::gaussianBlurPass(FrameGraph&
|
||||
|
||||
{
|
||||
// horizontal pass
|
||||
auto mi = getMaterialInstance(mEngine, separableGaussianBlur);
|
||||
auto mi = getMaterialInstance(mEngine, driver, separableGaussianBlur);
|
||||
setCommonParams(mi);
|
||||
mi->setParameter(sourceParameterName, hwIn, SamplerParams{
|
||||
.filterMag = SamplerMagFilter::LINEAR,
|
||||
@@ -1412,7 +1416,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::gaussianBlurPass(FrameGraph&
|
||||
|
||||
{
|
||||
// vertical pass
|
||||
auto mi = getMaterialInstance(mEngine, separableGaussianBlur);
|
||||
auto mi = getMaterialInstance(mEngine, driver, separableGaussianBlur);
|
||||
setCommonParams(mi);
|
||||
UTILS_UNUSED_IN_RELEASE auto width = outDesc.width;
|
||||
UTILS_UNUSED_IN_RELEASE auto height = outDesc.height;
|
||||
@@ -1822,7 +1826,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
|
||||
auto const& material = (dofResolution == 1) ?
|
||||
getPostProcessMaterial("dofCoc") :
|
||||
getPostProcessMaterial("dofDownsample");
|
||||
FMaterialInstance* const mi = getMaterialInstance(mEngine, material);
|
||||
FMaterialInstance* const mi = getMaterialInstance(mEngine, driver, material);
|
||||
|
||||
mi->setParameter("color", color, SamplerParams{
|
||||
.filterMin = SamplerMinFilter::NEAREST });
|
||||
@@ -1884,7 +1888,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
|
||||
auto inOutCoc = resources.getTexture(data.inOutCoc);
|
||||
|
||||
auto const& material = getPostProcessMaterial("dofMipmap");
|
||||
FMaterial const* const ma = material.getMaterial(mEngine);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, driver);
|
||||
|
||||
auto const pipeline = getPipelineState(ma, variant);
|
||||
|
||||
@@ -1964,7 +1968,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
|
||||
auto const& material = (!textureSwizzleSupported && (i == 0)) ?
|
||||
getPostProcessMaterial("dofTilesSwizzle") :
|
||||
getPostProcessMaterial("dofTiles");
|
||||
FMaterialInstance* const mi = getMaterialInstance(mEngine, material);
|
||||
FMaterialInstance* const mi = getMaterialInstance(mEngine, driver, material);
|
||||
mi->setParameter("cocMinMax", inCocMinMax, SamplerParams{
|
||||
.filterMin = SamplerMinFilter::NEAREST });
|
||||
mi->setParameter("texelSize", float2{ 1.0f / inputDesc.width, 1.0f / inputDesc.height });
|
||||
@@ -2001,7 +2005,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
|
||||
auto const& out = resources.getRenderPassInfo();
|
||||
auto inTilesCocMinMax = resources.getTexture(data.inTilesCocMinMax);
|
||||
auto const& material = getPostProcessMaterial("dofDilate");
|
||||
FMaterialInstance* const mi = getMaterialInstance(mEngine, material);
|
||||
FMaterialInstance* const mi = getMaterialInstance(mEngine, driver, material);
|
||||
mi->setParameter("tiles", inTilesCocMinMax, SamplerParams{
|
||||
.filterMin = SamplerMinFilter::NEAREST });
|
||||
commitAndRenderFullScreenQuad(driver, out, mi);
|
||||
@@ -2064,7 +2068,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
|
||||
auto const& inputDesc = resources.getDescriptor(data.coc);
|
||||
|
||||
auto const& material = getPostProcessMaterial("dof");
|
||||
FMaterialInstance* const mi = getMaterialInstance(mEngine, material);
|
||||
FMaterialInstance* const mi = getMaterialInstance(mEngine, driver, material);
|
||||
// it's not safe to use bilinear filtering in the general case (causes artifacts around edges)
|
||||
mi->setParameter("color", color, SamplerParams{
|
||||
.filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
|
||||
@@ -2128,7 +2132,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
|
||||
auto tilesCocMinMax = resources.getTexture(data.tilesCocMinMax);
|
||||
|
||||
auto const& material = getPostProcessMaterial("dofMedian");
|
||||
FMaterialInstance* const mi = getMaterialInstance(mEngine, material);
|
||||
FMaterialInstance* const mi = getMaterialInstance(mEngine, driver, material);
|
||||
mi->setParameter("dof", inColor, SamplerParams{
|
||||
.filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
|
||||
mi->setParameter("alpha", inAlpha, SamplerParams{
|
||||
@@ -2182,7 +2186,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
|
||||
auto tilesCocMinMax = resources.getTexture(data.tilesCocMinMax);
|
||||
|
||||
auto const& material = getPostProcessMaterial("dofCombine");
|
||||
FMaterialInstance* const mi = getMaterialInstance(mEngine, material);
|
||||
FMaterialInstance* const mi = getMaterialInstance(mEngine, driver, material);
|
||||
mi->setParameter("color", color, SamplerParams{
|
||||
.filterMin = SamplerMinFilter::NEAREST });
|
||||
mi->setParameter("dof", dof, SamplerParams{
|
||||
@@ -2219,7 +2223,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::downscalePass(FrameGraph& fg
|
||||
|
||||
auto const& out = resources.getRenderPassInfo();
|
||||
auto const& material = getPostProcessMaterial("bloomDownsample2x");
|
||||
FMaterialInstance* const mi = getMaterialInstance(mEngine, material);
|
||||
FMaterialInstance* const mi = getMaterialInstance(mEngine, driver, material);
|
||||
mi->setParameter("source", resources.getTexture(data.input), SamplerParams{
|
||||
.filterMag = SamplerMagFilter::LINEAR,
|
||||
.filterMin = SamplerMinFilter::LINEAR
|
||||
@@ -2363,10 +2367,10 @@ PostProcessManager::BloomPassOutput PostProcessManager::bloom(FrameGraph& fg,
|
||||
auto hwOut = resources.getTexture(data.out);
|
||||
|
||||
auto const& material9 = getPostProcessMaterial("bloomDownsample9");
|
||||
auto* mi9 = getMaterialInstance(mEngine, material9);
|
||||
auto* mi9 = getMaterialInstance(mEngine, driver, material9);
|
||||
|
||||
auto const& material13 = getPostProcessMaterial("bloomDownsample");
|
||||
auto* mi13 = getMaterialInstance(mEngine, material13);
|
||||
auto* mi13 = getMaterialInstance(mEngine, driver, material13);
|
||||
// These material instances have no UBO updates in the loop, so we do not move
|
||||
// getMaterialInstance() inside the loop.
|
||||
|
||||
@@ -2411,7 +2415,7 @@ PostProcessManager::BloomPassOutput PostProcessManager::bloom(FrameGraph& fg,
|
||||
auto const& outDesc = resources.getDescriptor(data.out);
|
||||
|
||||
auto const& material = getPostProcessMaterial("bloomUpsample");
|
||||
FMaterial const* const ma = material.getMaterial(mEngine);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, driver);
|
||||
|
||||
auto pipeline = getPipelineState(ma);
|
||||
pipeline.rasterState.blendFunctionSrcRGB = BlendFunction::ONE;
|
||||
@@ -2475,7 +2479,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::flarePass(FrameGraph& fg,
|
||||
|
||||
auto const& material = getPostProcessMaterial("flare");
|
||||
FMaterialInstance* const mi =
|
||||
getMaterialInstance(mEngine, material);
|
||||
getMaterialInstance(mEngine, driver, material);
|
||||
|
||||
mi->setParameter("color", in, SamplerParams{
|
||||
.filterMag = SamplerMagFilter::LINEAR,
|
||||
@@ -2539,7 +2543,7 @@ void PostProcessManager::colorGradingPrepareSubpass(DriverApi& driver,
|
||||
uint32_t const width, uint32_t const height) noexcept {
|
||||
auto& material = getPostProcessMaterial("colorGradingAsSubpass");
|
||||
FMaterialInstance const* const mi =
|
||||
configureColorGradingMaterial(material, colorGrading, colorGradingConfig,
|
||||
configureColorGradingMaterial(driver, material, colorGrading, colorGradingConfig,
|
||||
vignetteOptions, width, height);
|
||||
mi->commit(driver, getUboManager());
|
||||
}
|
||||
@@ -2554,7 +2558,7 @@ void PostProcessManager::colorGradingSubpass(DriverApi& driver,
|
||||
PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE;
|
||||
|
||||
auto const& material = getPostProcessMaterial("colorGradingAsSubpass");
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, variant);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, driver, variant);
|
||||
// the UBO has been set and committed in colorGradingPrepareSubpass()
|
||||
int32_t const fixedIndex = colorGradingConfig.translucent
|
||||
? mFixedMaterialInstanceIndex.colorGradingTranslucent
|
||||
@@ -2570,7 +2574,7 @@ void PostProcessManager::colorGradingSubpass(DriverApi& driver,
|
||||
|
||||
void PostProcessManager::customResolvePrepareSubpass(DriverApi& driver, CustomResolveOp const op) noexcept {
|
||||
auto const& material = getPostProcessMaterial("customResolveAsSubpass");
|
||||
auto const ma = material.getMaterial(mEngine, PostProcessVariant::OPAQUE);
|
||||
auto const ma = material.getMaterial(mEngine, driver, PostProcessVariant::OPAQUE);
|
||||
auto [mi, fixedIndex] = mMaterialInstanceManager.getFixedMaterialInstance(ma);
|
||||
mFixedMaterialInstanceIndex.customResolve = fixedIndex;
|
||||
mi->setParameter("direction", op == CustomResolveOp::COMPRESS ? 1.0f : -1.0f),
|
||||
@@ -2582,7 +2586,7 @@ void PostProcessManager::customResolveSubpass(DriverApi& driver) noexcept {
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
|
||||
auto const& material = getPostProcessMaterial("customResolveAsSubpass");
|
||||
FMaterial const* const ma = material.getMaterial(mEngine);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, driver);
|
||||
// the UBO has been set and committed in customResolvePrepareSubpass()
|
||||
FMaterialInstance const* mi = mMaterialInstanceManager.getMaterialInstance(ma,
|
||||
mFixedMaterialInstanceIndex.customResolve);
|
||||
@@ -2623,7 +2627,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::customResolveUncompressPass(
|
||||
|
||||
void PostProcessManager::clearAncillaryBuffersPrepare(DriverApi& driver) noexcept {
|
||||
auto const& material = getPostProcessMaterial("clearDepth");
|
||||
auto ma = material.getMaterial(mEngine, PostProcessVariant::OPAQUE);
|
||||
auto ma = material.getMaterial(mEngine, driver, PostProcessVariant::OPAQUE);
|
||||
auto [mi, fixedIndex] = mMaterialInstanceManager.getFixedMaterialInstance(ma);
|
||||
mFixedMaterialInstanceIndex.clearDepth = fixedIndex;
|
||||
mi->commit(driver, getUboManager());
|
||||
@@ -2641,7 +2645,7 @@ void PostProcessManager::clearAncillaryBuffers(DriverApi& driver,
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
|
||||
auto const& material = getPostProcessMaterial("clearDepth");
|
||||
FMaterial const* const ma = material.getMaterial(mEngine);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, driver);
|
||||
|
||||
// the UBO has been set and committed in clearAncillaryBuffersPrepare()
|
||||
FMaterialInstance const* const mi = mMaterialInstanceManager.getMaterialInstance(ma,
|
||||
@@ -2745,7 +2749,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::colorGrading(FrameGraph& fg,
|
||||
|
||||
auto& material = getPostProcessMaterial("colorGrading");
|
||||
FMaterialInstance* const mi =
|
||||
configureColorGradingMaterial(material, colorGrading, colorGradingConfig,
|
||||
configureColorGradingMaterial(driver, material, colorGrading, colorGradingConfig,
|
||||
vignetteOptions, output.width, output.height);
|
||||
|
||||
mi->setParameter("colorBuffer", colorTexture, { /* shader uses texelFetch */ });
|
||||
@@ -2830,7 +2834,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::fxaa(FrameGraph& fg,
|
||||
PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE;
|
||||
|
||||
FMaterialInstance* const mi =
|
||||
getMaterialInstance(mEngine, material, variant);
|
||||
getMaterialInstance(mEngine, driver, material, variant);
|
||||
|
||||
mi->setParameter("colorBuffer", texture, SamplerParams{
|
||||
.filterMag = SamplerMagFilter::LINEAR,
|
||||
@@ -2905,10 +2909,10 @@ void PostProcessManager::TaaJitterCamera(
|
||||
inoutCameraInfo->clipTransform.zw -= jitterInClipSpace;
|
||||
}
|
||||
|
||||
void PostProcessManager::configureTemporalAntiAliasingMaterial(
|
||||
void PostProcessManager::configureTemporalAntiAliasingMaterial(backend::DriverApi& driver,
|
||||
TemporalAntiAliasingOptions const& taaOptions) noexcept {
|
||||
|
||||
FMaterial* const ma = getPostProcessMaterial("taa").getMaterial(mEngine);
|
||||
FMaterial* const ma = getPostProcessMaterial("taa").getMaterial(mEngine, driver);
|
||||
bool dirty = false;
|
||||
|
||||
setConstantParameter(ma, "upscaling", taaOptions.upscaling > 1.0f, dirty);
|
||||
@@ -2928,11 +2932,11 @@ void PostProcessManager::configureTemporalAntiAliasingMaterial(
|
||||
}
|
||||
}
|
||||
|
||||
FMaterialInstance* PostProcessManager::configureColorGradingMaterial(
|
||||
FMaterialInstance* PostProcessManager::configureColorGradingMaterial(backend::DriverApi& driver,
|
||||
PostProcessMaterial const& material, FColorGrading const* colorGrading,
|
||||
ColorGradingConfig const& colorGradingConfig, VignetteOptions const& vignetteOptions,
|
||||
uint32_t const width, uint32_t const height) noexcept {
|
||||
FMaterial* ma = material.getMaterial(mEngine);
|
||||
FMaterial* ma = material.getMaterial(mEngine, driver);
|
||||
bool dirty = false;
|
||||
|
||||
setConstantParameter(ma, "isOneDimensional", colorGrading->isOneDimensional(), dirty);
|
||||
@@ -2947,7 +2951,7 @@ FMaterialInstance* PostProcessManager::configureColorGradingMaterial(
|
||||
PostProcessVariant const variant = colorGradingConfig.translucent
|
||||
? PostProcessVariant::TRANSLUCENT
|
||||
: PostProcessVariant::OPAQUE;
|
||||
ma = material.getMaterial(mEngine, variant);
|
||||
ma = material.getMaterial(mEngine, driver, variant);
|
||||
FMaterialInstance* mi = nullptr;
|
||||
int32_t& fixedIndex = colorGradingConfig.translucent
|
||||
? mFixedMaterialInstanceIndex.colorGradingTranslucent
|
||||
@@ -3064,7 +3068,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::taa(FrameGraph& fg,
|
||||
PostProcessVariant const variant = colorGradingConfig.translucent ?
|
||||
PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE;
|
||||
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, variant);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, driver, variant);
|
||||
|
||||
FMaterialInstance* mi = getMaterialInstance(ma);
|
||||
mi->setParameter("color", color, SamplerParams{}); // nearest
|
||||
@@ -3176,7 +3180,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::rcas(
|
||||
|
||||
auto const& material = getPostProcessMaterial("fsr_rcas");
|
||||
FMaterialInstance* const mi =
|
||||
getMaterialInstance(mEngine, material, variant);
|
||||
getMaterialInstance(mEngine, driver, material, variant);
|
||||
|
||||
FSRUniforms uniforms;
|
||||
FSR_SharpeningSetup(&uniforms, { .sharpness = 2.0f - 2.0f * sharpness });
|
||||
@@ -3188,7 +3192,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::rcas(
|
||||
mi->commit(driver, getUboManager());
|
||||
mi->use(driver);
|
||||
|
||||
auto pipeline = getPipelineState(material.getMaterial(mEngine), variant);
|
||||
auto pipeline = getPipelineState(material.getMaterial(mEngine, driver), variant);
|
||||
if (mode == RcasMode::BLENDED) {
|
||||
pipeline.rasterState.blendFunctionSrcRGB = BlendFunction::ONE;
|
||||
pipeline.rasterState.blendFunctionSrcAlpha = BlendFunction::ONE;
|
||||
@@ -3263,7 +3267,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleBilinear(FrameGraph&
|
||||
|
||||
auto& material = getPostProcessMaterial("blitLow");
|
||||
FMaterialInstance* const mi =
|
||||
getMaterialInstance(mEngine, material);
|
||||
getMaterialInstance(mEngine, driver, material);
|
||||
mi->setParameter("color", color, SamplerParams{
|
||||
.filterMag = filter
|
||||
});
|
||||
@@ -3281,7 +3285,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleBilinear(FrameGraph&
|
||||
|
||||
auto out = resources.getRenderPassInfo();
|
||||
|
||||
auto pipeline = getPipelineState(material.getMaterial(mEngine));
|
||||
auto pipeline = getPipelineState(material.getMaterial(mEngine, driver));
|
||||
if (blended) {
|
||||
pipeline.rasterState.blendFunctionSrcRGB = BlendFunction::ONE;
|
||||
pipeline.rasterState.blendFunctionSrcAlpha = BlendFunction::ONE;
|
||||
@@ -3340,7 +3344,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleSGSR1(FrameGraph& fg,
|
||||
PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE;
|
||||
|
||||
FMaterialInstance* const mi =
|
||||
getMaterialInstance(mEngine, material, variant);
|
||||
getMaterialInstance(mEngine, driver, material, variant);
|
||||
|
||||
mi->setParameter("color", color, SamplerParams{
|
||||
// The SGSR documentation doesn't clarify if LINEAR or NEAREST should be used. The
|
||||
@@ -3450,7 +3454,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleFSR1(FrameGraph& fg,
|
||||
if (twoPassesEASU) {
|
||||
splitEasuMaterial = &getPostProcessMaterial("fsr_easu_mobileF");
|
||||
FMaterialInstance* const mi =
|
||||
getMaterialInstance(mEngine, *splitEasuMaterial);
|
||||
getMaterialInstance(mEngine, driver, *splitEasuMaterial);
|
||||
setEasuUniforms(mi, inputDesc, outputDesc);
|
||||
mi->setParameter("color", color, SamplerParams{
|
||||
.filterMag = SamplerMagFilter::LINEAR
|
||||
@@ -3467,7 +3471,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleFSR1(FrameGraph& fg,
|
||||
unsigned const index = std::min(1u, unsigned(dsrOptions.quality) - 2);
|
||||
easuMaterial = &getPostProcessMaterial(blitterNames[index]);
|
||||
FMaterialInstance* const mi =
|
||||
getMaterialInstance(mEngine, *easuMaterial);
|
||||
getMaterialInstance(mEngine, driver, *easuMaterial);
|
||||
|
||||
setEasuUniforms(mi, inputDesc, outputDesc);
|
||||
|
||||
@@ -3495,15 +3499,15 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleFSR1(FrameGraph& fg,
|
||||
auto out = resources.getRenderPassInfo();
|
||||
|
||||
if (UTILS_UNLIKELY(twoPassesEASU)) {
|
||||
auto pipeline0 = getPipelineState(splitEasuMaterial->getMaterial(mEngine));
|
||||
auto pipeline1 = getPipelineState(easuMaterial->getMaterial(mEngine));
|
||||
auto pipeline0 = getPipelineState(splitEasuMaterial->getMaterial(mEngine, driver));
|
||||
auto pipeline1 = getPipelineState(easuMaterial->getMaterial(mEngine, driver));
|
||||
pipeline1.rasterState.depthFunc = SamplerCompareFunc::NE;
|
||||
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));
|
||||
auto pipeline = getPipelineState(easuMaterial->getMaterial(mEngine, driver));
|
||||
renderFullScreenQuad(out, pipeline, driver);
|
||||
}
|
||||
unbindAllDescriptorSets(driver);
|
||||
@@ -3555,7 +3559,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::blit(FrameGraph& fg, bool co
|
||||
|
||||
PostProcessMaterial const& material =
|
||||
getPostProcessMaterial(layer ? "blitArray" : "blitLow");
|
||||
FMaterial const* const ma = material.getMaterial(mEngine);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, driver);
|
||||
auto* mi = getMaterialInstance(ma);
|
||||
mi->setParameter("color", color, SamplerParams{
|
||||
.filterMag = filterMag,
|
||||
@@ -3592,8 +3596,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::blitDepth(FrameGraph& fg,
|
||||
FrameGraphId<FrameGraphTexture> const input) noexcept {
|
||||
auto const& inputDesc = fg.getDescriptor(input);
|
||||
filament::Viewport const vp = {0, 0, inputDesc.width, inputDesc.height};
|
||||
bool const hardwareBlitSupported =
|
||||
mEngine.getDriverApi().isDepthStencilBlitSupported(inputDesc.format);
|
||||
bool const hardwareBlitSupported = mDepthStencilBlitSupported;
|
||||
|
||||
struct BlitData {
|
||||
FrameGraphId<FrameGraphTexture> input;
|
||||
@@ -3656,7 +3659,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::blitDepth(FrameGraph& fg,
|
||||
// set uniforms
|
||||
PostProcessMaterial const& material = getPostProcessMaterial("blitDepth");
|
||||
FMaterialInstance* const mi =
|
||||
getMaterialInstance(mEngine, material);
|
||||
getMaterialInstance(mEngine, driver, material);
|
||||
mi->setParameter("depth", depth, SamplerParams {
|
||||
.filterMag = SamplerMagFilter::NEAREST,
|
||||
.filterMin = SamplerMinFilter::NEAREST,
|
||||
@@ -3683,7 +3686,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::resolve(FrameGraph& fg,
|
||||
}
|
||||
|
||||
// The Metal / Vulkan backends currently don't support depth/stencil resolve.
|
||||
if (isDepthFormat(inDesc.format) && (!mEngine.getDriverApi().isDepthStencilResolveSupported())) {
|
||||
if (isDepthFormat(inDesc.format) && (!mDepthStencilResolveSupported)) {
|
||||
return resolveDepth(fg, outputBufferName, input, outDesc);
|
||||
}
|
||||
|
||||
@@ -3769,7 +3772,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::resolveDepth(FrameGraph& fg,
|
||||
auto const& input = resources.getTexture(data.input);
|
||||
auto const& material = getPostProcessMaterial("resolveDepth");
|
||||
FMaterialInstance* const mi =
|
||||
getMaterialInstance(mEngine, material);
|
||||
getMaterialInstance(mEngine, driver, material);
|
||||
mi->setParameter("depth", input, SamplerParams{}); // NEAREST
|
||||
commitAndRenderFullScreenQuad(driver, resources.getRenderPassInfo(), mi);
|
||||
unbindAllDescriptorSets(driver);
|
||||
@@ -3815,7 +3818,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::vsmMipmapPass(FrameGraph& fg
|
||||
int const dim = width >> (level + 1);
|
||||
|
||||
auto& material = getPostProcessMaterial("vsmMipmap");
|
||||
FMaterial const* const ma = material.getMaterial(mEngine);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, driver);
|
||||
|
||||
// When generating shadow map mip levels, we want to preserve the 1 texel border.
|
||||
// (note clearing never respects the scissor in Filament)
|
||||
@@ -3867,7 +3870,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::debugShadowCascades(FrameGra
|
||||
auto const out = resources.getRenderPassInfo();
|
||||
auto const& material = getPostProcessMaterial("debugShadowCascades");
|
||||
FMaterialInstance* const mi =
|
||||
getMaterialInstance(mEngine, material);
|
||||
getMaterialInstance(mEngine, driver, material);
|
||||
mi->setParameter("color", color, SamplerParams{}); // nearest
|
||||
mi->setParameter("depth", depth, SamplerParams{}); // nearest
|
||||
commitAndRenderFullScreenQuad(driver, out, mi);
|
||||
@@ -3917,7 +3920,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::debugCombineArrayTexture(Fra
|
||||
// set uniforms
|
||||
|
||||
PostProcessMaterial const& material = getPostProcessMaterial("blitArray");
|
||||
FMaterial const* const ma = material.getMaterial(mEngine);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, driver);
|
||||
// It should be ok to not move this getMaterialInstance to inside the loop, since
|
||||
// this is a pass meant for debug.
|
||||
auto* mi = getMaterialInstance(ma);
|
||||
@@ -3995,7 +3998,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::debugDisplayShadowTexture(
|
||||
auto const out = resources.getRenderPassInfo();
|
||||
auto in = resources.getTexture(data.depth);
|
||||
auto const& material = getPostProcessMaterial("shadowmap");
|
||||
FMaterialInstance* const mi = getMaterialInstance(mEngine, material);
|
||||
FMaterialInstance* const mi = getMaterialInstance(mEngine, driver, material);
|
||||
mi->setParameter("shadowmap", in, SamplerParams{
|
||||
.filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
|
||||
mi->setParameter("scale", s);
|
||||
|
||||
@@ -93,7 +93,7 @@ public:
|
||||
void init() noexcept;
|
||||
void terminate(backend::DriverApi& driver) noexcept;
|
||||
|
||||
void configureTemporalAntiAliasingMaterial(
|
||||
void configureTemporalAntiAliasingMaterial(backend::DriverApi& driver,
|
||||
TemporalAntiAliasingOptions const& taaOptions) noexcept;
|
||||
|
||||
// methods below are ordered relative to their position in the pipeline (as much as possible)
|
||||
@@ -350,7 +350,7 @@ public:
|
||||
|
||||
void terminate(FEngine& engine) noexcept;
|
||||
|
||||
FMaterial* getMaterial(FEngine& engine,
|
||||
FMaterial* getMaterial(FEngine& engine, backend::DriverApi& driver,
|
||||
PostProcessVariant variant = PostProcessVariant::OPAQUE) const noexcept;
|
||||
|
||||
private:
|
||||
@@ -398,7 +398,7 @@ public:
|
||||
|
||||
// Sets the necessary spec constants and uniforms common to both colorGrading.mat and
|
||||
// colorGradingAsSubpass.mat.
|
||||
FMaterialInstance* configureColorGradingMaterial(
|
||||
FMaterialInstance* configureColorGradingMaterial(backend::DriverApi& driver,
|
||||
PostProcessMaterial const& material, FColorGrading const* colorGrading,
|
||||
ColorGradingConfig const& colorGradingConfig, VignetteOptions const& vignetteOptions,
|
||||
uint32_t width, uint32_t height) noexcept;
|
||||
@@ -419,9 +419,9 @@ private:
|
||||
}
|
||||
|
||||
// Helper to get a MaterialInstance from a PostProcessMaterial.
|
||||
FMaterialInstance* getMaterialInstance(FEngine& engine, PostProcessMaterial const& material,
|
||||
FMaterialInstance* getMaterialInstance(FEngine& engine, backend::DriverApi& driver, PostProcessMaterial const& material,
|
||||
PostProcessVariant variant = PostProcessVariant::OPAQUE) {
|
||||
FMaterial const* ma = material.getMaterial(engine, variant);
|
||||
FMaterial const* ma = material.getMaterial(engine, driver, variant);
|
||||
return getMaterialInstance(ma);
|
||||
}
|
||||
|
||||
@@ -438,6 +438,9 @@ private:
|
||||
|
||||
FEngine& mEngine;
|
||||
|
||||
backend::FeatureLevel mFeatureLevel;
|
||||
bool mDepthStencilResolveSupported;
|
||||
bool mDepthStencilBlitSupported;
|
||||
mutable SsrPassDescriptorSet mSsrPassDescriptorSet;
|
||||
mutable PostProcessDescriptorSet mPostProcessDescriptorSet;
|
||||
mutable StructureDescriptorSet mStructureDescriptorSet;
|
||||
|
||||
@@ -84,9 +84,9 @@ RenderPassBuilder& RenderPassBuilder::customCommand(
|
||||
return *this;
|
||||
}
|
||||
|
||||
RenderPass RenderPassBuilder::build(FEngine const& engine) const {
|
||||
RenderPass RenderPassBuilder::build(FEngine const& engine, backend::DriverApi& driver) const {
|
||||
assert_invariant(mRenderableSoa);
|
||||
return RenderPass{ engine, *this };
|
||||
return RenderPass{ engine, driver, *this };
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -105,7 +105,7 @@ void RenderPass::DescriptorSetHandleDeleter::operator()(DescriptorSetHandle hand
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
RenderPass::RenderPass(FEngine const& engine,
|
||||
RenderPass::RenderPass(FEngine const& engine, backend::DriverApi& driver,
|
||||
RenderPassBuilder const& builder) noexcept
|
||||
: mRenderableSoa(*builder.mRenderableSoa),
|
||||
mColorPassDescriptorSet(builder.mColorPassDescriptorSet) {
|
||||
@@ -139,7 +139,7 @@ RenderPass::RenderPass(FEngine const& engine,
|
||||
}
|
||||
}
|
||||
|
||||
appendCommands(engine, { commandBegin, commandCount },
|
||||
appendCommands(engine, driver, { commandBegin, commandCount },
|
||||
builder.mVisibleRenderables,
|
||||
builder.mCommandTypeFlags,
|
||||
builder.mFlags,
|
||||
@@ -182,7 +182,7 @@ RenderPass::Command* RenderPass::resize(Arena& arena, Command* const last) noexc
|
||||
return last;
|
||||
}
|
||||
|
||||
void RenderPass::appendCommands(FEngine const& engine,
|
||||
void RenderPass::appendCommands(FEngine const& engine, backend::DriverApi& driver,
|
||||
Slice<Command> commands,
|
||||
Range<uint32_t> const visibleRenderables,
|
||||
CommandTypeFlags const commandTypeFlags,
|
||||
@@ -244,7 +244,7 @@ void RenderPass::appendCommands(FEngine const& engine,
|
||||
for (Command const* first = curr, *last = curr + commandCount ; first != last ; ++first) {
|
||||
if (UTILS_LIKELY((first->key & CUSTOM_MASK) == uint64_t(CustomCommand::PASS))) {
|
||||
auto ma = first->info.mi->getMaterial();
|
||||
ma->prepareProgram(first->info.materialVariant, CompilerPriorityQueue::CRITICAL);
|
||||
ma->prepareProgram(driver, first->info.materialVariant, CompilerPriorityQueue::CRITICAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -416,11 +416,12 @@ public:
|
||||
private:
|
||||
friend class FRenderer;
|
||||
friend class RenderPassBuilder;
|
||||
RenderPass(FEngine const& engine, RenderPassBuilder const& builder) noexcept;
|
||||
friend class RenderPassBuilder;
|
||||
RenderPass(FEngine const& engine, backend::DriverApi& driver, RenderPassBuilder const& builder) noexcept;
|
||||
|
||||
// This is the main function of this class, this appends commands to the pass using
|
||||
// the current camera, geometry and flags set. This can be called multiple times if needed.
|
||||
void appendCommands(FEngine const& engine,
|
||||
void appendCommands(FEngine const& engine, backend::DriverApi& driver,
|
||||
utils::Slice<Command> commands,
|
||||
utils::Range<uint32_t> visibleRenderables,
|
||||
CommandTypeFlags commandTypeFlags,
|
||||
@@ -580,7 +581,7 @@ public:
|
||||
uint32_t order,
|
||||
const RenderPass::Executor::CustomCommandFn& command);
|
||||
|
||||
RenderPass build(FEngine const& engine) const;
|
||||
RenderPass build(FEngine const& engine, backend::DriverApi& driver) const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ void Renderer::resetUserTime() {
|
||||
downcast(this)->resetUserTime();
|
||||
}
|
||||
|
||||
void Renderer::skipNextFrames(size_t frameCount) const noexcept {
|
||||
void Renderer::skipNextFrames(size_t frameCount) noexcept {
|
||||
downcast(this)->skipNextFrames(frameCount);
|
||||
}
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ RendererUtils::ColorPassOutput RendererUtils::colorPass(
|
||||
data.color = builder.createTexture("Color Buffer", colorBufferDesc);
|
||||
}
|
||||
|
||||
const bool canAutoResolveDepth = engine.getDriverApi().isAutoDepthResolveSupported();
|
||||
const bool canAutoResolveDepth = config.isAutoDepthResolveSupported;
|
||||
|
||||
FrameGraphTexture::Usage depthStencilUsage = FrameGraphTexture::Usage::DEPTH_ATTACHMENT;
|
||||
|
||||
@@ -124,7 +124,7 @@ RendererUtils::ColorPassOutput RendererUtils::colorPass(
|
||||
utils::StaticString{"Depth Buffer"};
|
||||
|
||||
bool const isES2 =
|
||||
engine.getDriverApi().getFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0;
|
||||
config.featureLevel == FeatureLevel::FEATURE_LEVEL_0;
|
||||
|
||||
TextureFormat const stencilFormat = isES2 ?
|
||||
TextureFormat::DEPTH24_STENCIL8 : TextureFormat::DEPTH32F_STENCIL8;
|
||||
|
||||
@@ -71,6 +71,10 @@ public:
|
||||
bool hasScreenSpaceReflectionsOrRefractions;
|
||||
// Use a depth format with a stencil component.
|
||||
bool enabledStencilBuffer;
|
||||
// Backend feature level
|
||||
backend::FeatureLevel featureLevel;
|
||||
// Auto depth resolve supported
|
||||
bool isAutoDepthResolveSupported;
|
||||
};
|
||||
|
||||
struct ColorPassInput {
|
||||
|
||||
@@ -73,7 +73,8 @@ using namespace backend;
|
||||
using namespace math;
|
||||
|
||||
ShadowMapManager::ShadowMapManager(FEngine& engine)
|
||||
: mIsDepthClampSupported(engine.getDriverApi().isDepthClampSupported()) {
|
||||
: mIsDepthClampSupported(engine.getDriverApi().isDepthClampSupported()),
|
||||
mDisableBlitIntoTextureArray(engine.getDriverApi().isWorkaroundNeeded(Workaround::DISABLE_BLIT_INTO_TEXTURE_ARRAY)) {
|
||||
FDebugRegistry& debugRegistry = engine.getDebugRegistry();
|
||||
debugRegistry.registerProperty("d.shadowmap.visualize_cascades",
|
||||
&engine.debug.shadowmap.visualize_cascades);
|
||||
@@ -125,6 +126,7 @@ void ShadowMapManager::terminate(FEngine& engine) {
|
||||
}
|
||||
|
||||
ShadowMapManager::ShadowTechnique ShadowMapManager::update(
|
||||
DriverApi& driver,
|
||||
Builder const& builder,
|
||||
FEngine& engine, FView& view,
|
||||
CameraInfo const& cameraInfo,
|
||||
@@ -139,7 +141,7 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::update(
|
||||
if (UTILS_UNLIKELY(!mInitialized)) {
|
||||
mInitialized = true;
|
||||
// initialize our ShadowMap array in-place
|
||||
mShadowUbh = engine.getDriverApi().createBufferObject(mShadowUb.getSize(),
|
||||
mShadowUbh = driver.createBufferObject(mShadowUb.getSize(),
|
||||
BufferObjectBinding::UNIFORM, BufferUsage::DYNAMIC);
|
||||
UTILS_NOUNROLL
|
||||
for (auto& entry: mShadowMapCache) {
|
||||
@@ -421,7 +423,7 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
|
||||
.visibilityMask(entry.visibilityMask)
|
||||
.geometry(scene->getRenderableData(), entry.range)
|
||||
.commandTypeFlags(RenderPass::CommandTypeFlags::SHADOW)
|
||||
.build(engine);
|
||||
.build(engine, driver);
|
||||
|
||||
pass.finalize(engine, driver);
|
||||
|
||||
@@ -1085,7 +1087,7 @@ void ShadowMapManager::calculateTextureRequirements(FEngine& engine, FView& view
|
||||
((vsmShadowOptions.anisotropy > 0) || vsmShadowOptions.mipmapping);
|
||||
|
||||
uint8_t msaaSamples = vsmShadowOptions.msaaSamples;
|
||||
if (engine.getDriverApi().isWorkaroundNeeded(Workaround::DISABLE_BLIT_INTO_TEXTURE_ARRAY)) {
|
||||
if (mDisableBlitIntoTextureArray) {
|
||||
msaaSamples = 1;
|
||||
}
|
||||
|
||||
@@ -1113,7 +1115,7 @@ void ShadowMapManager::calculateTextureRequirements(FEngine& engine, FView& view
|
||||
engine.debug.shadowmap.display_shadow_texture_level_count = mipLevels;
|
||||
|
||||
mTextureAtlasRequirements = {
|
||||
(uint16_t)maxDimension,
|
||||
uint16_t(maxDimension),
|
||||
layersNeeded,
|
||||
mipLevels,
|
||||
msaaSamples,
|
||||
|
||||
@@ -123,10 +123,10 @@ public:
|
||||
|
||||
// Updates all the shadow maps and performs culling.
|
||||
// Returns true if any of the shadow maps have visible shadows.
|
||||
ShadowTechnique update(Builder const& builder,
|
||||
FEngine& engine, FView& view,
|
||||
CameraInfo const& cameraInfo,
|
||||
FScene::RenderableSoa& renderableData, FScene::LightSoa const& lightData) noexcept;
|
||||
ShadowTechnique update(backend::DriverApi& driver,
|
||||
Builder const& builder, FEngine& engine,
|
||||
FView& view,
|
||||
CameraInfo const& cameraInfo, FScene::RenderableSoa& renderableData, FScene::LightSoa const& lightData) noexcept;
|
||||
|
||||
// Renders all the shadow maps.
|
||||
FrameGraphId<FrameGraphTexture> render(FEngine& engine, FrameGraph& fg,
|
||||
@@ -238,6 +238,7 @@ private:
|
||||
bool const mIsDepthClampSupported;
|
||||
bool mInitialized = false;
|
||||
bool mFeatureShadowAllocator = false;
|
||||
bool mDisableBlitIntoTextureArray = false;
|
||||
|
||||
ShadowMap& getShadowMap(size_t const index) noexcept {
|
||||
assert_invariant(index < mShadowMapCache.size());
|
||||
|
||||
@@ -83,7 +83,7 @@ static Iterator compact(Iterator first, Iterator last,
|
||||
auto dst = runBegin;
|
||||
auto src = runBegin;
|
||||
|
||||
using value_type = std::iterator_traits<Iterator>::value_type;
|
||||
using value_type = typename std::iterator_traits<Iterator>::value_type;
|
||||
|
||||
while (src != last) {
|
||||
// Find the end of the current run.
|
||||
|
||||
+108
-63
@@ -39,20 +39,21 @@
|
||||
#include "details/VertexBuffer.h"
|
||||
#include "details/View.h"
|
||||
|
||||
#include <filament/ColorGrading.h>
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/MaterialEnums.h>
|
||||
|
||||
#include <private/filament/DescriptorSets.h>
|
||||
#include <private/filament/EngineEnums.h>
|
||||
#include <private/filament/Variant.h>
|
||||
|
||||
#include <private/backend/PlatformFactory.h>
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
#include <private/utils/FeatureFlagManager.h>
|
||||
#include <private/utils/Tracing.h>
|
||||
|
||||
#include <filament/ColorGrading.h>
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/MaterialEnums.h>
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
#include <utils/Allocator.h>
|
||||
#include <utils/CallStack.h>
|
||||
#include <utils/CString.h>
|
||||
@@ -60,6 +61,7 @@
|
||||
#include <utils/Logger.h>
|
||||
#include <utils/Panic.h>
|
||||
#include <utils/PrivateImplementation-impl.h>
|
||||
#include <utils/Slice.h>
|
||||
#include <utils/ThreadUtils.h>
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/debug.h>
|
||||
@@ -98,8 +100,9 @@ using namespace filaflat;
|
||||
|
||||
namespace {
|
||||
|
||||
backend::Platform::DriverConfig getDriverConfig(FEngine* instance) {
|
||||
Platform::DriverConfig driverConfig {
|
||||
Platform::DriverConfig getDriverConfig(FEngine* instance) {
|
||||
Platform::DriverConfig const driverConfig {
|
||||
.featureFlagManager = instance,
|
||||
.handleArenaSize = instance->getRequestedDriverHandleArenaSize(),
|
||||
.metalUploadBufferSizeBytes = instance->getConfig().metalUploadBufferSizeBytes,
|
||||
.disableParallelShaderCompile = instance->features.backend.disable_parallel_shader_compile,
|
||||
@@ -274,10 +277,19 @@ FEngine::FEngine(Builder const& builder) :
|
||||
mMainThreadId(ThreadUtils::getThreadId()),
|
||||
mConfig(builder->mConfig)
|
||||
{
|
||||
// update all the features flags specified in the builder
|
||||
for (auto const& [feature, value] : builder->mFeatureFlags) {
|
||||
auto* const p = getFeatureFlagPtr(feature.c_str_safe(), true);
|
||||
if (p) {
|
||||
*p = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// update a feature flag from Engine::Config if the flag is not specified in the Builder
|
||||
auto const featureFlagsBackwardCompatibility =
|
||||
[this, &builder](std::string_view const name, bool const value) {
|
||||
if (builder->mFeatureFlags.find(name) == builder->mFeatureFlags.end()) {
|
||||
if (builder->mFeatureFlags.find(utils::CString(name)) == builder->mFeatureFlags.end()) {
|
||||
auto* const p = getFeatureFlagPtr(name, true);
|
||||
if (p) {
|
||||
*p = value;
|
||||
@@ -285,14 +297,6 @@ FEngine::FEngine(Builder const& builder) :
|
||||
}
|
||||
};
|
||||
|
||||
// update all the features flags specified in the builder
|
||||
for (auto const& feature : builder->mFeatureFlags) {
|
||||
auto* const p = getFeatureFlagPtr(feature.first.c_str_safe(), true);
|
||||
if (p) {
|
||||
*p = feature.second;
|
||||
}
|
||||
}
|
||||
|
||||
// update "old" feature flags that were specified in Engine::Config
|
||||
featureFlagsBackwardCompatibility("backend.disable_parallel_shader_compile",
|
||||
mConfig.disableParallelShaderCompile);
|
||||
@@ -701,6 +705,12 @@ void FEngine::shutdown() {
|
||||
// Driver::terminate() has been called here.
|
||||
}
|
||||
|
||||
// Handle any pending deferred destruction for asynchronous objects.
|
||||
if (isAsynchronousModeEnabled()) {
|
||||
gcDeferredAsyncObjectDestruction();
|
||||
assert_invariant(mDeferredAsyncObjectDestruction.empty());
|
||||
}
|
||||
|
||||
// Finally, call user callbacks that might have been scheduled.
|
||||
// These callbacks CANNOT call driver APIs.
|
||||
getDriver().purge();
|
||||
@@ -716,12 +726,11 @@ void FEngine::shutdown() {
|
||||
mJobSystem.emancipate();
|
||||
}
|
||||
|
||||
void FEngine::prepare() {
|
||||
void FEngine::prepare(DriverApi& driver) {
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
// prepare() is called once per Renderer frame. Ideally we would upload the content of
|
||||
// UBOs that are visible only. It's not such a big issue because the actual upload() is
|
||||
// skipped if the UBO hasn't changed. Still we could have a lot of these.
|
||||
DriverApi& driver = getDriverApi();
|
||||
const bool useUboBatching = isUboBatchingEnabled();
|
||||
|
||||
if (useUboBatching) {
|
||||
@@ -731,7 +740,7 @@ void FEngine::prepare() {
|
||||
|
||||
UboManager* uboManager = mUboManager;
|
||||
for (auto& materialInstanceList: mMaterialInstances) {
|
||||
materialInstanceList.second.forEach([&driver, uboManager](FMaterialInstance* item) {
|
||||
materialInstanceList.second.forEach([&driver, uboManager](FMaterialInstance const* item) {
|
||||
// post-process materials instances must be commited explicitly because their
|
||||
// parameters are typically not set at this point in time.
|
||||
if (item->getMaterial()->getMaterialDomain() == MaterialDomain::SURFACE) {
|
||||
@@ -742,7 +751,7 @@ void FEngine::prepare() {
|
||||
|
||||
if (useUboBatching) {
|
||||
assert_invariant(mUboManager != nullptr);
|
||||
getUboManager()->finishBeginFrame(getDriverApi());
|
||||
getUboManager()->finishBeginFrame(driver);
|
||||
}
|
||||
|
||||
mMaterials.forEach([](FMaterial* material) {
|
||||
@@ -752,7 +761,7 @@ void FEngine::prepare() {
|
||||
});
|
||||
}
|
||||
|
||||
void FEngine::gc() {
|
||||
void FEngine::gcManagers() {
|
||||
// Note: this runs in a Job
|
||||
auto& em = mEntityManager;
|
||||
mRenderableManager.gc(em);
|
||||
@@ -761,6 +770,21 @@ void FEngine::gc() {
|
||||
mCameraManager.gc(*this, em);
|
||||
}
|
||||
|
||||
void FEngine::gcDeferredAsyncObjectDestruction() {
|
||||
if (mDeferredAsyncObjectDestruction.empty()) {
|
||||
return;
|
||||
}
|
||||
auto it = std::remove_if(
|
||||
mDeferredAsyncObjectDestruction.begin(),
|
||||
mDeferredAsyncObjectDestruction.end(),
|
||||
[](auto& f) {
|
||||
return f(); // Returns true if it should be removed
|
||||
}
|
||||
);
|
||||
// Actually erase the elements from the vector
|
||||
mDeferredAsyncObjectDestruction.erase(it, mDeferredAsyncObjectDestruction.end());
|
||||
}
|
||||
|
||||
void FEngine::submitFrame() {
|
||||
if (isUboBatchingEnabled()) {
|
||||
DriverApi& driver = getDriverApi();
|
||||
@@ -858,13 +882,7 @@ int FEngine::loop() {
|
||||
#endif
|
||||
if (fgviewerPortString != nullptr) {
|
||||
const int fgviewerPort = atoi(fgviewerPortString);
|
||||
debug.fgviewerServer = new fgviewer::DebugServer(fgviewerPort,
|
||||
fgviewer::DebugServer::ReadbackRequest([this](utils::CString name,
|
||||
std::function<void(fgviewer::DebugServer::PixelBuffer,
|
||||
uint32_t, uint32_t,
|
||||
fgviewer::DebugServer::PixelDataFormat)> callback) {
|
||||
requestTextureReadback(name, std::move(callback));
|
||||
}));
|
||||
debug.fgviewerServer = new fgviewer::DebugServer(fgviewerPort);
|
||||
|
||||
// Sometimes the server can fail to spin up (e.g. if the above port is already in use).
|
||||
// When this occurs, carry onward, developers can look at civetweb.txt for details.
|
||||
@@ -1143,11 +1161,18 @@ bool FEngine::isValid(const T* ptr, ResourceList<T> const& list) const {
|
||||
return l.find(ptr) != l.end();
|
||||
}
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct HasIsCreationComplete : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct HasIsCreationComplete<T, std::void_t<decltype(std::declval<T>().isCreationComplete())>>
|
||||
: std::true_type {};
|
||||
|
||||
template<typename T>
|
||||
UTILS_ALWAYS_INLINE
|
||||
bool FEngine::terminateAndDestroy(const T* p, ResourceList<T>& list) {
|
||||
if (p == nullptr) return true;
|
||||
bool const success = list.remove(p);
|
||||
bool FEngine::terminateAndDestroy(const T* ptr, ResourceList<T>& list) {
|
||||
if (ptr == nullptr) return true;
|
||||
bool const success = list.remove(ptr);
|
||||
|
||||
#if UTILS_HAS_RTTI
|
||||
auto typeName = CallStack::typeName<T>();
|
||||
@@ -1157,9 +1182,42 @@ bool FEngine::terminateAndDestroy(const T* p, ResourceList<T>& list) {
|
||||
#endif
|
||||
|
||||
if (ASSERT_PRECONDITION_NON_FATAL(success,
|
||||
"Object %s at %p doesn't exist (double free?)", typeNameCStr, p)) {
|
||||
const_cast<T*>(p)->terminate(*this);
|
||||
mHeapAllocator.destroy(const_cast<T*>(p));
|
||||
"Object %s at %p doesn't exist (double free?)", typeNameCStr, ptr)) {
|
||||
|
||||
T* p = const_cast<T*>(ptr);
|
||||
|
||||
if constexpr (HasIsCreationComplete<T>::value) {
|
||||
// The presence of 'isCreationComplete' in type T implies it supports asynchronous
|
||||
// creation. For these asynchronous objects, we can terminate the backend resources
|
||||
// immediately as they are no longer referenced. However, we defer the destruction of
|
||||
// the frontend object if it's still being loaded.
|
||||
// Reason: The creation process is still active and holds a reference to the frontend
|
||||
// object to set `mCreationComplete` to true (see FTexture::FTexture). Deleting it now
|
||||
// may cause a crash, so we wait until creation completes.
|
||||
|
||||
// Terminate the backend resource immediately as they're unnecessary from this point.
|
||||
p->terminate(*this);
|
||||
|
||||
if (p->isCreationComplete()) {
|
||||
// If creation is complete, we free the frontend object immediately. Note that in
|
||||
// regular (non-async) mode, the `isCreationComplete` method always return true.
|
||||
mHeapAllocator.destroy(p);
|
||||
} else {
|
||||
// We defer the destruction of the frontend object until the creation process
|
||||
// completes. This ensures the object remains valid while the creation process still
|
||||
// holds references to it.
|
||||
mDeferredAsyncObjectDestruction.push_back([this, p]() {
|
||||
if (!p->isCreationComplete()) {
|
||||
return false;
|
||||
}
|
||||
mHeapAllocator.destroy(p);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
p->terminate(*this);
|
||||
mHeapAllocator.destroy(p);
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
@@ -1462,7 +1520,7 @@ AsyncCallId FEngine::runCommandAsync(Invocable<void()>&& command,
|
||||
AsyncCompletionCallback userCallback;
|
||||
void* userParam;
|
||||
static void func(void* wrappedData) {
|
||||
auto* const data = static_cast<RunCommandAsyncCallback*>(wrappedData);
|
||||
auto const* const data = static_cast<RunCommandAsyncCallback*>(wrappedData);
|
||||
data->userCallback(data->userParam);
|
||||
delete data;
|
||||
}
|
||||
@@ -1556,30 +1614,26 @@ void FEngine::unprotected() noexcept {
|
||||
mUnprotectedDummySwapchain->makeCurrent(getDriverApi());
|
||||
}
|
||||
|
||||
bool FEngine::setFeatureFlag(char const* name, bool const value) const noexcept {
|
||||
auto* const p = getFeatureFlagPtr(name);
|
||||
if (p) {
|
||||
*p = value;
|
||||
}
|
||||
return p != nullptr;
|
||||
Slice<const Engine::FeatureFlag> FEngine::getFeatureFlags() const noexcept {
|
||||
// Engine::FeatureFlag and FeatureFlagManager::FeatureFlag are the same type
|
||||
Slice const r{ FeatureFlagManager::getFeatureFlags() };
|
||||
Slice const result{
|
||||
reinterpret_cast<Engine::FeatureFlag const*>(r.data()),
|
||||
r.size()
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
bool FEngine::setFeatureFlag(char const* name, bool const value) noexcept {
|
||||
return FeatureFlagManager::setFeatureFlag(name, value);
|
||||
}
|
||||
|
||||
std::optional<bool> FEngine::getFeatureFlag(char const* name) const noexcept {
|
||||
auto* const p = getFeatureFlagPtr(name, true);
|
||||
if (p) {
|
||||
return *p;
|
||||
}
|
||||
return std::nullopt;
|
||||
return FeatureFlagManager::getFeatureFlag(name);
|
||||
}
|
||||
|
||||
bool* FEngine::getFeatureFlagPtr(std::string_view name, bool const allowConstant) const noexcept {
|
||||
auto pos = std::find_if(mFeatures.begin(), mFeatures.end(),
|
||||
[name](FeatureFlag const& entry) {
|
||||
return name == entry.name;
|
||||
});
|
||||
|
||||
return (pos != mFeatures.end() && (!pos->constant || allowConstant)) ?
|
||||
const_cast<bool*>(pos->value) : nullptr;
|
||||
return FeatureFlagManager::getFeatureFlagPtr(name, allowConstant);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -1684,13 +1738,4 @@ Engine::Config Engine::BuilderDetails::validateConfig(Config config) noexcept {
|
||||
return config;
|
||||
}
|
||||
|
||||
#if FILAMENT_ENABLE_FGVIEWER
|
||||
void FEngine::requestTextureReadback(const CString& name,
|
||||
std::function<void(fgviewer::DebugServer::PixelBuffer, uint32_t, uint32_t,
|
||||
fgviewer::DebugServer::PixelDataFormat)>&& callback) {
|
||||
std::unique_lock<utils::Mutex> lock(mReadbackRequestsMutex);
|
||||
mReadbackRequests.emplace_back(ReadbackRequest{ name, std::move(callback) });
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace filament
|
||||
|
||||
+21
-153
@@ -47,12 +47,14 @@
|
||||
#include "details/Skybox.h"
|
||||
#include "details/Sync.h"
|
||||
|
||||
#include "private/backend/CommandBufferQueue.h"
|
||||
#include "private/backend/CommandStream.h"
|
||||
#include "private/backend/DriverApi.h"
|
||||
|
||||
#include <private/filament/EngineEnums.h>
|
||||
#include <private/filament/BufferInterfaceBlock.h>
|
||||
|
||||
#include <private/backend/CommandBufferQueue.h>
|
||||
#include <private/backend/CommandStream.h>
|
||||
#include <private/backend/DriverApi.h>
|
||||
|
||||
#include <private/utils/FeatureFlagManager.h>
|
||||
|
||||
#include <filament/ColorGrading.h>
|
||||
#include <filament/Engine.h>
|
||||
@@ -70,10 +72,10 @@
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/CountDownLatch.h>
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
#include <utils/Invocable.h>
|
||||
#include <utils/JobSystem.h>
|
||||
#include <utils/Slice.h>
|
||||
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
@@ -84,6 +86,9 @@
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if FILAMENT_ENABLE_MATDBG
|
||||
#include <matdbg/DebugServer.h>
|
||||
#else
|
||||
@@ -101,14 +106,6 @@ namespace filament::fgviewer {
|
||||
} // namespace filament::fgviewer
|
||||
#endif
|
||||
|
||||
// We have added correctness assertions that breaks clients' projects. We add this define to allow
|
||||
// for the client's to address these assertions at a more gradual pace.
|
||||
#if defined(FILAMENT_RELAXED_CORRECTNESS_ASSERTIONS)
|
||||
#define CORRECTNESS_ASSERTION_DEFAULT false
|
||||
#else
|
||||
#define CORRECTNESS_ASSERTION_DEFAULT true
|
||||
#endif
|
||||
|
||||
namespace filament {
|
||||
|
||||
class Renderer;
|
||||
@@ -134,8 +131,7 @@ class TextureCache;
|
||||
* Concrete implementation of the Engine interface. This keeps track of all hardware resources
|
||||
* for a given context.
|
||||
*/
|
||||
class FEngine : public Engine {
|
||||
friend class FRenderer;
|
||||
class FEngine : public Engine, public utils::FeatureFlagManager {
|
||||
public:
|
||||
void* operator new(std::size_t const size) noexcept {
|
||||
return utils::aligned_alloc(size, alignof(FEngine));
|
||||
@@ -459,8 +455,9 @@ public:
|
||||
return mPlatform->pumpEvents();
|
||||
}
|
||||
|
||||
void prepare();
|
||||
void gc();
|
||||
void prepare(backend::DriverApi& driver);
|
||||
void gcManagers();
|
||||
void gcDeferredAsyncObjectDestruction();
|
||||
void submitFrame();
|
||||
|
||||
using ShaderContent = utils::FixedCapacityVector<uint8_t>;
|
||||
@@ -573,11 +570,10 @@ public:
|
||||
|
||||
backend::Driver& getDriver() const noexcept { return *mDriver; }
|
||||
|
||||
#if FILAMENT_ENABLE_FGVIEWER
|
||||
void requestTextureReadback(utils::CString const& name,
|
||||
std::function<void(fgviewer::DebugServer::PixelBuffer, uint32_t, uint32_t,
|
||||
fgviewer::DebugServer::PixelDataFormat)>&& callback);
|
||||
#endif
|
||||
utils::Slice<const Engine::FeatureFlag> getFeatureFlags() const noexcept;
|
||||
bool setFeatureFlag(char const* name, bool value) noexcept;
|
||||
std::optional<bool> getFeatureFlag(char const* name) const noexcept;
|
||||
bool* getFeatureFlagPtr(std::string_view name, bool allowConstant = false) const noexcept;
|
||||
|
||||
private:
|
||||
explicit FEngine(Builder const& builder);
|
||||
@@ -591,7 +587,7 @@ private:
|
||||
bool isValid(const T* ptr, ResourceList<T> const& list) const;
|
||||
|
||||
template<typename T>
|
||||
bool terminateAndDestroy(const T* p, ResourceList<T>& list);
|
||||
bool terminateAndDestroy(const T* ptr, ResourceList<T>& list);
|
||||
|
||||
template<typename T, typename Lock>
|
||||
bool terminateAndDestroyLocked(Lock& lock, const T* p, ResourceList<T>& list);
|
||||
@@ -710,20 +706,11 @@ private:
|
||||
|
||||
bool mInitialized = false;
|
||||
|
||||
#if FILAMENT_ENABLE_FGVIEWER
|
||||
struct ReadbackRequest {
|
||||
using Callback = std::function<void(fgviewer::DebugServer::PixelBuffer, uint32_t, uint32_t,
|
||||
fgviewer::DebugServer::PixelDataFormat)>;
|
||||
utils::CString name;
|
||||
Callback callback;
|
||||
};
|
||||
utils::Mutex mReadbackRequestsMutex;
|
||||
std::vector<ReadbackRequest> mReadbackRequests;
|
||||
#endif
|
||||
|
||||
// Creation parameters
|
||||
Config mConfig;
|
||||
|
||||
std::vector<std::function<bool()>> mDeferredAsyncObjectDestruction;
|
||||
|
||||
public:
|
||||
// These are the debug properties used by FDebug.
|
||||
// They're accessed directly by modules who need them.
|
||||
@@ -770,125 +757,6 @@ public:
|
||||
matdbg::DebugServer* server = nullptr;
|
||||
fgviewer::DebugServer* fgviewerServer = nullptr;
|
||||
} debug;
|
||||
|
||||
struct {
|
||||
struct {
|
||||
struct {
|
||||
bool use_1d_lut = false;
|
||||
} color_grading;
|
||||
struct {
|
||||
bool use_shadow_atlas = false;
|
||||
} shadows;
|
||||
struct {
|
||||
// TODO: clean-up the following flags (equivalent to setting them to true) when
|
||||
// clients have addressed their usages.
|
||||
bool assert_material_instance_in_use = CORRECTNESS_ASSERTION_DEFAULT;
|
||||
bool assert_destroy_material_before_material_instance =
|
||||
CORRECTNESS_ASSERTION_DEFAULT;
|
||||
bool assert_vertex_buffer_count_exceeds_8 = CORRECTNESS_ASSERTION_DEFAULT;
|
||||
bool assert_vertex_buffer_attribute_stride_mult_of_4 =
|
||||
CORRECTNESS_ASSERTION_DEFAULT;
|
||||
bool assert_material_instance_texture_descriptor_set_compatible =
|
||||
CORRECTNESS_ASSERTION_DEFAULT;
|
||||
bool assert_texture_can_generate_mipmap = CORRECTNESS_ASSERTION_DEFAULT;
|
||||
} debug;
|
||||
struct {
|
||||
bool disable_gpu_frame_complete_metric = true;
|
||||
} frame_info;
|
||||
} engine;
|
||||
struct {
|
||||
struct {
|
||||
bool assert_native_window_is_valid = false;
|
||||
} opengl;
|
||||
struct {
|
||||
// In certain GPU drivers, graphics pipelines are cached based on a subset of their
|
||||
// parameters. In those cases, we can create fake pipelines ahead of time to ensure
|
||||
// a cache hit when creating graphics pipelines at draw time, eliminating hitching.
|
||||
bool enable_pipeline_cache_prewarming = false;
|
||||
// On Unified Memory Architecture device, it is possible to bypass using the staging
|
||||
// buffer. This is an experimental feature that still needs to be implemented fully
|
||||
// before it can be fully enabled.
|
||||
bool enable_staging_buffer_bypass = false;
|
||||
} vulkan;
|
||||
bool disable_parallel_shader_compile = false;
|
||||
bool disable_amortized_shader_compile = true;
|
||||
bool disable_handle_use_after_free_check = false;
|
||||
bool disable_heap_handle_tags = true; // FIXME: this should be false
|
||||
bool enable_asynchronous_operation = false;
|
||||
} backend;
|
||||
struct {
|
||||
bool check_crc32_after_loading = false;
|
||||
bool enable_material_instance_uniform_batching = false;
|
||||
} material;
|
||||
} features;
|
||||
|
||||
std::array<FeatureFlag, sizeof(features)> const mFeatures{{
|
||||
{ "backend.disable_parallel_shader_compile",
|
||||
"Disable parallel shader compilation in GL and Metal backends.",
|
||||
&features.backend.disable_parallel_shader_compile },
|
||||
{ "backend.disable_amortized_shader_compile",
|
||||
"Disable amortized shader compilation in GL backend.",
|
||||
&features.backend.disable_amortized_shader_compile },
|
||||
{ "backend.disable_handle_use_after_free_check",
|
||||
"Disable Handle<> use-after-free checks.",
|
||||
&features.backend.disable_handle_use_after_free_check },
|
||||
{ "backend.disable_heap_handle_tags",
|
||||
"Disable Handle<> tags for heap-allocated handles.",
|
||||
&features.backend.disable_heap_handle_tags },
|
||||
{ "backend.enable_asynchronous_operation",
|
||||
"Enable asynchronous operation for resource management.",
|
||||
&features.backend.enable_asynchronous_operation },
|
||||
{ "backend.opengl.assert_native_window_is_valid",
|
||||
"Asserts that the ANativeWindow is valid when rendering starts.",
|
||||
&features.backend.opengl.assert_native_window_is_valid },
|
||||
{ "engine.color_grading.use_1d_lut",
|
||||
"Uses a 1D LUT for color grading.",
|
||||
&features.engine.color_grading.use_1d_lut, false },
|
||||
{ "engine.shadows.use_shadow_atlas",
|
||||
"Uses an array of atlases to store shadow maps.",
|
||||
&features.engine.shadows.use_shadow_atlas, false },
|
||||
{ "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 },
|
||||
{ "engine.debug.assert_destroy_material_before_material_instance",
|
||||
"Assert when a Material is destroyed but its instances are still alive.",
|
||||
&features.engine.debug.assert_destroy_material_before_material_instance, false },
|
||||
{ "engine.debug.assert_vertex_buffer_count_exceeds_8",
|
||||
"Assert when a client's number of buffers for a VertexBuffer exceeds 8.",
|
||||
&features.engine.debug.assert_vertex_buffer_count_exceeds_8, false },
|
||||
{ "engine.debug.assert_vertex_buffer_attribute_stride_mult_of_4",
|
||||
"Assert that the attribute stride of a vertex buffer is a multiple of 4.",
|
||||
&features.engine.debug.assert_vertex_buffer_attribute_stride_mult_of_4, false },
|
||||
{ "backend.vulkan.enable_pipeline_cache_prewarming",
|
||||
"Enables an experimental approach to parallel shader compilation on Vulkan.",
|
||||
&features.backend.vulkan.enable_pipeline_cache_prewarming, false },
|
||||
{ "backend.vulkan.enable_staging_buffer_bypass",
|
||||
"vulkan: enable a staging bypass logic for unified memory architecture.",
|
||||
&features.backend.vulkan.enable_staging_buffer_bypass, false },
|
||||
{ "engine.debug.assert_material_instance_texture_descriptor_set_compatible",
|
||||
"Assert that the textures in a material instance are compatible with descriptor set.",
|
||||
&features.engine.debug.assert_material_instance_texture_descriptor_set_compatible, false },
|
||||
{ "engine.debug.assert_texture_can_generate_mipmap",
|
||||
"Assert if a texture has the correct usage set for generating mipmaps.",
|
||||
&features.engine.debug.assert_texture_can_generate_mipmap, false },
|
||||
{ "material.check_crc32_after_loading",
|
||||
"Verify the checksum of package data when a material is loaded.",
|
||||
&features.material.check_crc32_after_loading, false },
|
||||
{ "material.enable_material_instance_uniform_batching",
|
||||
"Make all MaterialInstances share a common large uniform buffer and use sub-allocations within it.",
|
||||
&features.material.enable_material_instance_uniform_batching },
|
||||
{ "engine.frame_info.disable_gpu_complete_metric",
|
||||
"Disable Renderer::FrameInfo::gpuFrameComplete reporting",
|
||||
&features.engine.frame_info.disable_gpu_frame_complete_metric },
|
||||
}};
|
||||
|
||||
utils::Slice<const FeatureFlag> getFeatureFlags() const noexcept {
|
||||
return { mFeatures.data(), mFeatures.size() };
|
||||
}
|
||||
|
||||
bool setFeatureFlag(char const* name, bool value) const noexcept;
|
||||
std::optional<bool> getFeatureFlag(char const* name) const noexcept;
|
||||
bool* getFeatureFlagPtr(std::string_view name, bool allowConstant = false) const noexcept;
|
||||
};
|
||||
|
||||
FILAMENT_DOWNCAST(Engine)
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#include <private/filament/DescriptorSets.h>
|
||||
#include <private/filament/SamplerInterfaceBlock.h>
|
||||
#include <private/filament/BufferInterfaceBlock.h>
|
||||
#include <private/filament/PushConstantInfo.h>
|
||||
#include <private/filament/Variant.h>
|
||||
|
||||
#include <filament/Material.h>
|
||||
@@ -40,6 +39,7 @@
|
||||
|
||||
#include <filaflat/ChunkContainer.h>
|
||||
|
||||
#include <backend/DriverApiForward.h>
|
||||
#include <backend/DriverEnums.h>
|
||||
#include <backend/CallbackHandler.h>
|
||||
#include <backend/Program.h>
|
||||
@@ -51,7 +51,6 @@
|
||||
#include <utils/Invocable.h>
|
||||
#include <utils/Logger.h>
|
||||
#include <utils/Panic.h>
|
||||
#include <utils/bitset.h>
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/debug.h>
|
||||
#include <utils/ostream.h>
|
||||
@@ -166,10 +165,20 @@ FMaterial::FMaterial(FEngine& engine, const Builder& builder, MaterialDefinition
|
||||
definition.materialDomain)),
|
||||
mEngine(engine),
|
||||
mMaterialId(engine.getMaterialId()) {
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(!mUseUboBatching || engine.isUboBatchingEnabled())
|
||||
<< "UBO batching is not enabled.";
|
||||
|
||||
DriverApi& driver = engine.getDriverApi();
|
||||
|
||||
mIsStereoSupported = driver.isStereoSupported();
|
||||
mIsParallelShaderCompileSupported = driver.isParallelShaderCompileSupported();
|
||||
mDepthPrecacheDisabled = driver.isWorkaroundNeeded(Workaround::DISABLE_DEPTH_PRECACHE_FOR_DEFAULT_MATERIAL);
|
||||
mDefaultMaterial = engine.getDefaultMaterial();
|
||||
|
||||
mSpecializationConstants = processSpecializationConstants(builder);
|
||||
precacheDepthVariants(engine);
|
||||
|
||||
precacheDepthVariants(driver);
|
||||
|
||||
#if FILAMENT_ENABLE_MATDBG
|
||||
// Register the material with matdbg.
|
||||
@@ -275,11 +284,10 @@ backend::DescriptorSetLayout const& FMaterial::getDescriptorSetLayoutDescription
|
||||
if (!isSharedVariant(variant)) {
|
||||
return mDefinition.descriptorSetLayoutDescription;
|
||||
}
|
||||
FMaterial const* const pDefaultMaterial = mEngine.getDefaultMaterial();
|
||||
if (UTILS_UNLIKELY(!pDefaultMaterial)) {
|
||||
if (UTILS_UNLIKELY(!mDefaultMaterial)) {
|
||||
return mDefinition.descriptorSetLayoutDescription;
|
||||
}
|
||||
return pDefaultMaterial->getDescriptorSetLayoutDescription();
|
||||
return mDefaultMaterial->getDescriptorSetLayoutDescription();
|
||||
}
|
||||
|
||||
void FMaterial::compile(CompilerPriorityQueue const priority,
|
||||
@@ -287,21 +295,23 @@ void FMaterial::compile(CompilerPriorityQueue const priority,
|
||||
CallbackHandler* handler,
|
||||
Invocable<void(Material*)>&& callback) noexcept {
|
||||
|
||||
DriverApi& driver = mEngine.getDriverApi();
|
||||
|
||||
// Turn off the STE variant if stereo is not supported.
|
||||
if (!mEngine.getDriverApi().isStereoSupported()) {
|
||||
if (!mIsStereoSupported) {
|
||||
variantSpec &= ~UserVariantFilterMask(UserVariantFilterBit::STE);
|
||||
}
|
||||
|
||||
UserVariantFilterMask const variantFilter =
|
||||
~variantSpec & UserVariantFilterMask(UserVariantFilterBit::ALL);
|
||||
|
||||
if (UTILS_LIKELY(mEngine.getDriverApi().isParallelShaderCompileSupported())) {
|
||||
if (UTILS_LIKELY(mIsParallelShaderCompileSupported)) {
|
||||
auto const& variants = isVariantLit() ?
|
||||
VariantUtils::getLitVariants() : VariantUtils::getUnlitVariants();
|
||||
for (auto const variant: variants) {
|
||||
if (!variantFilter || variant == Variant::filterUserVariant(variant, variantFilter)) {
|
||||
if (hasVariant(variant)) {
|
||||
prepareProgram(variant, priority);
|
||||
prepareProgram(driver, variant, priority);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -318,9 +328,9 @@ void FMaterial::compile(CompilerPriorityQueue const priority,
|
||||
}
|
||||
};
|
||||
auto* const user = new(std::nothrow) Callback{ std::move(callback), this };
|
||||
mEngine.getDriverApi().compilePrograms(priority, handler, &Callback::func, user);
|
||||
driver.compilePrograms(priority, handler, &Callback::func, user);
|
||||
} else {
|
||||
mEngine.getDriverApi().compilePrograms(priority, nullptr, nullptr, nullptr);
|
||||
driver.compilePrograms(priority, nullptr, nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -391,15 +401,15 @@ bool FMaterial::hasVariant(Variant const variant) const noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
void FMaterial::prepareProgramSlow(Variant const variant,
|
||||
void FMaterial::prepareProgramSlow(DriverApi& driver, Variant const variant,
|
||||
backend::CompilerPriorityQueue const priorityQueue) const noexcept {
|
||||
assert_invariant(mEngine.hasFeatureLevel(mDefinition.featureLevel));
|
||||
switch (getMaterialDomain()) {
|
||||
case MaterialDomain::SURFACE:
|
||||
getSurfaceProgramSlow(variant, priorityQueue);
|
||||
getSurfaceProgramSlow(driver, variant, priorityQueue);
|
||||
break;
|
||||
case MaterialDomain::POST_PROCESS:
|
||||
getPostProcessProgramSlow(variant, priorityQueue);
|
||||
getPostProcessProgramSlow(driver, variant, priorityQueue);
|
||||
break;
|
||||
case MaterialDomain::COMPUTE:
|
||||
// TODO: implement MaterialDomain::COMPUTE
|
||||
@@ -407,7 +417,7 @@ void FMaterial::prepareProgramSlow(Variant const variant,
|
||||
}
|
||||
}
|
||||
|
||||
void FMaterial::getSurfaceProgramSlow(Variant const variant,
|
||||
void FMaterial::getSurfaceProgramSlow(DriverApi& driver, Variant const variant,
|
||||
CompilerPriorityQueue const priorityQueue) const noexcept {
|
||||
// filterVariant() has already been applied in generateCommands(), shouldn't be needed here
|
||||
// if we're unlit, we don't have any bits that correspond to lit materials
|
||||
@@ -423,14 +433,14 @@ void FMaterial::getSurfaceProgramSlow(Variant const variant,
|
||||
pb.multiview(
|
||||
mEngine.getConfig().stereoscopicType == StereoscopicType::MULTIVIEW &&
|
||||
Variant::isStereoVariant(variant));
|
||||
createAndCacheProgram(std::move(pb), variant);
|
||||
createAndCacheProgram(driver, std::move(pb), variant);
|
||||
}
|
||||
|
||||
void FMaterial::getPostProcessProgramSlow(Variant const variant,
|
||||
void FMaterial::getPostProcessProgramSlow(DriverApi& driver, Variant const variant,
|
||||
CompilerPriorityQueue const priorityQueue) const noexcept {
|
||||
Program pb{ getProgramWithVariants(variant, variant, variant) };
|
||||
pb.priorityQueue(priorityQueue);
|
||||
createAndCacheProgram(std::move(pb), variant);
|
||||
createAndCacheProgram(driver, std::move(pb), variant);
|
||||
}
|
||||
|
||||
Program FMaterial::getProgramWithVariants(
|
||||
@@ -477,7 +487,7 @@ Program FMaterial::getProgramWithVariants(
|
||||
.shader(ShaderStage::FRAGMENT, fsBuilder.data(), fsBuilder.size())
|
||||
.shaderLanguage(parser.getShaderLanguage())
|
||||
.diagnostics(mDefinition.name,
|
||||
[variant, vertexVariant, fragmentVariant](utils::CString const& name,
|
||||
[variant, vertexVariant, fragmentVariant](CString const& name,
|
||||
io::ostream& out) -> io::ostream& {
|
||||
return out << name.c_str_safe() << ", variant=(" << io::hex << +variant.key
|
||||
<< io::dec << "), vertexVariant=(" << io::hex
|
||||
@@ -511,17 +521,13 @@ Program FMaterial::getProgramWithVariants(
|
||||
return program;
|
||||
}
|
||||
|
||||
void FMaterial::createAndCacheProgram(Program&& p, Variant const variant) const noexcept {
|
||||
FEngine const& engine = mEngine;
|
||||
DriverApi& driverApi = mEngine.getDriverApi();
|
||||
|
||||
void FMaterial::createAndCacheProgram(DriverApi& driver, Program&& p, Variant const variant) const noexcept {
|
||||
bool const isShared = isSharedVariant(variant);
|
||||
|
||||
// Check if the default material has this program cached
|
||||
if (isShared) {
|
||||
FMaterial const* const pDefaultMaterial = engine.getDefaultMaterial();
|
||||
if (pDefaultMaterial) {
|
||||
auto const program = pDefaultMaterial->mCachedPrograms[variant.key];
|
||||
if (mDefaultMaterial) {
|
||||
auto const program = mDefaultMaterial->mCachedPrograms[variant.key];
|
||||
if (program) {
|
||||
mCachedPrograms[variant.key] = program;
|
||||
return;
|
||||
@@ -539,7 +545,7 @@ void FMaterial::createAndCacheProgram(Program&& p, Variant const variant) const
|
||||
p.descriptorLayout(+DescriptorSetBindingPoints::PER_MATERIAL,
|
||||
getDescriptorSetLayoutDescription(variant));
|
||||
|
||||
auto const program = driverApi.createProgram(std::move(p),
|
||||
auto const program = driver.createProgram(std::move(p),
|
||||
ImmutableCString{ mDefinition.name.c_str_safe() });
|
||||
assert_invariant(program);
|
||||
mCachedPrograms[variant.key] = program;
|
||||
@@ -548,9 +554,8 @@ void FMaterial::createAndCacheProgram(Program&& p, Variant const variant) const
|
||||
// are met (Surface Domain and no custom depth shader), cache it now.
|
||||
// New Materials will inherit these program automatically.
|
||||
if (isShared) {
|
||||
FMaterial const* const pDefaultMaterial = engine.getDefaultMaterial();
|
||||
if (pDefaultMaterial && !pDefaultMaterial->mCachedPrograms[variant.key]) {
|
||||
pDefaultMaterial->mCachedPrograms[variant.key] = program;
|
||||
if (mDefaultMaterial && !mDefaultMaterial->mCachedPrograms[variant.key]) {
|
||||
mDefaultMaterial->mCachedPrograms[variant.key] = program;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -838,17 +843,16 @@ FMaterial::processSpecializationConstants(Builder const& builder) {
|
||||
return specializationConstants;
|
||||
}
|
||||
|
||||
void FMaterial::precacheDepthVariants(FEngine& engine) {
|
||||
void FMaterial::precacheDepthVariants(DriverApi& driver) {
|
||||
|
||||
bool const disableDepthPrecacheForDefaultMaterial = engine.getDriverApi().isWorkaroundNeeded(
|
||||
Workaround::DISABLE_DEPTH_PRECACHE_FOR_DEFAULT_MATERIAL);
|
||||
bool const disableDepthPrecacheForDefaultMaterial = mDepthPrecacheDisabled;
|
||||
|
||||
// pre-cache all depth variants inside the default material. Note that this should be
|
||||
// entirely optional; if we remove this pre-caching, these variants will be populated
|
||||
// later, when/if needed by createAndCacheProgram(). Doing it now potentially uses more
|
||||
// memory and increases init time, but reduces hiccups during the first frame.
|
||||
if (UTILS_UNLIKELY(mIsDefaultMaterial && !disableDepthPrecacheForDefaultMaterial)) {
|
||||
const bool stereoSupported = mEngine.getDriverApi().isStereoSupported();
|
||||
const bool stereoSupported = driver.isStereoSupported();
|
||||
auto const allDepthVariants = VariantUtils::getDepthVariants();
|
||||
for (auto const variant: allDepthVariants) {
|
||||
// Don't precache any stereo variants if stereo is not supported.
|
||||
@@ -857,7 +861,7 @@ void FMaterial::precacheDepthVariants(FEngine& engine) {
|
||||
}
|
||||
assert_invariant(Variant::isValidDepthVariant(variant));
|
||||
if (hasVariant(variant)) {
|
||||
prepareProgram(variant, CompilerPriorityQueue::HIGH);
|
||||
prepareProgram(driver, variant, CompilerPriorityQueue::HIGH);
|
||||
}
|
||||
}
|
||||
return;
|
||||
@@ -867,12 +871,11 @@ void FMaterial::precacheDepthVariants(FEngine& engine) {
|
||||
if (mDefinition.materialDomain == MaterialDomain::SURFACE &&
|
||||
!mIsDefaultMaterial &&
|
||||
!mDefinition.hasCustomDepthShader) {
|
||||
FMaterial const* const pDefaultMaterial = engine.getDefaultMaterial();
|
||||
assert_invariant(pDefaultMaterial);
|
||||
assert_invariant(mDefaultMaterial);
|
||||
auto const allDepthVariants = VariantUtils::getDepthVariants();
|
||||
for (auto const variant: allDepthVariants) {
|
||||
assert_invariant(Variant::isValidDepthVariant(variant));
|
||||
mCachedPrograms[variant.key] = pDefaultMaterial->mCachedPrograms[variant.key];
|
||||
mCachedPrograms[variant.key] = mDefaultMaterial->mCachedPrograms[variant.key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,11 +134,11 @@ public:
|
||||
// prepareProgram creates the program for the material's given variant at the backend level.
|
||||
// Must be called outside of backend render pass.
|
||||
// Must be called before getProgram() below.
|
||||
void prepareProgram(Variant const variant,
|
||||
void prepareProgram(backend::DriverApi& driver, Variant const variant,
|
||||
backend::CompilerPriorityQueue const priorityQueue) const noexcept {
|
||||
// prepareProgram() is called for each RenderPrimitive in the scene, so it must be efficient.
|
||||
if (UTILS_UNLIKELY(!isCached(variant))) {
|
||||
prepareProgramSlow(variant, priorityQueue);
|
||||
prepareProgramSlow(driver, variant, priorityQueue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,11 +292,11 @@ private:
|
||||
MaterialParser const& getMaterialParser() const noexcept;
|
||||
|
||||
bool hasVariant(Variant variant) const noexcept;
|
||||
void prepareProgramSlow(Variant variant,
|
||||
void prepareProgramSlow(backend::DriverApi& driver, Variant variant,
|
||||
CompilerPriorityQueue priorityQueue) const noexcept;
|
||||
void getSurfaceProgramSlow(Variant variant,
|
||||
void getSurfaceProgramSlow(backend::DriverApi& driver, Variant variant,
|
||||
CompilerPriorityQueue priorityQueue) const noexcept;
|
||||
void getPostProcessProgramSlow(Variant variant,
|
||||
void getPostProcessProgramSlow(backend::DriverApi& driver, Variant variant,
|
||||
CompilerPriorityQueue priorityQueue) const noexcept;
|
||||
backend::Program getProgramWithVariants(Variant variant,
|
||||
Variant vertexVariant, Variant fragmentVariant) const;
|
||||
@@ -304,9 +304,9 @@ private:
|
||||
utils::FixedCapacityVector<backend::Program::SpecializationConstant>
|
||||
processSpecializationConstants(Builder const& builder);
|
||||
|
||||
void precacheDepthVariants(FEngine& engine);
|
||||
void precacheDepthVariants(backend::DriverApi& driver);
|
||||
|
||||
void createAndCacheProgram(backend::Program&& p, Variant variant) const noexcept;
|
||||
void createAndCacheProgram(backend::DriverApi& driver, backend::Program&& p, Variant variant) const noexcept;
|
||||
|
||||
backend::DescriptorSetLayout const& getPerViewDescriptorSetLayoutDescription(
|
||||
Variant const variant, bool const useVsmDescriptorSetLayout) const noexcept;
|
||||
@@ -325,6 +325,11 @@ private:
|
||||
bool mIsDefaultMaterial = false;
|
||||
|
||||
bool mUseUboBatching = false;
|
||||
bool mIsStereoSupported = false;
|
||||
bool mIsParallelShaderCompileSupported = false;
|
||||
bool mDepthPrecacheDisabled = false;
|
||||
|
||||
FMaterial const* mDefaultMaterial = nullptr;
|
||||
|
||||
// reserve some space to construct the default material instance
|
||||
mutable FMaterialInstance* mDefaultMaterialInstance = nullptr;
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#include <limits>
|
||||
#include <mutex>
|
||||
#include <string_view>
|
||||
#include <variant>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
+103
-138
@@ -37,7 +37,6 @@
|
||||
#include "fg/FrameGraphResources.h"
|
||||
#include "fg/FrameGraphTexture.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <private/filament/EngineEnums.h>
|
||||
#include <private/filament/Variant.h>
|
||||
|
||||
@@ -61,7 +60,6 @@
|
||||
#include <utils/Allocator.h>
|
||||
#include <utils/bitset.h>
|
||||
#include <utils/JobSystem.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Logger.h>
|
||||
#include <utils/Panic.h>
|
||||
#include <utils/compiler.h>
|
||||
@@ -99,7 +97,11 @@ FRenderer::FRenderer(FEngine& engine) :
|
||||
mHdrTranslucent(TextureFormat::RGBA16F),
|
||||
mHdrQualityMedium(TextureFormat::R11F_G11F_B10F),
|
||||
mHdrQualityHigh(TextureFormat::RGB16F),
|
||||
mFeatureLevel(FeatureLevel::FEATURE_LEVEL_0),
|
||||
mIsRGB8Supported(false),
|
||||
mIsFrameBufferFetchSupported(false),
|
||||
mIsFrameBufferFetchMultiSampleSupported(false),
|
||||
mIsAutoDepthResolveSupported(false),
|
||||
mUserEpoch(engine.getEngineEpoch()),
|
||||
mResourceAllocator(std::make_unique<TextureCache>(
|
||||
engine.getSharedResourceAllocatorDisposer(),
|
||||
@@ -134,7 +136,11 @@ FRenderer::FRenderer(FEngine& engine) :
|
||||
|
||||
DriverApi& driver = engine.getDriverApi();
|
||||
|
||||
mFeatureLevel = driver.getFeatureLevel();
|
||||
mIsRGB8Supported = driver.isRenderTargetFormatSupported(TextureFormat::RGB8);
|
||||
mIsFrameBufferFetchSupported = driver.isFrameBufferFetchSupported();
|
||||
mIsFrameBufferFetchMultiSampleSupported = driver.isFrameBufferFetchMultiSampleSupported();
|
||||
mIsAutoDepthResolveSupported = driver.isAutoDepthResolveSupported();
|
||||
|
||||
// our default HDR translucent format, fallback to LDR if not supported by the backend
|
||||
if (!driver.isRenderTargetFormatSupported(TextureFormat::RGBA16F)) {
|
||||
@@ -284,6 +290,9 @@ void FRenderer::skipFrame(uint64_t vsyncSteadyClockTimeNano) {
|
||||
mVsyncSteadyClockTimeNano = 0;
|
||||
}
|
||||
|
||||
mFrameId++;
|
||||
FILAMENT_TRACING_FRAME_ID(FILAMENT_TRACING_CATEGORY_FILAMENT, mFrameId);
|
||||
|
||||
FEngine& engine = mEngine;
|
||||
FEngine::DriverApi& driver = engine.getDriverApi();
|
||||
|
||||
@@ -298,52 +307,86 @@ void FRenderer::skipFrame(uint64_t vsyncSteadyClockTimeNano) {
|
||||
|
||||
engine.flush(); // flush command stream
|
||||
|
||||
// Run the component managers' GC
|
||||
auto& js = engine.getJobSystem();
|
||||
js.runAndWait(jobs::createJob(js, nullptr, &FEngine::gc, &engine)); // gc all managers
|
||||
// Run GC
|
||||
JobSystem& js = engine.getJobSystem();
|
||||
auto *rootJob = js.createJob();
|
||||
js.run(jobs::createJob(js, rootJob, &FEngine::gcManagers, &engine)); // gc all component managers
|
||||
if (engine.isAsynchronousModeEnabled()) {
|
||||
js.run(jobs::createJob(js, rootJob, &FEngine::gcDeferredAsyncObjectDestruction, &engine));
|
||||
}
|
||||
js.runAndWait(rootJob);
|
||||
|
||||
mFrameSkipper.frameSkipped();
|
||||
}
|
||||
|
||||
bool FRenderer::shouldRenderFrame() const noexcept {
|
||||
FEngine& engine = mEngine;
|
||||
FEngine::DriverApi& driver = engine.getDriverApi();
|
||||
return mFrameSkipper.shouldRenderFrame(driver);
|
||||
bool const renderFrame = mFrameSkipper.shouldRenderFrame(driver);
|
||||
if (renderFrame && engine.features.engine.skip_frame_when_cpu_ahead_of_display) {
|
||||
// see if we have another reason to skip
|
||||
auto history = mFrameInfoManager.getFrameInfoHistory();
|
||||
for (size_t i = 0, c = history.size(); i < c; i++) {
|
||||
FrameInfo const& info = history[i];
|
||||
if (int32_t(info.frameId - mLastFrameId) <= 0) {
|
||||
continue;
|
||||
}
|
||||
if (info.expectedPresentLatency < 0 || info.displayPresent < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// this frame's presentation latency (time from vsync to display)
|
||||
auto const presentLatency = info.displayPresent - info.vsync;
|
||||
|
||||
// The maximum latency we allow. we choose the expected presentation latency + one whole frame, this
|
||||
// is because be default the expected presentation latency is the shorted possible, and is usually almost
|
||||
// impossible to achieve, so we aim for an extra frame. The system is typically configured to allow this
|
||||
// (on Android), i.e. it has enough intermediary buffers.
|
||||
// TODO: the "expectedPresentLatency" should come from the user, and if they use the choreographer APIs
|
||||
// on Android, it will be set to that. Of course, we need an abstraction. This code assumes
|
||||
// the caller selected the default timeline.
|
||||
auto const maximumLatencyAllowed = info.expectedPresentLatency + info.displayPresentInterval;
|
||||
|
||||
// if we took a whole extra frame more than the maximum latency allowed, we need to skip a frame.
|
||||
// we use a whole frame because in practice the presentLatency will straddle around the
|
||||
// maximumLatency, and the latency "unit" is displayPresentInterval.
|
||||
if (presentLatency - maximumLatencyAllowed >= info.displayPresentInterval) {
|
||||
// Keep for debugging
|
||||
// LOG(INFO) << "skip frame " << mFrameId
|
||||
// << " because of frame " << info.frameId << " (" << (info.frameId - mFrameId) << ")"
|
||||
// << ", displayPresentInterval=" << info.displayPresentInterval
|
||||
// << ", expectedPresentLatency=" << info.expectedPresentLatency
|
||||
// << ", maximumLatencyAllowed=" << maximumLatencyAllowed
|
||||
// << ", latency=" << presentLatency
|
||||
// << ", missed=" << presentLatency - maximumLatencyAllowed
|
||||
// ;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return renderFrame;
|
||||
}
|
||||
|
||||
bool FRenderer::beginFrame(FSwapChain* swapChain, uint64_t vsyncSteadyClockTimeNano) {
|
||||
assert_invariant(swapChain);
|
||||
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
|
||||
#if 0 && defined(__ANDROID__)
|
||||
char scratch[PROP_VALUE_MAX + 1];
|
||||
int length = __system_property_get("debug.filament.protected", scratch);
|
||||
if (swapChain && length > 0) {
|
||||
uint64_t flags = swapChain->getFlags();
|
||||
bool value = bool(atoi(scratch));
|
||||
if (value) {
|
||||
flags |= SwapChain::CONFIG_PROTECTED_CONTENT;
|
||||
} else {
|
||||
flags &= ~SwapChain::CONFIG_PROTECTED_CONTENT;
|
||||
}
|
||||
swapChain->recreateWithNewFlags(mEngine, flags);
|
||||
}
|
||||
#endif
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT, "frameId", (mFrameId + 1));
|
||||
|
||||
if (!vsyncSteadyClockTimeNano) {
|
||||
vsyncSteadyClockTimeNano = mVsyncSteadyClockTimeNano;
|
||||
mVsyncSteadyClockTimeNano = 0;
|
||||
}
|
||||
|
||||
mFrameId++;
|
||||
FILAMENT_TRACING_FRAME_ID(FILAMENT_TRACING_CATEGORY_FILAMENT, mFrameId);
|
||||
|
||||
// get the timestamp as soon as possible
|
||||
using namespace std::chrono;
|
||||
const steady_clock::time_point now{ steady_clock::now() };
|
||||
const steady_clock::time_point userVsync{ steady_clock::duration(vsyncSteadyClockTimeNano) };
|
||||
const time_point appVsync(vsyncSteadyClockTimeNano ? userVsync : now);
|
||||
|
||||
mFrameId++;
|
||||
|
||||
FILAMENT_TRACING_FRAME_ID(FILAMENT_TRACING_CATEGORY_FILAMENT, mFrameId);
|
||||
|
||||
FEngine& engine = mEngine;
|
||||
FEngine::DriverApi& driver = engine.getDriverApi();
|
||||
|
||||
@@ -400,10 +443,10 @@ bool FRenderer::beginFrame(FSwapChain* swapChain, uint64_t vsyncSteadyClockTimeN
|
||||
}, mFrameId, appVsync);
|
||||
|
||||
// ask the engine to do what it needs to (e.g. updates light buffer, materials...)
|
||||
engine.prepare();
|
||||
engine.prepare(driver);
|
||||
};
|
||||
|
||||
if (mFrameSkipper.shouldRenderFrame(driver)) {
|
||||
if (shouldRenderFrame()) {
|
||||
// if beginFrame() returns true, we are expecting a call to endFrame(),
|
||||
// so do the beginFrame work right now, instead of requiring a call to render()
|
||||
beginFrameInternal();
|
||||
@@ -421,6 +464,9 @@ bool FRenderer::beginFrame(FSwapChain* swapChain, uint64_t vsyncSteadyClockTimeN
|
||||
// we need to flush in this case, to make sure the tick() call is executed at some point
|
||||
engine.flush();
|
||||
|
||||
// we cannot detect more until we reach at least this frame
|
||||
mLastFrameId = mFrameId;
|
||||
mFrameSkipper.frameSkipped();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -469,9 +515,14 @@ void FRenderer::endFrame() {
|
||||
|
||||
engine.flush(); // flush command stream
|
||||
|
||||
// Run the component managers' GC
|
||||
auto& js = engine.getJobSystem();
|
||||
js.runAndWait(jobs::createJob(js, nullptr, &FEngine::gc, &engine)); // gc all managers
|
||||
// Run GC
|
||||
JobSystem& js = engine.getJobSystem();
|
||||
auto *rootJob = js.createJob();
|
||||
js.run(jobs::createJob(js, rootJob, &FEngine::gcManagers, &engine)); // gc all component managers
|
||||
if (engine.isAsynchronousModeEnabled()) {
|
||||
js.run(jobs::createJob(js, rootJob, &FEngine::gcDeferredAsyncObjectDestruction, &engine));
|
||||
}
|
||||
js.runAndWait(rootJob);
|
||||
}
|
||||
|
||||
void FRenderer::readPixels(
|
||||
@@ -568,9 +619,10 @@ void FRenderer::renderStandaloneView(FView const* view) {
|
||||
|
||||
// ask the engine to do what it needs to (e.g. updates light buffer, materials...)
|
||||
FEngine& engine = mEngine;
|
||||
engine.prepare();
|
||||
|
||||
FEngine::DriverApi& driver = engine.getDriverApi();
|
||||
|
||||
engine.prepare(driver);
|
||||
|
||||
driver.beginFrame(
|
||||
steady_clock::now().time_since_epoch().count(),
|
||||
mDisplayInfo.refreshRate == 0.0 ? 0 : int64_t(
|
||||
@@ -579,7 +631,7 @@ void FRenderer::renderStandaloneView(FView const* view) {
|
||||
// because we don't have a "present" call, we use flush so the driver can submit
|
||||
// the command buffer; we do this before driver.endFrame() to mimic what would
|
||||
// happen with Renderer::beginFrame/endFrame.
|
||||
renderInternal(view, true);
|
||||
renderInternal(driver, view, true);
|
||||
|
||||
engine.submitFrame();
|
||||
|
||||
@@ -587,7 +639,7 @@ void FRenderer::renderStandaloneView(FView const* view) {
|
||||
|
||||
// engine.flush() has already been called by renderInternal(), but we need an extra one
|
||||
// for endFrame() above. This operation in actually not too heavy, it just kicks the
|
||||
// driver thread, which is mostlikely already running.
|
||||
// driver thread, which is most likely already running.
|
||||
engine.flush();
|
||||
}
|
||||
}
|
||||
@@ -606,11 +658,11 @@ void FRenderer::render(FView const* view) {
|
||||
assert_invariant(mSwapChain);
|
||||
|
||||
if (UTILS_LIKELY(view && view->getScene() && view->hasCamera())) {
|
||||
renderInternal(view, false);
|
||||
renderInternal(mEngine.getDriverApi(), view, false);
|
||||
}
|
||||
}
|
||||
|
||||
void FRenderer::renderInternal(FView const* view, bool flush) {
|
||||
void FRenderer::renderInternal(DriverApi& driver, FView const* view, bool flush) {
|
||||
FEngine& engine = mEngine;
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(!view->hasPostProcessPass() ||
|
||||
@@ -625,10 +677,10 @@ void FRenderer::renderInternal(FView const* view, bool flush) {
|
||||
auto *rootJob = js.setRootJob(js.createJob());
|
||||
|
||||
// execute the render pass
|
||||
renderJob(rootArenaScope, const_cast<FView&>(*view));
|
||||
renderJob(driver, rootArenaScope, const_cast<FView&>(*view));
|
||||
|
||||
if (flush) {
|
||||
engine.getDriverApi().flush();
|
||||
driver.flush();
|
||||
}
|
||||
|
||||
// make sure to flush the command buffer
|
||||
@@ -638,10 +690,9 @@ void FRenderer::renderInternal(FView const* view, bool flush) {
|
||||
js.runAndWait(rootJob);
|
||||
}
|
||||
|
||||
void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
|
||||
void FRenderer::renderJob(DriverApi& driver, RootArenaScope& rootArenaScope, FView& view) {
|
||||
FEngine& engine = mEngine;
|
||||
JobSystem& js = engine.getJobSystem();
|
||||
FEngine::DriverApi& driver = engine.getDriverApi();
|
||||
PostProcessManager& ppm = engine.getPostProcessManager();
|
||||
ppm.resetForRender();
|
||||
ppm.setFrameUniforms(driver, view.getFrameUniforms());
|
||||
@@ -691,7 +742,7 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
|
||||
} else {
|
||||
// This configures post-process materials by setting constant parameters
|
||||
if (taaOptions.enabled) {
|
||||
ppm.configureTemporalAntiAliasingMaterial(taaOptions);
|
||||
ppm.configureTemporalAntiAliasingMaterial(driver, taaOptions);
|
||||
if (taaOptions.upscaling > 1.0f) {
|
||||
// for now TAA upscaling is incompatible with regular dsr
|
||||
dsrOptions.enabled = false;
|
||||
@@ -726,11 +777,11 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
|
||||
const PostProcessManager::ColorGradingConfig colorGradingConfig{
|
||||
.asSubpass =
|
||||
isSubpassPossible &&
|
||||
driver.isFrameBufferFetchSupported() &&
|
||||
mIsFrameBufferFetchSupported &&
|
||||
!engine.debug.renderer.disable_subpasses,
|
||||
.customResolve =
|
||||
msaaSampleCount > 1 &&
|
||||
driver.isFrameBufferFetchMultiSampleSupported() &&
|
||||
mIsFrameBufferFetchMultiSampleSupported &&
|
||||
msaaOptions.customResolve &&
|
||||
hasColorGrading &&
|
||||
!engine.debug.renderer.disable_subpasses,
|
||||
@@ -1009,7 +1060,9 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
|
||||
.hasContactShadows = scene.hasContactShadows(),
|
||||
// at this point we don't know if we have refraction, but that's handled later
|
||||
.hasScreenSpaceReflectionsOrRefractions = ssReflectionsOptions.enabled,
|
||||
.enabledStencilBuffer = view.isStencilBufferEnabled()
|
||||
.enabledStencilBuffer = view.isStencilBufferEnabled(),
|
||||
.featureLevel = mFeatureLevel,
|
||||
.isAutoDepthResolveSupported = mIsAutoDepthResolveSupported
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1199,7 +1252,7 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
|
||||
}
|
||||
|
||||
// create the pass, which generates all its commands (this is a heavy operation)
|
||||
RenderPass const pass{ passBuilder.build(engine) };
|
||||
RenderPass const pass{ passBuilder.build(engine, driver) };
|
||||
|
||||
// now that we have the commands we can figure out if we have refraction commands
|
||||
auto* const firstRefractionCommand = [&view](RenderPass const& pass) {
|
||||
@@ -1245,10 +1298,9 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
|
||||
.shadows = blackboard.get<FrameGraphTexture>("shadows"),
|
||||
.ssao = blackboard.get<FrameGraphTexture>("ssao"),
|
||||
.ssr = ssrConfig.ssr,
|
||||
.structure = structure
|
||||
},
|
||||
config, ssrConfig, colorGradingConfigForColor,
|
||||
pass, firstRefractionCommand);
|
||||
.structure = structure
|
||||
}, config, ssrConfig, colorGradingConfigForColor,
|
||||
pass, firstRefractionCommand);
|
||||
}
|
||||
|
||||
if (colorGradingConfig.customResolve) {
|
||||
@@ -1492,18 +1544,12 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
|
||||
|
||||
fg.forwardResource(fgViewRenderTarget, input);
|
||||
|
||||
#if FILAMENT_ENABLE_FGVIEWER
|
||||
fgviewer::DebugServer* fgviewerServer = engine.debug.fgviewerServer;
|
||||
if (UTILS_LIKELY(fgviewerServer)) {
|
||||
readPixels(fg, blackboard);
|
||||
}
|
||||
#endif
|
||||
|
||||
fg.present(fgViewRenderTarget);
|
||||
|
||||
fg.compile();
|
||||
|
||||
#if FILAMENT_ENABLE_FGVIEWER
|
||||
fgviewer::DebugServer* fgviewerServer = engine.debug.fgviewerServer;
|
||||
if (UTILS_LIKELY(fgviewerServer)) {
|
||||
fgviewerServer->update(view.getViewHandle(), fg.getFrameGraphInfo(view.getName()));
|
||||
}
|
||||
@@ -1515,91 +1561,10 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
|
||||
|
||||
fg.execute(driver);
|
||||
|
||||
#if FILAMENT_ENABLE_FGVIEWER
|
||||
if (UTILS_LIKELY(fgviewerServer)) {
|
||||
fgviewerServer->tick();
|
||||
}
|
||||
#endif
|
||||
|
||||
// save the current history entry and destroy the oldest entry
|
||||
view.commitFrameHistory(engine);
|
||||
|
||||
recordHighWatermark(commandArena.getListener().getHighWatermark());
|
||||
}
|
||||
|
||||
#if FILAMENT_ENABLE_FGVIEWER
|
||||
|
||||
void FRenderer::readPixels(FrameGraph& fg, Blackboard& blackboard) {
|
||||
|
||||
FEngine& engine = mEngine;
|
||||
std::vector<FEngine::ReadbackRequest> requests;
|
||||
|
||||
{ // scope for lock
|
||||
std::unique_lock<utils::Mutex> lock(engine.mReadbackRequestsMutex);
|
||||
requests = std::move(engine.mReadbackRequests);
|
||||
engine.mReadbackRequests.clear();
|
||||
}
|
||||
|
||||
for (auto& request : requests) {
|
||||
FrameGraphId<FrameGraphTexture> fgTexture = fg.getTextureByName(request.name.c_str());
|
||||
if (!fgTexture.isInitialized()) {
|
||||
slog.w << "[fgviewer] Requested texture \"" << request.name.c_str_safe()
|
||||
<< "\" not found in FrameGraph." << io::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
struct ReadbackPassData {
|
||||
FrameGraphId<FrameGraphTexture> texture;
|
||||
};
|
||||
fg.addPass<ReadbackPassData>(
|
||||
"Readback Pass",
|
||||
[&](FrameGraph::Builder& builder, ReadbackPassData& data) {
|
||||
data.texture = builder.read(fgTexture, FrameGraphTexture::Usage::SAMPLEABLE);
|
||||
builder.sideEffect(); // Ensure this pass is not culled
|
||||
},
|
||||
[request = std::move(request)](FrameGraphResources const& resources,
|
||||
ReadbackPassData const& data, DriverApi& d) {
|
||||
const FrameGraphTexture::Descriptor& desc =
|
||||
resources.getDescriptor(data.texture);
|
||||
|
||||
backend::PixelBufferDescriptor::PixelDataFormat format =
|
||||
PixelBufferDescriptor::PixelDataFormat::RGBA;
|
||||
backend::PixelBufferDescriptor::PixelDataType type =
|
||||
PixelBufferDescriptor::PixelDataType::UBYTE;
|
||||
fgviewer::DebugServer::PixelDataFormat targetFormat =
|
||||
fgviewer::DebugServer::Format::RGBA;
|
||||
const size_t bufferSize = desc.width * desc.height * 4;
|
||||
|
||||
fgviewer::DebugServer::PixelBuffer pixelBuffer(bufferSize);
|
||||
void* bufferData = pixelBuffer.data();
|
||||
|
||||
struct UserData {
|
||||
size_t width;
|
||||
size_t height;
|
||||
fgviewer::DebugServer::PixelDataFormat targetFormat;
|
||||
FEngine::ReadbackRequest::Callback callback;
|
||||
fgviewer::DebugServer::PixelBuffer pixelBuffer;
|
||||
};
|
||||
|
||||
PixelBufferDescriptor pbd(
|
||||
bufferData, bufferSize, format, type, 1, 0, 0, 0, 0,
|
||||
[](void* buffer, size_t size, void* user) {
|
||||
std::unique_ptr<UserData> d {static_cast<UserData*>(user)};
|
||||
auto& callback = d->callback;
|
||||
callback(std::move(d->pixelBuffer), d->width, d->height, d->targetFormat);
|
||||
},
|
||||
new UserData{ desc.width, desc.height, targetFormat,
|
||||
std::move(request.callback), std::move(pixelBuffer) });
|
||||
|
||||
MRT color(resources.getTexture(data.texture), 0, 0);
|
||||
Handle<HwRenderTarget> rt = d.createRenderTarget(TargetBufferFlags::COLOR0,
|
||||
desc.width, desc.height, 1, 1, color, {}, {});
|
||||
|
||||
d.readPixels(rt, 0, 0, desc.width, desc.height, std::move(pbd));
|
||||
d.destroyRenderTarget(rt);
|
||||
});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -55,7 +55,6 @@
|
||||
namespace filament {
|
||||
|
||||
class TextureCache;
|
||||
class Blackboard;
|
||||
|
||||
namespace backend {
|
||||
class Driver;
|
||||
@@ -84,7 +83,7 @@ public:
|
||||
|
||||
void resetUserTime();
|
||||
|
||||
void skipNextFrames(size_t frameCount) const noexcept {
|
||||
void skipNextFrames(size_t frameCount) noexcept {
|
||||
mFrameSkipper.skipNextFrames(frameCount);
|
||||
}
|
||||
|
||||
@@ -197,11 +196,8 @@ private:
|
||||
return mCommandsHighWatermark;
|
||||
}
|
||||
|
||||
void renderInternal(FView const* view, bool flush);
|
||||
void renderJob(RootArenaScope& rootArenaScope, FView& view);
|
||||
#if FILAMENT_ENABLE_FGVIEWER
|
||||
void readPixels(FrameGraph& fg, Blackboard& blackboard);
|
||||
#endif
|
||||
void renderInternal(backend::DriverApi& driver, FView const* view, bool flush);
|
||||
void renderJob(backend::DriverApi& driver, RootArenaScope& rootArenaScope, FView& view);
|
||||
|
||||
static std::pair<float, math::float2> prepareUpscaler(math::float2 scale,
|
||||
TemporalAntiAliasingOptions const& taaOptions,
|
||||
@@ -218,7 +214,11 @@ private:
|
||||
backend::TextureFormat mHdrTranslucent;
|
||||
backend::TextureFormat mHdrQualityMedium;
|
||||
backend::TextureFormat mHdrQualityHigh;
|
||||
backend::FeatureLevel mFeatureLevel;
|
||||
bool mIsRGB8Supported : 1;
|
||||
bool mIsFrameBufferFetchSupported : 1;
|
||||
bool mIsFrameBufferFetchMultiSampleSupported : 1;
|
||||
bool mIsAutoDepthResolveSupported : 1;
|
||||
Epoch mUserEpoch;
|
||||
math::float4 mShaderUserTime{};
|
||||
DisplayInfo mDisplayInfo;
|
||||
@@ -230,6 +230,7 @@ private:
|
||||
std::function<void()> mBeginFrameInternal;
|
||||
uint64_t mVsyncSteadyClockTimeNano = 0;
|
||||
std::unique_ptr<TextureCache> mResourceAllocator{};
|
||||
int64_t mLastFrameId = -1;
|
||||
};
|
||||
|
||||
FILAMENT_DOWNCAST(Renderer)
|
||||
|
||||
@@ -394,8 +394,10 @@ bool FView::isSkyboxVisible() const noexcept {
|
||||
return skybox != nullptr && (skybox->getLayerMask() & mVisibleLayers);
|
||||
}
|
||||
|
||||
void FView::prepareShadowing(FEngine& engine, FScene::RenderableSoa& renderableData,
|
||||
FScene::LightSoa const& lightData, CameraInfo const& cameraInfo) noexcept {
|
||||
void FView::prepareShadowing(FEngine& engine, DriverApi& driver,
|
||||
FScene::RenderableSoa& renderableData,
|
||||
FScene::LightSoa const& lightData,
|
||||
CameraInfo const& cameraInfo) noexcept {
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
|
||||
mHasShadowing = false;
|
||||
@@ -404,7 +406,7 @@ void FView::prepareShadowing(FEngine& engine, FScene::RenderableSoa& renderableD
|
||||
return;
|
||||
}
|
||||
|
||||
auto& lcm = engine.getLightManager();
|
||||
auto const& lcm = engine.getLightManager();
|
||||
|
||||
ShadowMapManager::Builder builder;
|
||||
|
||||
@@ -461,8 +463,8 @@ void FView::prepareShadowing(FEngine& engine, FScene::RenderableSoa& renderableD
|
||||
|
||||
if (builder.hasShadowMaps()) {
|
||||
ShadowMapManager::createIfNeeded(engine, mShadowMapManager);
|
||||
auto const shadowTechnique = mShadowMapManager->update(builder, engine, *this,
|
||||
cameraInfo, renderableData, lightData);
|
||||
auto const shadowTechnique = mShadowMapManager->update(driver, builder, engine,
|
||||
*this, cameraInfo, renderableData, lightData);
|
||||
|
||||
mHasShadowing = any(shadowTechnique);
|
||||
mNeedsShadowMap = any(shadowTechnique & ShadowMapManager::ShadowTechnique::SHADOW_MAP);
|
||||
@@ -685,7 +687,7 @@ void FView::prepare(FEngine& engine, DriverApi& driver, RootArenaScope& rootAren
|
||||
|
||||
setFroxelizerSync(froxelizeLightsJob);
|
||||
|
||||
prepareShadowing(engine, renderableData, lightData, cameraInfo);
|
||||
prepareShadowing(engine, driver, renderableData, lightData, cameraInfo);
|
||||
|
||||
/*
|
||||
* Partition the SoA so that renderables are partitioned w.r.t their visibility into the
|
||||
|
||||
@@ -163,8 +163,8 @@ public:
|
||||
const Viewport& physicalViewport,
|
||||
const Viewport& logicalViewport) const noexcept;
|
||||
|
||||
void prepareShadowing(FEngine& engine, FScene::RenderableSoa& renderableData,
|
||||
FScene::LightSoa const& lightData, CameraInfo const& cameraInfo) noexcept;
|
||||
void prepareShadowing(FEngine& engine, backend::DriverApi& driver,
|
||||
FScene::RenderableSoa& renderableData, FScene::LightSoa const& lightData, CameraInfo const& cameraInfo) noexcept;
|
||||
void prepareLighting(FEngine& engine, CameraInfo const& cameraInfo) noexcept;
|
||||
|
||||
void prepareSSAO(backend::Handle<backend::HwTexture> ssao) const noexcept;
|
||||
|
||||
@@ -582,21 +582,6 @@ fgviewer::FrameGraphInfo FrameGraph::getFrameGraphInfo(const char *viewName) con
|
||||
#endif
|
||||
}
|
||||
|
||||
#if FILAMENT_ENABLE_FGVIEWER
|
||||
FrameGraphId<FrameGraphTexture> FrameGraph::getTextureByName(const char* name) const {
|
||||
for (size_t i = 0; i < mResourceSlots.size(); ++i) {
|
||||
const auto& slot = mResourceSlots[i];
|
||||
const VirtualResource* resource = mResources[slot.rid];
|
||||
if (strcmp(resource->name.data(), name) == 0) {
|
||||
FrameGraphHandle handle((FrameGraphHandle::Index)i);
|
||||
handle.version = slot.version;
|
||||
return FrameGraphId<FrameGraphTexture>(handle);
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
|
||||
#include "fg/details/DependencyGraph.h"
|
||||
#include "fg/details/Resource.h"
|
||||
#include "fg/details/ResourceCreationContext.h"
|
||||
#include "fg/details/Utilities.h"
|
||||
|
||||
#include "backend/DriverApiForward.h"
|
||||
@@ -37,8 +36,6 @@
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <utils/Log.h>
|
||||
|
||||
#if FILAMENT_ENABLE_FGVIEWER
|
||||
#include <fgviewer/FrameGraphInfo.h>
|
||||
#else
|
||||
@@ -451,21 +448,8 @@ public:
|
||||
* Export a fgviewer::FrameGraphInfo for current graph.
|
||||
* Note that this function should be called after FrameGraph::compile().
|
||||
*/
|
||||
#if FILAMENT_ENABLE_FGVIEWER
|
||||
fgviewer::FrameGraphInfo getFrameGraphInfo(const char *viewName) const;
|
||||
|
||||
/**
|
||||
* Retrieve a texture handle by its name. This is used for debugging/visualization tools.
|
||||
* @param name Name of the resource
|
||||
* @return Handle to the texture, or an uninitialized handle if not found.
|
||||
*/
|
||||
FrameGraphId<FrameGraphTexture> getTextureByName(const char* name) const;
|
||||
#else
|
||||
fgviewer::FrameGraphInfo getFrameGraphInfo(const char*) const {
|
||||
return fgviewer::FrameGraphInfo();
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
friend class FrameGraphResources;
|
||||
friend class PassNode;
|
||||
@@ -689,4 +673,4 @@ extern template FrameGraphId<FrameGraphTexture> FrameGraph::forwardResource(
|
||||
|
||||
} // namespace filament
|
||||
|
||||
#endif // TNT_FILAMENT_FG_FRAMEGRAPH_H
|
||||
#endif //TNT_FILAMENT_FG_FRAMEGRAPH_H
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user