Compare commits
29
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 | ||
|
|
408b2371f0 | ||
|
|
6ea08b40a8 | ||
|
|
5eb0f7d3ec | ||
|
|
d465d59c3a | ||
|
|
af9a60d175 |
@@ -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:
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
- uses: ./.github/actions/mac-prereq
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/mac && printf "y" | ./build.sh presubmit
|
||||
cd build/mac && printf "y" | ./build.sh presubmit-with-test
|
||||
- name: Test material parser
|
||||
run: |
|
||||
out/cmake-release/filament/test/test_material_parser
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -34,6 +34,11 @@ if [[ "$TARGET" == "presubmit" ]]; then
|
||||
BUILD_RELEASE=release
|
||||
fi
|
||||
|
||||
if [[ "$TARGET" == "presubmit-with-test" ]]; then
|
||||
BUILD_RELEASE=release
|
||||
RUN_TESTS=-u
|
||||
fi
|
||||
|
||||
if [[ "$TARGET" == "debug" ]]; then
|
||||
BUILD_DEBUG=debug
|
||||
GENERATE_ARCHIVES=-a
|
||||
|
||||
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.2'
|
||||
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.2'
|
||||
<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>
|
||||
|
||||
+199
-199
@@ -504,9 +504,9 @@ D_{GGX}(h,\alpha) = \frac{\aa}{\pi ( (\NoH)^2 (\aa - 1) + 1)^2}
|
||||
\end{equation}$$
|
||||
</p><p>
|
||||
The GLSL implementation of the NDF, shown in <a href="#listing_speculard">listing 1</a>, is simple and efficient.
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-function"><span class="hljs-built_in">float</span> <span class="hljs-title">D_GGX</span>(<span class="hljs-params"><span class="hljs-built_in">float</span> NoH, <span class="hljs-built_in">float</span> roughness</span>)</span> {</span>
|
||||
<span class="line"> <span class="hljs-built_in">float</span> a = NoH * roughness;</span>
|
||||
<span class="line"> <span class="hljs-built_in">float</span> k = roughness / (<span class="hljs-number">1.0</span> - NoH * NoH + a * a);</span>
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-function"><span class="hljs-type">float</span> <span class="hljs-title">D_GGX</span><span class="hljs-params">(<span class="hljs-type">float</span> NoH, <span class="hljs-type">float</span> roughness)</span> </span>{</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> a = NoH * roughness;</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> k = roughness / (<span class="hljs-number">1.0</span> - NoH * NoH + a * a);</span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> k * k * (<span class="hljs-number">1.0</span> / PI);</span>
|
||||
<span class="line">}</span></code></pre><center><div class="listingcaption tilde"><a class="target" name="listing_speculard"> </a><b style="font-style:normal;">Listing 1:</b> Implementation of the specular D term in GLSL</div></center>
|
||||
<p>
|
||||
@@ -590,10 +590,10 @@ V(v,l,\alpha) = \frac{0.5}{\NoL \sqrt{(\NoV)^2 (1 - \aa) + \aa} + \NoV \sqrt{(\N
|
||||
\end{equation}$$
|
||||
</p><p>
|
||||
The GLSL implementation of the visibility term, shown in <a href="#listing_specularv">listing 3</a>, is a bit more expensive than we would like since it requires two <code>sqrt</code> operations.
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-function"><span class="hljs-keyword">float</span> <span class="hljs-title">V_SmithGGXCorrelated</span><span class="hljs-params">(<span class="hljs-keyword">float</span> NoV, <span class="hljs-keyword">float</span> NoL, <span class="hljs-keyword">float</span> roughness)</span> </span>{</span>
|
||||
<span class="line"> <span class="hljs-keyword">float</span> a2 = roughness * roughness;</span>
|
||||
<span class="line"> <span class="hljs-keyword">float</span> GGXV = NoL * <span class="hljs-built_in">sqrt</span>(NoV * NoV * (<span class="hljs-number">1.0</span> - a2) + a2);</span>
|
||||
<span class="line"> <span class="hljs-keyword">float</span> GGXL = NoV * <span class="hljs-built_in">sqrt</span>(NoL * NoL * (<span class="hljs-number">1.0</span> - a2) + a2);</span>
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-function"><span class="hljs-type">float</span> <span class="hljs-title">V_SmithGGXCorrelated</span><span class="hljs-params">(<span class="hljs-type">float</span> NoV, <span class="hljs-type">float</span> NoL, <span class="hljs-type">float</span> roughness)</span> </span>{</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> a2 = roughness * roughness;</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> GGXV = NoL * <span class="hljs-built_in">sqrt</span>(NoV * NoV * (<span class="hljs-number">1.0</span> - a2) + a2);</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> GGXL = NoV * <span class="hljs-built_in">sqrt</span>(NoL * NoL * (<span class="hljs-number">1.0</span> - a2) + a2);</span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> <span class="hljs-number">0.5</span> / (GGXV + GGXL);</span>
|
||||
<span class="line">}</span></code></pre><center><div class="listingcaption tilde"><a class="target" name="listing_specularv"> </a><b style="font-style:normal;">Listing 3:</b> Implementation of the specular V term in GLSL</div></center>
|
||||
<p>
|
||||
@@ -604,10 +604,10 @@ V(v,l,\alpha) = \frac{0.5}{\NoL (\NoV (1 - \alpha) + \alpha) + \NoV (\NoL (1 - \
|
||||
\end{equation}$$
|
||||
</p><p>
|
||||
This approximation is mathematically wrong but saves two square root operations and is good enough for real-time mobile applications, as shown in <a href="#listing_approximatedspecularv">listing 4</a>.
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-function"><span class="hljs-built_in">float</span> <span class="hljs-title">V_SmithGGXCorrelatedFast</span>(<span class="hljs-params"><span class="hljs-built_in">float</span> NoV, <span class="hljs-built_in">float</span> NoL, <span class="hljs-built_in">float</span> roughness</span>)</span> {</span>
|
||||
<span class="line"> <span class="hljs-built_in">float</span> a = roughness;</span>
|
||||
<span class="line"> <span class="hljs-built_in">float</span> GGXV = NoL * (NoV * (<span class="hljs-number">1.0</span> - a) + a);</span>
|
||||
<span class="line"> <span class="hljs-built_in">float</span> GGXL = NoV * (NoL * (<span class="hljs-number">1.0</span> - a) + a);</span>
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-function"><span class="hljs-type">float</span> <span class="hljs-title">V_SmithGGXCorrelatedFast</span><span class="hljs-params">(<span class="hljs-type">float</span> NoV, <span class="hljs-type">float</span> NoL, <span class="hljs-type">float</span> roughness)</span> </span>{</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> a = roughness;</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> GGXV = NoL * (NoV * (<span class="hljs-number">1.0</span> - a) + a);</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> GGXL = NoV * (NoL * (<span class="hljs-number">1.0</span> - a) + a);</span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> <span class="hljs-number">0.5</span> / (GGXV + GGXL);</span>
|
||||
<span class="line">}</span></code></pre><center><div class="listingcaption tilde"><a class="target" name="listing_approximatedspecularv"> </a><b style="font-style:normal;">Listing 4:</b> Implementation of the approximated specular V term in GLSL</div></center>
|
||||
<p>
|
||||
@@ -659,7 +659,7 @@ $$\begin{equation}
|
||||
\end{equation}$$
|
||||
</p><p>
|
||||
In practice, the diffuse reflectance \(\sigma\) is multiplied later, as shown in <a href="#listing_diffusebrdf">listing 8</a>.
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-function"><span class="hljs-built_in">float</span> <span class="hljs-title">Fd_Lambert</span>(<span class="hljs-params"></span>)</span> {</span>
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-function"><span class="hljs-built_in">float</span> <span class="hljs-title">Fd_Lambert</span>()</span> {</span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> <span class="hljs-number">1.0</span> / PI;</span>
|
||||
<span class="line">}</span>
|
||||
<span class="line"></span>
|
||||
@@ -680,14 +680,14 @@ Where:
|
||||
$$\begin{equation}
|
||||
\fGrazing=0.5 + 2 \cdot \alpha cos^2(\theta_d)
|
||||
\end{equation}$$
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-function"><span class="hljs-keyword">float</span> <span class="hljs-title">F_Schlick</span><span class="hljs-params">(<span class="hljs-keyword">float</span> u, <span class="hljs-keyword">float</span> f0, <span class="hljs-keyword">float</span> f90)</span> </span>{</span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> f0 + (f90 - f0) * <span class="hljs-built_in">pow</span>(<span class="hljs-number">1.0</span> - u, <span class="hljs-number">5.0</span>);</span>
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-type">float</span> <span class="hljs-title function_">F_Schlick</span><span class="hljs-params">(<span class="hljs-type">float</span> u, <span class="hljs-type">float</span> f0, <span class="hljs-type">float</span> f90)</span> {</span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> f0 + (f90 - f0) * pow(<span class="hljs-number">1.0</span> - u, <span class="hljs-number">5.0</span>);</span>
|
||||
<span class="line">}</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"><span class="hljs-function"><span class="hljs-keyword">float</span> <span class="hljs-title">Fd_Burley</span><span class="hljs-params">(<span class="hljs-keyword">float</span> NoV, <span class="hljs-keyword">float</span> NoL, <span class="hljs-keyword">float</span> LoH, <span class="hljs-keyword">float</span> roughness)</span> </span>{</span>
|
||||
<span class="line"> <span class="hljs-keyword">float</span> f90 = <span class="hljs-number">0.5</span> + <span class="hljs-number">2.0</span> * roughness * LoH * LoH;</span>
|
||||
<span class="line"> <span class="hljs-keyword">float</span> lightScatter = F_Schlick(NoL, <span class="hljs-number">1.0</span>, f90);</span>
|
||||
<span class="line"> <span class="hljs-keyword">float</span> viewScatter = F_Schlick(NoV, <span class="hljs-number">1.0</span>, f90);</span>
|
||||
<span class="line"><span class="hljs-type">float</span> <span class="hljs-title function_">Fd_Burley</span><span class="hljs-params">(<span class="hljs-type">float</span> NoV, <span class="hljs-type">float</span> NoL, <span class="hljs-type">float</span> LoH, <span class="hljs-type">float</span> roughness)</span> {</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> <span class="hljs-variable">f90</span> <span class="hljs-operator">=</span> <span class="hljs-number">0.5</span> + <span class="hljs-number">2.0</span> * roughness * LoH * LoH;</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> <span class="hljs-variable">lightScatter</span> <span class="hljs-operator">=</span> F_Schlick(NoL, <span class="hljs-number">1.0</span>, f90);</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> <span class="hljs-variable">viewScatter</span> <span class="hljs-operator">=</span> F_Schlick(NoV, <span class="hljs-number">1.0</span>, f90);</span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> lightScatter * viewScatter * (<span class="hljs-number">1.0</span> / PI);</span>
|
||||
<span class="line">}</span></code></pre><center><div class="listingcaption tilde"><a class="target" name="listing_diffusebrdf"> </a><b style="font-style:normal;">Listing 8:</b> Implementation of the diffuse Disney BRDF in GLSL</div></center>
|
||||
<p>
|
||||
@@ -704,47 +704,47 @@ We could allow artists/developers to choose the Disney diffuse BRDF depending on
|
||||
<strong class="asterisk">Diffuse term</strong>: a Lambertian diffuse model.
|
||||
</p><p>
|
||||
The full GLSL implementation of the standard model is shown in <a href="#listing_glslbrdf">listing 9</a>.
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-type">float</span> D_GGX(<span class="hljs-type">float</span> NoH, <span class="hljs-type">float</span> a) {</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> a2 = a * a;</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> f = (NoH * a2 - NoH) * NoH + <span class="hljs-number">1.0</span>;</span>
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-type">float</span> <span class="hljs-title function_">D_GGX</span><span class="hljs-params">(<span class="hljs-type">float</span> NoH, <span class="hljs-type">float</span> a)</span> {</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> <span class="hljs-variable">a2</span> <span class="hljs-operator">=</span> a * a;</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> <span class="hljs-variable">f</span> <span class="hljs-operator">=</span> (NoH * a2 - NoH) * NoH + <span class="hljs-number">1.0</span>;</span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> a2 / (PI * f * f);</span>
|
||||
<span class="line">}</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"><span class="hljs-type">vec3</span> F_Schlick(<span class="hljs-type">float</span> u, <span class="hljs-type">vec3</span> f0) {</span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> f0 + (<span class="hljs-type">vec3</span>(<span class="hljs-number">1.0</span>) - f0) * <span class="hljs-built_in">pow</span>(<span class="hljs-number">1.0</span> - u, <span class="hljs-number">5.0</span>);</span>
|
||||
<span class="line">vec3 <span class="hljs-title function_">F_Schlick</span><span class="hljs-params">(<span class="hljs-type">float</span> u, vec3 f0)</span> {</span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> f0 + (vec3(<span class="hljs-number">1.0</span>) - f0) * pow(<span class="hljs-number">1.0</span> - u, <span class="hljs-number">5.0</span>);</span>
|
||||
<span class="line">}</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"><span class="hljs-type">float</span> V_SmithGGXCorrelated(<span class="hljs-type">float</span> NoV, <span class="hljs-type">float</span> NoL, <span class="hljs-type">float</span> a) {</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> a2 = a * a;</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> GGXL = NoV * <span class="hljs-built_in">sqrt</span>((-NoL * a2 + NoL) * NoL + a2);</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> GGXV = NoL * <span class="hljs-built_in">sqrt</span>((-NoV * a2 + NoV) * NoV + a2);</span>
|
||||
<span class="line"><span class="hljs-type">float</span> <span class="hljs-title function_">V_SmithGGXCorrelated</span><span class="hljs-params">(<span class="hljs-type">float</span> NoV, <span class="hljs-type">float</span> NoL, <span class="hljs-type">float</span> a)</span> {</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> <span class="hljs-variable">a2</span> <span class="hljs-operator">=</span> a * a;</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> <span class="hljs-variable">GGXL</span> <span class="hljs-operator">=</span> NoV * sqrt((-NoL * a2 + NoL) * NoL + a2);</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> <span class="hljs-variable">GGXV</span> <span class="hljs-operator">=</span> NoL * sqrt((-NoV * a2 + NoV) * NoV + a2);</span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> <span class="hljs-number">0.5</span> / (GGXV + GGXL);</span>
|
||||
<span class="line">}</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"><span class="hljs-type">float</span> Fd_Lambert() {</span>
|
||||
<span class="line"><span class="hljs-type">float</span> <span class="hljs-title function_">Fd_Lambert</span><span class="hljs-params">()</span> {</span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> <span class="hljs-number">1.0</span> / PI;</span>
|
||||
<span class="line">}</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"><span class="hljs-type">void</span> BRDF(...) {</span>
|
||||
<span class="line"> <span class="hljs-type">vec3</span> h = <span class="hljs-built_in">normalize</span>(v + l);</span>
|
||||
<span class="line"><span class="hljs-keyword">void</span> <span class="hljs-title function_">BRDF</span><span class="hljs-params">(...)</span> {</span>
|
||||
<span class="line"> <span class="hljs-type">vec3</span> <span class="hljs-variable">h</span> <span class="hljs-operator">=</span> normalize(v + l);</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"> <span class="hljs-type">float</span> NoV = <span class="hljs-built_in">abs</span>(<span class="hljs-built_in">dot</span>(n, v)) + <span class="hljs-number">1e-5</span>;</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> NoL = <span class="hljs-built_in">clamp</span>(<span class="hljs-built_in">dot</span>(n, l), <span class="hljs-number">0.0</span>, <span class="hljs-number">1.0</span>);</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> NoH = <span class="hljs-built_in">clamp</span>(<span class="hljs-built_in">dot</span>(n, h), <span class="hljs-number">0.0</span>, <span class="hljs-number">1.0</span>);</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> LoH = <span class="hljs-built_in">clamp</span>(<span class="hljs-built_in">dot</span>(l, h), <span class="hljs-number">0.0</span>, <span class="hljs-number">1.0</span>);</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> <span class="hljs-variable">NoV</span> <span class="hljs-operator">=</span> abs(dot(n, v)) + <span class="hljs-number">1e-5</span>;</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> <span class="hljs-variable">NoL</span> <span class="hljs-operator">=</span> clamp(dot(n, l), <span class="hljs-number">0.0</span>, <span class="hljs-number">1.0</span>);</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> <span class="hljs-variable">NoH</span> <span class="hljs-operator">=</span> clamp(dot(n, h), <span class="hljs-number">0.0</span>, <span class="hljs-number">1.0</span>);</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> <span class="hljs-variable">LoH</span> <span class="hljs-operator">=</span> clamp(dot(l, h), <span class="hljs-number">0.0</span>, <span class="hljs-number">1.0</span>);</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"> <span class="hljs-comment">// perceptually linear roughness to roughness (see parameterization)</span></span>
|
||||
<span class="line"> <span class="hljs-type">float</span> roughness = perceptualRoughness * perceptualRoughness;</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> <span class="hljs-variable">roughness</span> <span class="hljs-operator">=</span> perceptualRoughness * perceptualRoughness;</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"> <span class="hljs-type">float</span> D = D_GGX(NoH, roughness);</span>
|
||||
<span class="line"> <span class="hljs-type">vec3</span> F = F_Schlick(LoH, f0);</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> V = V_SmithGGXCorrelated(NoV, NoL, roughness);</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> <span class="hljs-variable">D</span> <span class="hljs-operator">=</span> D_GGX(NoH, roughness);</span>
|
||||
<span class="line"> <span class="hljs-type">vec3</span> <span class="hljs-variable">F</span> <span class="hljs-operator">=</span> F_Schlick(LoH, f0);</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> <span class="hljs-variable">V</span> <span class="hljs-operator">=</span> V_SmithGGXCorrelated(NoV, NoL, roughness);</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"> <span class="hljs-comment">// specular BRDF</span></span>
|
||||
<span class="line"> <span class="hljs-type">vec3</span> Fr = (D * V) * F;</span>
|
||||
<span class="line"> <span class="hljs-type">vec3</span> <span class="hljs-variable">Fr</span> <span class="hljs-operator">=</span> (D * V) * F;</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"> <span class="hljs-comment">// diffuse BRDF</span></span>
|
||||
<span class="line"> <span class="hljs-type">vec3</span> Fd = diffuseColor * Fd_Lambert();</span>
|
||||
<span class="line"> <span class="hljs-type">vec3</span> <span class="hljs-variable">Fd</span> <span class="hljs-operator">=</span> diffuseColor * Fd_Lambert();</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"> <span class="hljs-comment">// apply lighting...</span></span>
|
||||
<span class="line">}</span></code></pre><center><div class="listingcaption tilde"><a class="target" name="listing_glslbrdf"> </a><b style="font-style:normal;">Listing 9:</b> Evaluation of the BRDF in GLSL</div></center>
|
||||
@@ -965,7 +965,7 @@ $$\begin{equation}
|
||||
\end{equation}$$
|
||||
</p><p>
|
||||
<a href="#listing_fnormal">Listing 12</a> shows how \(\fNormal\) is computed for both dielectric and metallic materials. It shows that the color of the specular reflectance is derived from the base color in the metallic case.
|
||||
</p><pre class="listing tilde"><code><span class="line">vec3 f0 = 0.16 <span class="hljs-emphasis">* reflectance *</span> reflectance <span class="hljs-emphasis">* (1.0 - metallic) + baseColor *</span> metallic;</span></code></pre><center><div class="listingcaption tilde"><a class="target" name="listing_fnormal"> </a><b style="font-style:normal;">Listing 12:</b> Computing \(\fNormal\) for dielectric and metallic materials in GLSL</div></center>
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-symbol">vec3</span> <span class="hljs-built_in">f0</span> = <span class="hljs-number">0</span>.<span class="hljs-number">16</span> * reflectance * reflectance * (<span class="hljs-number">1</span>.<span class="hljs-number">0</span> - metallic) + baseColor * metallic<span class="hljs-comment">;</span></span></code></pre><center><div class="listingcaption tilde"><a class="target" name="listing_fnormal"> </a><b style="font-style:normal;">Listing 12:</b> Computing \(\fNormal\) for dielectric and metallic materials in GLSL</div></center>
|
||||
<a class="target" name="roughnessremappingandclamping"> </a><a class="target" name="materialsystem/parameterization/remapping/roughnessremappingandclamping"> </a><a class="target" name="toc4.8.3.3"> </a><h4 id="roughness-remapping-and-clamping"><a class="header" href="#roughness-remapping-and-clamping">Roughness remapping and clamping</a></h4>
|
||||
<p>
|
||||
<p>The roughness set by the user, called <code>perceptualRoughness</code> here, is remapped to a perceptually linear range using the following formulation:</p>
|
||||
@@ -1054,7 +1054,7 @@ V(l,h) = \frac{1}{4(\LoH)^2}
|
||||
This masking-shadowing function is not physically based, as shown in [<a href="#citation-heitz14">Heitz14</a>], but its simplicity makes it desirable for real-time rendering.
|
||||
</p><p>
|
||||
In summary, our clear coat BRDF is a Cook-Torrance specular microfacet model, with a GGX normal distribution function, a Kelemen visibility function, and a Schlick Fresnel function. <a href="#listing_kelemen">Listing 13</a> shows how trivial the GLSL implementation is.
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-function"><span class="hljs-built_in">float</span> <span class="hljs-title">V_Kelemen</span>(<span class="hljs-params"><span class="hljs-built_in">float</span> LoH</span>)</span> {</span>
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-function"><span class="hljs-type">float</span> <span class="hljs-title">V_Kelemen</span><span class="hljs-params">(<span class="hljs-type">float</span> LoH)</span> </span>{</span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> <span class="hljs-number">0.25</span> / (LoH * LoH);</span>
|
||||
<span class="line">}</span></code></pre><center><div class="listingcaption tilde"><a class="target" name="listing_kelemen"> </a><b style="font-style:normal;">Listing 13:</b> Implementation of the Kelemen visibility term in GLSL</div></center>
|
||||
<p>
|
||||
@@ -1097,18 +1097,18 @@ The clear coat roughness parameter is remapped and clamped in a similar way to t
|
||||
<center><div class="image" style=""><a href="../images/material_clear_coat2.png" target="_blank"><img class="markdeep" src="../images/material_clear_coat2.png" /></a><center><span class="imagecaption"><a class="target" name="figure_clearcoatroughness"> </a><b style="font-style:normal;">Figure 26:</b> Clear coat roughness varying from 0.0 (left) to 1.0 (right) with metallic set to 1.0, roughness to 0.8 and clear coat to 1.0</span></center></div></center>
|
||||
</p><p>
|
||||
<a href="#listing_clearcoatbrdf">Listing 14</a> shows the GLSL implementation of the clear coat material model after remapping, parameterization and integration in the standard surface response.
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">BRDF</span>(<span class="hljs-params">...</span>)</span> {</span>
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">BRDF</span><span class="hljs-params">(...)</span> </span>{</span>
|
||||
<span class="line"> <span class="hljs-comment">// compute Fd and Fr from standard model</span></span>
|
||||
<span class="line"></span>
|
||||
<span class="line"> <span class="hljs-comment">// remapping and linearization of clear coat roughness</span></span>
|
||||
<span class="line"> clearCoatPerceptualRoughness = clamp(clearCoatPerceptualRoughness, <span class="hljs-number">0.089</span>, <span class="hljs-number">1.0</span>);</span>
|
||||
<span class="line"> clearCoatPerceptualRoughness = <span class="hljs-built_in">clamp</span>(clearCoatPerceptualRoughness, <span class="hljs-number">0.089</span>, <span class="hljs-number">1.0</span>);</span>
|
||||
<span class="line"> clearCoatRoughness = clearCoatPerceptualRoughness * clearCoatPerceptualRoughness;</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"> <span class="hljs-comment">// clear coat BRDF</span></span>
|
||||
<span class="line"> <span class="hljs-built_in">float</span> Dc = D_GGX(clearCoatRoughness, NoH);</span>
|
||||
<span class="line"> <span class="hljs-built_in">float</span> Vc = V_Kelemen(clearCoatRoughness, LoH);</span>
|
||||
<span class="line"> <span class="hljs-built_in">float</span> Fc = F_Schlick(<span class="hljs-number">0.04</span>, LoH) * clearCoat; <span class="hljs-comment">// clear coat strength</span></span>
|
||||
<span class="line"> <span class="hljs-built_in">float</span> Frc = (Dc * Vc) * Fc;</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> Dc = <span class="hljs-built_in">D_GGX</span>(clearCoatRoughness, NoH);</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> Vc = <span class="hljs-built_in">V_Kelemen</span>(clearCoatRoughness, LoH);</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> Fc = <span class="hljs-built_in">F_Schlick</span>(<span class="hljs-number">0.04</span>, LoH) * clearCoat; <span class="hljs-comment">// clear coat strength</span></span>
|
||||
<span class="line"> <span class="hljs-type">float</span> Frc = (Dc * Vc) * Fc;</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"> <span class="hljs-comment">// account for energy loss in the base layer</span></span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> color * ((Fd + Fr * (<span class="hljs-number">1.0</span> - Fc)) * (<span class="hljs-number">1.0</span> - Fc) + Frc);</span>
|
||||
@@ -1294,14 +1294,14 @@ f_{r}(v,h,\alpha) = \frac{D_{velvet}(v,h,\alpha)}{4(\NoL + \NoV - (\NoL)(\NoV))}
|
||||
\end{equation}$$
|
||||
</p><p>
|
||||
The implementation of the velvet NDF is presented in <a href="#listing_clothbrdf">listing 17</a>, optimized to properly fit in half float formats and to avoid computing a costly cotangent, relying instead on trigonometric identities. Note that we removed the Fresnel component from this BRDF.
|
||||
</p><pre class="listing tilde"><code><span class="line">float D_Ashikhmin(float roughness, float NoH) {</span>
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-function"><span class="hljs-type">float</span> <span class="hljs-title">D_Ashikhmin</span><span class="hljs-params">(<span class="hljs-type">float</span> roughness, <span class="hljs-type">float</span> NoH)</span> </span>{</span>
|
||||
<span class="line"> <span class="hljs-comment">// Ashikhmin 2007, "Distribution-based BRDFs"</span></span>
|
||||
<span class="line"> float a<span class="hljs-number">2</span> = roughness * roughness;</span>
|
||||
<span class="line"> float <span class="hljs-keyword">cos</span><span class="hljs-number">2</span>h = NoH * NoH;</span>
|
||||
<span class="line"> float <span class="hljs-keyword">sin</span><span class="hljs-number">2</span>h = <span class="hljs-keyword">max</span>(<span class="hljs-number">1.0</span> - <span class="hljs-keyword">cos</span><span class="hljs-number">2</span>h, <span class="hljs-number">0.0078125</span>); <span class="hljs-comment">// 2^(-14/2), so sin2h^2 > 0 in fp16</span></span>
|
||||
<span class="line"> float <span class="hljs-keyword">sin</span><span class="hljs-number">4</span>h = <span class="hljs-keyword">sin</span><span class="hljs-number">2</span>h * <span class="hljs-keyword">sin</span><span class="hljs-number">2</span>h;</span>
|
||||
<span class="line"> float cot<span class="hljs-number">2</span> = -<span class="hljs-keyword">cos</span><span class="hljs-number">2</span>h / (a<span class="hljs-number">2</span> * <span class="hljs-keyword">sin</span><span class="hljs-number">2</span>h);</span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> <span class="hljs-number">1.0</span> / (PI * (<span class="hljs-number">4.0</span> * a<span class="hljs-number">2</span> + <span class="hljs-number">1.0</span>) * <span class="hljs-keyword">sin</span><span class="hljs-number">4</span>h) * (<span class="hljs-number">4.0</span> * exp(cot<span class="hljs-number">2</span>) + <span class="hljs-keyword">sin</span><span class="hljs-number">4</span>h);</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> a2 = roughness * roughness;</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> cos2h = NoH * NoH;</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> sin2h = <span class="hljs-built_in">max</span>(<span class="hljs-number">1.0</span> - cos2h, <span class="hljs-number">0.0078125</span>); <span class="hljs-comment">// 2^(-14/2), so sin2h^2 > 0 in fp16</span></span>
|
||||
<span class="line"> <span class="hljs-type">float</span> sin4h = sin2h * sin2h;</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> cot2 = -cos2h / (a2 * sin2h);</span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> <span class="hljs-number">1.0</span> / (PI * (<span class="hljs-number">4.0</span> * a2 + <span class="hljs-number">1.0</span>) * sin4h) * (<span class="hljs-number">4.0</span> * <span class="hljs-built_in">exp</span>(cot2) + sin4h);</span>
|
||||
<span class="line">}</span></code></pre><center><div class="listingcaption tilde"><a class="target" name="listing_clothbrdf"> </a><b style="font-style:normal;">Listing 17:</b> Implementation of Ashikhmin's velvet NDF in GLSL</div></center>
|
||||
<p>
|
||||
<p>In [<a href="#citation-estevez17">Estevez17</a>] Estevez and Kulla propose a different NDF (called the “Charlie” sheen) that is based on an exponentiated sinusoidal instead of an inverted Gaussian. This NDF is appealing for several reasons: its parameterization feels more natural and intuitive, it provides a softer appearance and, as shown in equation (\ref{charlieNDF}), its implementation is simpler:</p>
|
||||
@@ -1312,11 +1312,11 @@ D(m) = \frac{(2 + \frac{1}{\alpha}) sin(\theta)^{\frac{1}{\alpha}}}{2 \pi}
|
||||
</p><p>
|
||||
[<a href="#citation-estevez17">Estevez17</a>] also presents a new shadowing term that we omit here because of its cost. We instead rely on the visibility term from [<a href="#citation-neubelt13">Neubelt13</a>] (shown in equation \(\ref{clothSpecularBRDF}\) above).
|
||||
The implementation of this NDF is presented in <a href="#listing_clothcharliebrdf">listing 18</a>, optimized to properly fit in half float formats.
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-function"><span class="hljs-keyword">float</span> <span class="hljs-title">D_Charlie</span><span class="hljs-params">(<span class="hljs-keyword">float</span> roughness, <span class="hljs-keyword">float</span> NoH)</span> </span>{</span>
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-function"><span class="hljs-type">float</span> <span class="hljs-title">D_Charlie</span><span class="hljs-params">(<span class="hljs-type">float</span> roughness, <span class="hljs-type">float</span> NoH)</span> </span>{</span>
|
||||
<span class="line"> <span class="hljs-comment">// Estevez and Kulla 2017, "Production Friendly Microfacet Sheen BRDF"</span></span>
|
||||
<span class="line"> <span class="hljs-keyword">float</span> invAlpha = <span class="hljs-number">1.0</span> / roughness;</span>
|
||||
<span class="line"> <span class="hljs-keyword">float</span> cos2h = NoH * NoH;</span>
|
||||
<span class="line"> <span class="hljs-keyword">float</span> sin2h = max(<span class="hljs-number">1.0</span> - cos2h, <span class="hljs-number">0.0078125</span>); <span class="hljs-comment">// 2^(-14/2), so sin2h^2 > 0 in fp16</span></span>
|
||||
<span class="line"> <span class="hljs-type">float</span> invAlpha = <span class="hljs-number">1.0</span> / roughness;</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> cos2h = NoH * NoH;</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> sin2h = <span class="hljs-built_in">max</span>(<span class="hljs-number">1.0</span> - cos2h, <span class="hljs-number">0.0078125</span>); <span class="hljs-comment">// 2^(-14/2), so sin2h^2 > 0 in fp16</span></span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> (<span class="hljs-number">2.0</span> + invAlpha) * <span class="hljs-built_in">pow</span>(sin2h, invAlpha * <span class="hljs-number">0.5</span>) / (<span class="hljs-number">2.0</span> * PI);</span>
|
||||
<span class="line">}</span></code></pre><center><div class="listingcaption tilde"><a class="target" name="listing_clothcharliebrdf"> </a><b style="font-style:normal;">Listing 18:</b> Implementation of the “Charlie” NDF in GLSL</div></center>
|
||||
<a class="target" name="sheencolor"> </a><a class="target" name="materialsystem/clothmodel/clothspecularbrdf/sheencolor"> </a><a class="target" name="toc4.12.1.1"> </a><h4 id="sheen-color"><a class="header" href="#sheen-color">Sheen color</a></h4>
|
||||
@@ -1745,21 +1745,21 @@ The photometric attenuation function can be easily implemented in GLSL by adding
|
||||
<span class="line">}</span></code></pre><center><div class="listingcaption tilde"><a class="target" name="listing_glslphotometricpunctuallight"> </a><b style="font-style:normal;">Listing 22:</b> Implementation of attenuation from photometric profiles in GLSL</div></center>
|
||||
<p>
|
||||
<p>The light intensity is computed CPU-side (<a href="#listing_photometriclightintensity">listing 23</a>) and depends on whether the photometric profile is used as a mask.</p>
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-keyword">float</span> multiplier;</span>
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-type">float</span> multiplier;</span>
|
||||
<span class="line"><span class="hljs-comment">// Photometric profile used as a mask</span></span>
|
||||
<span class="line"><span class="hljs-keyword">if</span> (photometricLight.isMasked()) {</span>
|
||||
<span class="line"><span class="hljs-keyword">if</span> (photometricLight.<span class="hljs-built_in">isMasked</span>()) {</span>
|
||||
<span class="line"> <span class="hljs-comment">// The desired intensity is set by the artist</span></span>
|
||||
<span class="line"> <span class="hljs-comment">// The integrated intensity comes from a Monte-Carlo</span></span>
|
||||
<span class="line"> <span class="hljs-comment">// integration over the unit sphere around the luminaire</span></span>
|
||||
<span class="line"> multiplier = photometricLight.getDesiredIntensity() /</span>
|
||||
<span class="line"> photometricLight.getIntegratedIntensity();</span>
|
||||
<span class="line"> multiplier = photometricLight.<span class="hljs-built_in">getDesiredIntensity</span>() /</span>
|
||||
<span class="line"> photometricLight.<span class="hljs-built_in">getIntegratedIntensity</span>();</span>
|
||||
<span class="line">} <span class="hljs-keyword">else</span> {</span>
|
||||
<span class="line"> <span class="hljs-comment">// Multiplier provided for convenience, set to 1.0 by default</span></span>
|
||||
<span class="line"> multiplier = photometricLight.getMultiplier();</span>
|
||||
<span class="line"> multiplier = photometricLight.<span class="hljs-built_in">getMultiplier</span>();</span>
|
||||
<span class="line">}</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"><span class="hljs-comment">// The max intensity in cd comes from the IES profile</span></span>
|
||||
<span class="line"><span class="hljs-keyword">float</span> lightIntensity = photometricLight.getMaxIntensity() * multiplier;</span></code></pre><center><div class="listingcaption tilde"><a class="target" name="listing_photometriclightintensity"> </a><b style="font-style:normal;">Listing 23:</b> Computing the intensity of a photometric light on the CPU</div></center>
|
||||
<span class="line"><span class="hljs-type">float</span> lightIntensity = photometricLight.<span class="hljs-built_in">getMaxIntensity</span>() * multiplier;</span></code></pre><center><div class="listingcaption tilde"><a class="target" name="listing_photometriclightintensity"> </a><b style="font-style:normal;">Listing 23:</b> Computing the intensity of a photometric light on the CPU</div></center>
|
||||
<p>
|
||||
<div class="endnote"><a class="target" name="endnote-xarrowintensity"> </a><sup>4</sup> The XArrow profile declares a luminous intensity of 1,750 lm but a Monte-Carlo integration shows an intensity of only 350 lm.
|
||||
</div>
|
||||
@@ -2058,19 +2058,19 @@ In practice only 4 or 9 coefficients (i.e.: 2 or 3 bands) are enough for \(\cosT
|
||||
<center><div class="image" style=""><a href="../images/ibl/ibl_irradiance_sh2.png" target="_blank"><img class="markdeep" src="../images/ibl/ibl_irradiance_sh2.png" style="max-width:100%;" /></a><center><span class="imagecaption"><a class="target" name="figure_iblsh2"> </a><b style="font-style:normal;">Figure 52:</b> 2 bands (4 coefficients)</span></center></div></center>
|
||||
</p><p>
|
||||
In practice we pre-convolve \(\Lt\) with \(\cosTheta\) and pre-scale these coefficients by the basis scaling factors \(K_l^m\) so that the reconstruction code is as simple as possible in the shader:
|
||||
</p><pre class="listing tilde"><code><span class="line">vec3 <span class="hljs-function"><span class="hljs-title">irradianceSH</span>(<span class="hljs-params">vec3 n</span>)</span> {</span>
|
||||
<span class="line"> <span class="hljs-comment">// uniform vec3 sphericalHarmonics[9]</span></span>
|
||||
<span class="line"> <span class="hljs-comment">// We can use only the first 2 bands for better performance</span></span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span></span>
|
||||
<span class="line"> sphericalHarmonics[<span class="hljs-number">0</span>]</span>
|
||||
<span class="line"> + sphericalHarmonics[<span class="hljs-number">1</span>] * (n.y)</span>
|
||||
<span class="line"> + sphericalHarmonics[<span class="hljs-number">2</span>] * (n.z)</span>
|
||||
<span class="line"> + sphericalHarmonics[<span class="hljs-number">3</span>] * (n.x)</span>
|
||||
<span class="line"> + sphericalHarmonics[<span class="hljs-number">4</span>] * (n.y * n.x)</span>
|
||||
<span class="line"> + sphericalHarmonics[<span class="hljs-number">5</span>] * (n.y * n.z)</span>
|
||||
<span class="line"> + sphericalHarmonics[<span class="hljs-number">6</span>] * (<span class="hljs-number">3.0</span> * n.z * n.z - <span class="hljs-number">1.0</span>)</span>
|
||||
<span class="line"> + sphericalHarmonics[<span class="hljs-number">7</span>] * (n.z * n.x)</span>
|
||||
<span class="line"> + sphericalHarmonics[<span class="hljs-number">8</span>] * (n.x * n.x - n.y * n.y);</span>
|
||||
</p><pre class="listing tilde"><code><span class="line">vec3 irradianceSH(vec3 n) {</span>
|
||||
<span class="line"> // uniform vec3 sphericalHarmonics<span class="hljs-selector-attr">[9]</span></span>
|
||||
<span class="line"> // We can <span class="hljs-selector-tag">use</span> only the first <span class="hljs-number">2</span> bands for better performance</span>
|
||||
<span class="line"> return</span>
|
||||
<span class="line"> sphericalHarmonics<span class="hljs-selector-attr">[0]</span></span>
|
||||
<span class="line"> + sphericalHarmonics<span class="hljs-selector-attr">[1]</span> * (n<span class="hljs-selector-class">.y</span>)</span>
|
||||
<span class="line"> + sphericalHarmonics<span class="hljs-selector-attr">[2]</span> * (n<span class="hljs-selector-class">.z</span>)</span>
|
||||
<span class="line"> + sphericalHarmonics<span class="hljs-selector-attr">[3]</span> * (n<span class="hljs-selector-class">.x</span>)</span>
|
||||
<span class="line"> + sphericalHarmonics<span class="hljs-selector-attr">[4]</span> * (n<span class="hljs-selector-class">.y</span> * n<span class="hljs-selector-class">.x</span>)</span>
|
||||
<span class="line"> + sphericalHarmonics<span class="hljs-selector-attr">[5]</span> * (n<span class="hljs-selector-class">.y</span> * n<span class="hljs-selector-class">.z</span>)</span>
|
||||
<span class="line"> + sphericalHarmonics<span class="hljs-selector-attr">[6]</span> * (<span class="hljs-number">3.0</span> * n<span class="hljs-selector-class">.z</span> * n<span class="hljs-selector-class">.z</span> - <span class="hljs-number">1.0</span>)</span>
|
||||
<span class="line"> + sphericalHarmonics<span class="hljs-selector-attr">[7]</span> * (n<span class="hljs-selector-class">.z</span> * n<span class="hljs-selector-class">.x</span>)</span>
|
||||
<span class="line"> + sphericalHarmonics<span class="hljs-selector-attr">[8]</span> * (n<span class="hljs-selector-class">.x</span> * n<span class="hljs-selector-class">.x</span> - n<span class="hljs-selector-class">.y</span> * n<span class="hljs-selector-class">.y</span>);</span>
|
||||
<span class="line">}</span></code></pre><center><div class="listingcaption tilde"><a class="target" name="listing_irradiancesh"> </a><b style="font-style:normal;">Listing 26:</b> GLSL code to reconstruct the irradiance from the pre-scaled SH</div></center>
|
||||
<p>
|
||||
<p>Note that with 2 bands, the computation above becomes a single (4 \times 4) matrix-by-vector multiply.</p>
|
||||
@@ -2443,7 +2443,7 @@ LD(n, \alpha) &= \frac{\sum_i^N V(l_i, n,
|
||||
$$
|
||||
</p><p>
|
||||
These two new \(DFG\) terms simply need to replace the ones used in the implementation shown in section <a href="#toc9.5">9.5</a>:
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-keyword">float</span> Fc = <span class="hljs-built_in">pow</span>(<span class="hljs-number">1</span> - VoH, <span class="hljs-number">5.0f</span>);</span>
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-type">float</span> Fc = <span class="hljs-built_in">pow</span>(<span class="hljs-number">1</span> - VoH, <span class="hljs-number">5.0f</span>);</span>
|
||||
<span class="line">r.x += Gv * Fc;</span>
|
||||
<span class="line">r.y += Gv;</span></code></pre><center><div class="listingcaption tilde"><a class="target" name="listing_multiscatteriblpreintegration"> </a><b style="font-style:normal;">Listing 29:</b> C++ implementation of the \(L_{DFG}\) term for multiscattering</div></center>
|
||||
<p>
|
||||
@@ -2507,11 +2507,11 @@ using an environment made of colored vertical stripes (skybox hidden).</span></c
|
||||
<p>
|
||||
<p>When sampling the IBL, the clear coat layer is calculated as a second specular lobe. This specular lobe is oriented along the view direction since we cannot reasonably integrate over the hemisphere. <a href="#listing_clearcoatibl">Listing 31</a> demonstrates this approximation in practice. It also shows the energy conservation step. It is important to note that this second specular lobe is computed exactly the same way as the main specular lobe, using the same DFG approximation.</p>
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-comment">// clearCoat_NoV == shading_NoV if the clear coat layer doesn't have its own normal map</span></span>
|
||||
<span class="line"><span class="hljs-built_in">float</span> Fc = F_Schlick(<span class="hljs-number">0.04</span>, <span class="hljs-number">1.0</span>, clearCoat_NoV) * clearCoat;</span>
|
||||
<span class="line"><span class="hljs-type">float</span> Fc = <span class="hljs-built_in">F_Schlick</span>(<span class="hljs-number">0.04</span>, <span class="hljs-number">1.0</span>, clearCoat_NoV) * clearCoat;</span>
|
||||
<span class="line"><span class="hljs-comment">// base layer attenuation for energy compensation</span></span>
|
||||
<span class="line">iblDiffuse *= <span class="hljs-number">1.0</span> - Fc;</span>
|
||||
<span class="line">iblSpecular *= sq(<span class="hljs-number">1.0</span> - Fc);</span>
|
||||
<span class="line">iblSpecular += specularIBL(r, clearCoatPerceptualRoughness) * Fc;</span></code></pre><center><div class="listingcaption tilde"><a class="target" name="listing_clearcoatibl"> </a><b style="font-style:normal;">Listing 31:</b> GLSL implementation of the clear coat specular lobe for image-based lighting</div></center>
|
||||
<span class="line">iblSpecular *= <span class="hljs-built_in">sq</span>(<span class="hljs-number">1.0</span> - Fc);</span>
|
||||
<span class="line">iblSpecular += <span class="hljs-built_in">specularIBL</span>(r, clearCoatPerceptualRoughness) * Fc;</span></code></pre><center><div class="listingcaption tilde"><a class="target" name="listing_clearcoatibl"> </a><b style="font-style:normal;">Listing 31:</b> GLSL implementation of the clear coat specular lobe for image-based lighting</div></center>
|
||||
<a class="target" name="anisotropy"> </a><a class="target" name="lighting/imagebasedlights/anisotropy"> </a><a class="target" name="toc5.3.6"> </a><h3 id="anisotropy"><a class="header" href="#anisotropy">Anisotropy </a></h3>
|
||||
<p>
|
||||
<p>[<a href="#citation-mcauley15">McAuley15</a>] describes a technique called “bent reflection vector”, based [<a href="#citation-revie12">Revie12</a>]. The bent reflection vector is a rough approximation of anisotropic lighting but the alternative is to use importance sampling. This approximation is sufficiently cheap to compute and provides good results, as shown in <a href="#figure_anisotropicibl1">figure 59</a> and <a href="#figure_anisotropicibl2">figure 60</a>.</p>
|
||||
@@ -2550,17 +2550,17 @@ The DG term is generated using uniform sampling as recommended in [<a href="#cit
|
||||
<center><div class="image" style=""><a href="../images/ibl/dfg_cloth.png" target="_blank"><img class="markdeep" src="../images/ibl/dfg_cloth.png" /></a><center><span class="imagecaption"><a class="target" name="figure_dfgclothlut"> </a><b style="font-style:normal;">Figure 62:</b> DFG LUT with a 3rd channel encoding the DG term of the cloth BRDF</span></center></div></center>
|
||||
</p><p>
|
||||
The remainder of the image-based lighting implementation follows the same steps as the implementation of regular lights, including the optional subsurface scattering term and its wrap diffuse component. Just as with the clear coat IBL implementation, we cannot integrate over the hemisphere and use the view direction as the dominant light direction to compute the wrap diffuse component.
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-built_in">float</span> diffuse = Fd_Lambert() * ambientOcclusion;</span>
|
||||
<span class="line"><span class="hljs-meta">#<span class="hljs-meta-keyword">if</span> defined(SHADING_MODEL_CLOTH)</span></span>
|
||||
<span class="line"><span class="hljs-meta">#<span class="hljs-meta-keyword">if</span> defined(MATERIAL_HAS_SUBSURFACE_COLOR)</span></span>
|
||||
<span class="line">diffuse *= saturate((NoV + <span class="hljs-number">0.5</span>) / <span class="hljs-number">2.25</span>);</span>
|
||||
<span class="line"><span class="hljs-meta">#<span class="hljs-meta-keyword">endif</span></span></span>
|
||||
<span class="line"><span class="hljs-meta">#<span class="hljs-meta-keyword">endif</span></span></span>
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-type">float</span> diffuse = <span class="hljs-built_in">Fd_Lambert</span>() * ambientOcclusion;</span>
|
||||
<span class="line"><span class="hljs-meta">#<span class="hljs-keyword">if</span> defined(SHADING_MODEL_CLOTH)</span></span>
|
||||
<span class="line"><span class="hljs-meta">#<span class="hljs-keyword">if</span> defined(MATERIAL_HAS_SUBSURFACE_COLOR)</span></span>
|
||||
<span class="line">diffuse *= <span class="hljs-built_in">saturate</span>((NoV + <span class="hljs-number">0.5</span>) / <span class="hljs-number">2.25</span>);</span>
|
||||
<span class="line"><span class="hljs-meta">#<span class="hljs-keyword">endif</span></span></span>
|
||||
<span class="line"><span class="hljs-meta">#<span class="hljs-keyword">endif</span></span></span>
|
||||
<span class="line"></span>
|
||||
<span class="line">vec3 indirectDiffuse = irradianceIBL(n) * diffuse;</span>
|
||||
<span class="line"><span class="hljs-meta">#<span class="hljs-meta-keyword">if</span> defined(SHADING_MODEL_CLOTH) && defined(MATERIAL_HAS_SUBSURFACE_COLOR)</span></span>
|
||||
<span class="line">indirectDiffuse *= saturate(subsurfaceColor + NoV);</span>
|
||||
<span class="line"><span class="hljs-meta">#<span class="hljs-meta-keyword">endif</span></span></span>
|
||||
<span class="line">vec3 indirectDiffuse = <span class="hljs-built_in">irradianceIBL</span>(n) * diffuse;</span>
|
||||
<span class="line"><span class="hljs-meta">#<span class="hljs-keyword">if</span> defined(SHADING_MODEL_CLOTH) && defined(MATERIAL_HAS_SUBSURFACE_COLOR)</span></span>
|
||||
<span class="line">indirectDiffuse *= <span class="hljs-built_in">saturate</span>(subsurfaceColor + NoV);</span>
|
||||
<span class="line"><span class="hljs-meta">#<span class="hljs-keyword">endif</span></span></span>
|
||||
<span class="line"></span>
|
||||
<span class="line">vec3 ibl = diffuseColor * indirectDiffuse + indirectSpecular * specularColor;</span></code></pre><center><div class="listingcaption tilde"><a class="target" name="listing_clothapprox"> </a><b style="font-style:normal;">Listing 34:</b> GLSL implementation of the DFG approximation for the cloth NDF</div></center>
|
||||
<p>
|
||||
@@ -2982,20 +2982,20 @@ L_{max} &= 2^{EV_{100}} \times 1.2
|
||||
<span class="line"><span class="hljs-comment">// aperture in f-stops</span></span>
|
||||
<span class="line"><span class="hljs-comment">// shutterSpeed in seconds</span></span>
|
||||
<span class="line"><span class="hljs-comment">// sensitivity in ISO</span></span>
|
||||
<span class="line"><span class="hljs-function"><span class="hljs-keyword">float</span> <span class="hljs-title">exposureSettings</span><span class="hljs-params">(<span class="hljs-keyword">float</span> aperture, <span class="hljs-keyword">float</span> shutterSpeed, <span class="hljs-keyword">float</span> sensitivity)</span> </span>{</span>
|
||||
<span class="line"><span class="hljs-type">float</span> <span class="hljs-title function_">exposureSettings</span><span class="hljs-params">(<span class="hljs-type">float</span> aperture, <span class="hljs-type">float</span> shutterSpeed, <span class="hljs-type">float</span> sensitivity)</span> {</span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> log2((aperture * aperture) / shutterSpeed * <span class="hljs-number">100.0</span> / sensitivity);</span>
|
||||
<span class="line">}</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"><span class="hljs-comment">// Computes the exposure normalization factor from</span></span>
|
||||
<span class="line"><span class="hljs-comment">// the camera's EV100</span></span>
|
||||
<span class="line"><span class="hljs-function"><span class="hljs-keyword">float</span> <span class="hljs-title">exposure</span><span class="hljs-params">(<span class="hljs-keyword">float</span> ev100)</span> </span>{</span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> <span class="hljs-number">1.0</span> / (<span class="hljs-built_in">pow</span>(<span class="hljs-number">2.0</span>, ev100) * <span class="hljs-number">1.2</span>);</span>
|
||||
<span class="line"><span class="hljs-type">float</span> <span class="hljs-title function_">exposure</span><span class="hljs-params">(<span class="hljs-type">float</span> ev100)</span> {</span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> <span class="hljs-number">1.0</span> / (pow(<span class="hljs-number">2.0</span>, ev100) * <span class="hljs-number">1.2</span>);</span>
|
||||
<span class="line">}</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"><span class="hljs-keyword">float</span> ev100 = exposureSettings(aperture, shutterSpeed, sensitivity);</span>
|
||||
<span class="line"><span class="hljs-keyword">float</span> exposure = exposure(ev100);</span>
|
||||
<span class="line"><span class="hljs-type">float</span> <span class="hljs-variable">ev100</span> <span class="hljs-operator">=</span> exposureSettings(aperture, shutterSpeed, sensitivity);</span>
|
||||
<span class="line"><span class="hljs-type">float</span> <span class="hljs-variable">exposure</span> <span class="hljs-operator">=</span> exposure(ev100);</span>
|
||||
<span class="line"></span>
|
||||
<span class="line">vec4 color = evaluateLighting();</span>
|
||||
<span class="line"><span class="hljs-type">vec4</span> <span class="hljs-variable">color</span> <span class="hljs-operator">=</span> evaluateLighting();</span>
|
||||
<span class="line">color.rgb *= exposure;</span></code></pre><center><div class="listingcaption tilde"><a class="target" name="listing_fragmentexposure"> </a><b style="font-style:normal;">Listing 42:</b> Implementation of exposure in GLSL</div></center>
|
||||
<p>
|
||||
<p>In practice the exposure factor can be pre-computed on the CPU to save shader instructions.</p>
|
||||
@@ -3466,9 +3466,9 @@ Our implementation is presented in <a href="#listing_specularcolorimpl">listing&
|
||||
<span class="line"><span class="hljs-comment">// Data source:</span></span>
|
||||
<span class="line"><span class="hljs-comment">// http://cvrl.ioo.ucl.ac.uk/cmfs.htm</span></span>
|
||||
<span class="line"><span class="hljs-comment">// http://cvrl.ioo.ucl.ac.uk/database/text/cmfs/ciexyz31.htm</span></span>
|
||||
<span class="line"><span class="hljs-keyword">const</span> <span class="hljs-keyword">size_t</span> CIE_XYZ_START = <span class="hljs-number">360</span>;</span>
|
||||
<span class="line"><span class="hljs-keyword">const</span> <span class="hljs-keyword">size_t</span> CIE_XYZ_COUNT = <span class="hljs-number">471</span>;</span>
|
||||
<span class="line"><span class="hljs-keyword">const</span> float3 CIE_XYZ[CIE_XYZ_COUNT] = { ... };</span>
|
||||
<span class="line"><span class="hljs-type">const</span> <span class="hljs-type">size_t</span> CIE_XYZ_START = <span class="hljs-number">360</span>;</span>
|
||||
<span class="line"><span class="hljs-type">const</span> <span class="hljs-type">size_t</span> CIE_XYZ_COUNT = <span class="hljs-number">471</span>;</span>
|
||||
<span class="line"><span class="hljs-type">const</span> float3 CIE_XYZ[CIE_XYZ_COUNT] = { ... };</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"><span class="hljs-comment">// CIE Standard Illuminant D65 relative spectral power distribution,</span></span>
|
||||
<span class="line"><span class="hljs-comment">// from 300nm to 830, at 5nm intervals</span></span>
|
||||
@@ -3476,51 +3476,51 @@ Our implementation is presented in <a href="#listing_specularcolorimpl">listing&
|
||||
<span class="line"><span class="hljs-comment">// Data source:</span></span>
|
||||
<span class="line"><span class="hljs-comment">// https://en.wikipedia.org/wiki/Illuminant_D65</span></span>
|
||||
<span class="line"><span class="hljs-comment">// https://cielab.xyz/pdf/CIE_sel_colorimetric_tables.xls</span></span>
|
||||
<span class="line"><span class="hljs-keyword">const</span> <span class="hljs-keyword">size_t</span> CIE_D65_INTERVAL = <span class="hljs-number">5</span>;</span>
|
||||
<span class="line"><span class="hljs-keyword">const</span> <span class="hljs-keyword">size_t</span> CIE_D65_START = <span class="hljs-number">300</span>;</span>
|
||||
<span class="line"><span class="hljs-keyword">const</span> <span class="hljs-keyword">size_t</span> CIE_D65_END = <span class="hljs-number">830</span>;</span>
|
||||
<span class="line"><span class="hljs-keyword">const</span> <span class="hljs-keyword">size_t</span> CIE_D65_COUNT = <span class="hljs-number">107</span>;</span>
|
||||
<span class="line"><span class="hljs-keyword">const</span> <span class="hljs-keyword">float</span> CIE_D65[CIE_D65_COUNT] = { ... };</span>
|
||||
<span class="line"><span class="hljs-type">const</span> <span class="hljs-type">size_t</span> CIE_D65_INTERVAL = <span class="hljs-number">5</span>;</span>
|
||||
<span class="line"><span class="hljs-type">const</span> <span class="hljs-type">size_t</span> CIE_D65_START = <span class="hljs-number">300</span>;</span>
|
||||
<span class="line"><span class="hljs-type">const</span> <span class="hljs-type">size_t</span> CIE_D65_END = <span class="hljs-number">830</span>;</span>
|
||||
<span class="line"><span class="hljs-type">const</span> <span class="hljs-type">size_t</span> CIE_D65_COUNT = <span class="hljs-number">107</span>;</span>
|
||||
<span class="line"><span class="hljs-type">const</span> <span class="hljs-type">float</span> CIE_D65[CIE_D65_COUNT] = { ... };</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Sample</span> {</span></span>
|
||||
<span class="line"> <span class="hljs-keyword">float</span> w = <span class="hljs-number">0.0f</span>; <span class="hljs-comment">// wavelength</span></span>
|
||||
<span class="line"> <span class="hljs-built_in">std</span>::<span class="hljs-built_in">complex</span><<span class="hljs-keyword">float</span>> ior; <span class="hljs-comment">// complex IOR, n + ik</span></span>
|
||||
<span class="line"><span class="hljs-keyword">struct</span> <span class="hljs-title class_">Sample</span> {</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> w = <span class="hljs-number">0.0f</span>; <span class="hljs-comment">// wavelength</span></span>
|
||||
<span class="line"> std::complex<<span class="hljs-type">float</span>> ior; <span class="hljs-comment">// complex IOR, n + ik</span></span>
|
||||
<span class="line">};</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"><span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">float</span> <span class="hljs-title">illuminantD65</span><span class="hljs-params">(<span class="hljs-keyword">float</span> w)</span> </span>{</span>
|
||||
<span class="line"> <span class="hljs-keyword">auto</span> i0 = <span class="hljs-keyword">size_t</span>((w - CIE_D65_START) / CIE_D65_INTERVAL);</span>
|
||||
<span class="line"> uint2 indexBounds{i0, <span class="hljs-built_in">std</span>::min(i0 + <span class="hljs-number">1</span>, CIE_D65_END)};</span>
|
||||
<span class="line"><span class="hljs-function"><span class="hljs-type">static</span> <span class="hljs-type">float</span> <span class="hljs-title">illuminantD65</span><span class="hljs-params">(<span class="hljs-type">float</span> w)</span> </span>{</span>
|
||||
<span class="line"> <span class="hljs-keyword">auto</span> i0 = <span class="hljs-built_in">size_t</span>((w - CIE_D65_START) / CIE_D65_INTERVAL);</span>
|
||||
<span class="line"> uint2 indexBounds{i0, std::<span class="hljs-built_in">min</span>(i0 + <span class="hljs-number">1</span>, CIE_D65_END)};</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"> float2 wavelengthBounds = CIE_D65_START + float2{indexBounds} * CIE_D65_INTERVAL;</span>
|
||||
<span class="line"> <span class="hljs-keyword">float</span> t = (w - wavelengthBounds.x) / (wavelengthBounds.y - wavelengthBounds.x);</span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> lerp(CIE_D65[indexBounds.x], CIE_D65[indexBounds.y], t);</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> t = (w - wavelengthBounds.x) / (wavelengthBounds.y - wavelengthBounds.x);</span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> <span class="hljs-built_in">lerp</span>(CIE_D65[indexBounds.x], CIE_D65[indexBounds.y], t);</span>
|
||||
<span class="line">}</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"><span class="hljs-comment">// For std::lower_bound</span></span>
|
||||
<span class="line"><span class="hljs-keyword">bool</span> <span class="hljs-keyword">operator</span><(<span class="hljs-keyword">const</span> Sample& lhs, <span class="hljs-keyword">const</span> Sample& rhs) {</span>
|
||||
<span class="line"><span class="hljs-type">bool</span> <span class="hljs-keyword">operator</span><(<span class="hljs-type">const</span> Sample& lhs, <span class="hljs-type">const</span> Sample& rhs) {</span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> lhs.w < rhs.w;</span>
|
||||
<span class="line">}</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"><span class="hljs-comment">// The wavelength w must be between 360nm and 830nm</span></span>
|
||||
<span class="line"><span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-built_in">std</span>::<span class="hljs-built_in">complex</span><<span class="hljs-keyword">float</span>> <span class="hljs-title">findSample</span><span class="hljs-params">(<span class="hljs-keyword">const</span> <span class="hljs-built_in">std</span>::<span class="hljs-built_in">vector</span><sample>& samples, <span class="hljs-keyword">float</span> w)</span> </span>{</span>
|
||||
<span class="line"> <span class="hljs-keyword">auto</span> i1 = <span class="hljs-built_in">std</span>::lower_bound(</span>
|
||||
<span class="line"> samples.begin(), samples.end(), Sample{w, <span class="hljs-number">0.0f</span> + <span class="hljs-number">0.0</span><span class="hljs-keyword">if</span>});</span>
|
||||
<span class="line"><span class="hljs-function"><span class="hljs-type">static</span> std::complex<<span class="hljs-type">float</span>> <span class="hljs-title">findSample</span><span class="hljs-params">(<span class="hljs-type">const</span> std::vector<sample>& samples, <span class="hljs-type">float</span> w)</span> </span>{</span>
|
||||
<span class="line"> <span class="hljs-keyword">auto</span> i1 = std::<span class="hljs-built_in">lower_bound</span>(</span>
|
||||
<span class="line"> samples.<span class="hljs-built_in">begin</span>(), samples.<span class="hljs-built_in">end</span>(), Sample{w, <span class="hljs-number">0.0f</span> + <span class="hljs-number">0.0</span><span class="hljs-keyword">if</span>});</span>
|
||||
<span class="line"> <span class="hljs-keyword">auto</span> i0 = i1 - <span class="hljs-number">1</span>;</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"> <span class="hljs-comment">// Interpolate the complex IORs</span></span>
|
||||
<span class="line"> <span class="hljs-keyword">float</span> t = (w - i0->w) / (i1->w - i0->w);</span>
|
||||
<span class="line"> <span class="hljs-keyword">float</span> n = lerp(i0->ior.real(), i1->ior.real(), t);</span>
|
||||
<span class="line"> <span class="hljs-keyword">float</span> k = lerp(i0->ior.imag(), i1->ior.imag(), t);</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> t = (w - i0->w) / (i1->w - i0->w);</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> n = <span class="hljs-built_in">lerp</span>(i0->ior.<span class="hljs-built_in">real</span>(), i1->ior.<span class="hljs-built_in">real</span>(), t);</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> k = <span class="hljs-built_in">lerp</span>(i0->ior.<span class="hljs-built_in">imag</span>(), i1->ior.<span class="hljs-built_in">imag</span>(), t);</span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> { n, k };</span>
|
||||
<span class="line">}</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"><span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">float</span> <span class="hljs-title">fresnel</span><span class="hljs-params">(<span class="hljs-keyword">const</span> <span class="hljs-built_in">std</span>::<span class="hljs-built_in">complex</span><<span class="hljs-keyword">float</span>>& sample)</span> </span>{</span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> (((sample - (<span class="hljs-number">1.0f</span> + <span class="hljs-number">0</span><span class="hljs-keyword">if</span>)) * (<span class="hljs-built_in">std</span>::conj(sample) - (<span class="hljs-number">1.0f</span> + <span class="hljs-number">0</span><span class="hljs-keyword">if</span>))) /</span>
|
||||
<span class="line"> ((sample + (<span class="hljs-number">1.0f</span> + <span class="hljs-number">0</span><span class="hljs-keyword">if</span>)) * (<span class="hljs-built_in">std</span>::conj(sample) + (<span class="hljs-number">1.0f</span> + <span class="hljs-number">0</span><span class="hljs-keyword">if</span>)))).real();</span>
|
||||
<span class="line"><span class="hljs-function"><span class="hljs-type">static</span> <span class="hljs-type">float</span> <span class="hljs-title">fresnel</span><span class="hljs-params">(<span class="hljs-type">const</span> std::complex<<span class="hljs-type">float</span>>& sample)</span> </span>{</span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> (((sample - (<span class="hljs-number">1.0f</span> + <span class="hljs-number">0</span><span class="hljs-keyword">if</span>)) * (std::<span class="hljs-built_in">conj</span>(sample) - (<span class="hljs-number">1.0f</span> + <span class="hljs-number">0</span><span class="hljs-keyword">if</span>))) /</span>
|
||||
<span class="line"> ((sample + (<span class="hljs-number">1.0f</span> + <span class="hljs-number">0</span><span class="hljs-keyword">if</span>)) * (std::<span class="hljs-built_in">conj</span>(sample) + (<span class="hljs-number">1.0f</span> + <span class="hljs-number">0</span><span class="hljs-keyword">if</span>)))).<span class="hljs-built_in">real</span>();</span>
|
||||
<span class="line">}</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"><span class="hljs-function"><span class="hljs-keyword">static</span> float3 <span class="hljs-title">XYZ_to_sRGB</span><span class="hljs-params">(<span class="hljs-keyword">const</span> float3& v)</span> </span>{</span>
|
||||
<span class="line"> <span class="hljs-keyword">const</span> mat3f XYZ_sRGB{</span>
|
||||
<span class="line"><span class="hljs-function"><span class="hljs-type">static</span> float3 <span class="hljs-title">XYZ_to_sRGB</span><span class="hljs-params">(<span class="hljs-type">const</span> float3& v)</span> </span>{</span>
|
||||
<span class="line"> <span class="hljs-type">const</span> mat3f XYZ_sRGB{</span>
|
||||
<span class="line"> <span class="hljs-number">3.2404542f</span>, <span class="hljs-number">-0.9692660f</span>, <span class="hljs-number">0.0556434f</span>,</span>
|
||||
<span class="line"> <span class="hljs-number">-1.5371385f</span>, <span class="hljs-number">1.8760108f</span>, <span class="hljs-number">-0.2040259f</span>,</span>
|
||||
<span class="line"> <span class="hljs-number">-0.4985314f</span>, <span class="hljs-number">0.0415560f</span>, <span class="hljs-number">1.0572252f</span></span>
|
||||
@@ -3529,21 +3529,21 @@ Our implementation is presented in <a href="#listing_specularcolorimpl">listing&
|
||||
<span class="line">}</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"><span class="hljs-comment">// Outputs a linear sRGB color</span></span>
|
||||
<span class="line"><span class="hljs-function"><span class="hljs-keyword">static</span> float3 <span class="hljs-title">computeColor</span><span class="hljs-params">(<span class="hljs-keyword">const</span> <span class="hljs-built_in">std</span>::<span class="hljs-built_in">vector</span><sample>& samples)</span> </span>{</span>
|
||||
<span class="line"><span class="hljs-function"><span class="hljs-type">static</span> float3 <span class="hljs-title">computeColor</span><span class="hljs-params">(<span class="hljs-type">const</span> std::vector<sample>& samples)</span> </span>{</span>
|
||||
<span class="line"> float3 xyz{<span class="hljs-number">0.0f</span>};</span>
|
||||
<span class="line"> <span class="hljs-keyword">float</span> y = <span class="hljs-number">0.0f</span>;</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> y = <span class="hljs-number">0.0f</span>;</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">size_t</span> i = <span class="hljs-number">0</span>; i < CIE_XYZ_COUNT; i++) {</span>
|
||||
<span class="line"> <span class="hljs-keyword">for</span> (<span class="hljs-type">size_t</span> i = <span class="hljs-number">0</span>; i < CIE_XYZ_COUNT; i++) {</span>
|
||||
<span class="line"> <span class="hljs-comment">// Current wavelength</span></span>
|
||||
<span class="line"> <span class="hljs-keyword">float</span> w = CIE_XYZ_START + i;</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> w = CIE_XYZ_START + i;</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"> <span class="hljs-comment">// Find most appropriate CIE XYZ sample for the wavelength</span></span>
|
||||
<span class="line"> <span class="hljs-keyword">auto</span> sample = findSample(samples, w);</span>
|
||||
<span class="line"> <span class="hljs-keyword">auto</span> sample = <span class="hljs-built_in">findSample</span>(samples, w);</span>
|
||||
<span class="line"> <span class="hljs-comment">// Compute Fresnel reflectance at normal incidence</span></span>
|
||||
<span class="line"> <span class="hljs-keyword">float</span> f0 = fresnel(sample);</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> f0 = <span class="hljs-built_in">fresnel</span>(sample);</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"> <span class="hljs-comment">// We need to multiply by the spectral power distribution of the illuminant</span></span>
|
||||
<span class="line"> <span class="hljs-keyword">float</span> d65 = illuminantD65(w);</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> d65 = <span class="hljs-built_in">illuminantD65</span>(w);</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"> xyz += f0 * CIE_XYZ[i] * d65;</span>
|
||||
<span class="line"> y += CIE_XYZ[i].y * d65;</span>
|
||||
@@ -3552,10 +3552,10 @@ Our implementation is presented in <a href="#listing_specularcolorimpl">listing&
|
||||
<span class="line"> <span class="hljs-comment">// Normalize so that 100% reflectance at every wavelength yields Y=1</span></span>
|
||||
<span class="line"> xyz /= y;</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"> float3 linear = XYZ_to_sRGB(xyz);</span>
|
||||
<span class="line"> float3 linear = <span class="hljs-built_in">XYZ_to_sRGB</span>(xyz);</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"> <span class="hljs-comment">// Normalize out-of-gamut values</span></span>
|
||||
<span class="line"> <span class="hljs-keyword">if</span> (any(greaterThan(linear, float3{<span class="hljs-number">1.0f</span>}))) linear *= <span class="hljs-number">1.0f</span> / max(linear);</span>
|
||||
<span class="line"> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">any</span>(<span class="hljs-built_in">greaterThan</span>(linear, float3{<span class="hljs-number">1.0f</span>}))) linear *= <span class="hljs-number">1.0f</span> / <span class="hljs-built_in">max</span>(linear);</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> linear;</span>
|
||||
<span class="line">}</span></code></pre><center><div class="listingcaption tilde"><a class="target" name="listing_specularcolorimpl"> </a><b style="font-style:normal;">Listing 46:</b> C++ implementation to compute the base color of a metallic surface from spectral data</div></center>
|
||||
@@ -3735,47 +3735,47 @@ l &= \{ cos\phi sin\theta,sin\phi sin\theta,cos\theta \}
|
||||
<pre class="listing tilde"><code><span class="line">vec2f hammersley(uint i, <span class="hljs-built_in">float</span> numSamples) {</span>
|
||||
<span class="line"> uint bits = i;</span>
|
||||
<span class="line"> bits = (bits << <span class="hljs-string">16) | (bits >> 16</span>);</span>
|
||||
<span class="line"> bits = ((bits & 0x55555555) << <span class="hljs-string">1) | ((bits & 0xAAAAAAAA) >> 1</span>);</span>
|
||||
<span class="line"> bits = ((bits & 0x33333333) << <span class="hljs-string">2) | ((bits & 0xCCCCCCCC) >> 2</span>);</span>
|
||||
<span class="line"> bits = ((bits & 0x0F0F0F0F) << <span class="hljs-string">4) | ((bits & 0xF0F0F0F0) >> 4</span>);</span>
|
||||
<span class="line"> bits = ((bits & 0x00FF00FF) << <span class="hljs-string">8) | ((bits & 0xFF00FF00) >> 8</span>);</span>
|
||||
<span class="line"> <span class="hljs-built_in">return</span> vec2f(i / numSamples, bits / exp2(32));</span>
|
||||
<span class="line"> bits = ((bits & <span class="hljs-number">0</span>x55555555) << <span class="hljs-number">1</span>) | ((bits & <span class="hljs-number">0</span>xAAAAAAAA) >> <span class="hljs-number">1</span>);</span>
|
||||
<span class="line"> bits = ((bits & <span class="hljs-number">0</span>x33333333) << <span class="hljs-number">2</span>) | ((bits & <span class="hljs-number">0</span>xCCCCCCCC) >> <span class="hljs-number">2</span>);</span>
|
||||
<span class="line"> bits = ((bits & <span class="hljs-number">0</span>x0F0F0F0F) << <span class="hljs-number">4</span>) | ((bits & <span class="hljs-number">0</span>xF0F0F0F0) >> <span class="hljs-number">4</span>);</span>
|
||||
<span class="line"> bits = ((bits & <span class="hljs-number">0</span>x00FF00FF) << <span class="hljs-number">8</span>) | ((bits & <span class="hljs-number">0</span>xFF00FF00) >> <span class="hljs-number">8</span>);</span>
|
||||
<span class="line"> return vec2f(i / numSamples, bits / exp2(<span class="hljs-number">32</span>));</span>
|
||||
<span class="line">}</span></code></pre><center><div class="listingcaption tilde">C++ implementation of a Hammersley sequence generator</div></center>
|
||||
<a class="target" name="precomputinglforimage-basedlighting"> </a><a class="target" name="annex/precomputinglforimage-basedlighting"> </a><a class="target" name="toc9.5"> </a><h2 id="precomputing-l-for-image-based-lighting"><a class="header" href="#precomputing-l-for-image-based-lighting">Precomputing L for image-based lighting</a></h2>
|
||||
<p>
|
||||
<p>The term ( L_{DFG} ) is only dependent on ( \NoV ). Below, the normal is arbitrarily set to ( n=\left[0, 0, 1\right] ) and (v) is chosen to satisfy ( \NoV ). The vector ( h_i ) is the ( D_{GGX}(\alpha) ) important direction sample (i).</p>
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-type">float</span> GDFG(<span class="hljs-type">float</span> NoV, <span class="hljs-type">float</span> NoL, <span class="hljs-type">float</span> a) {</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> a2 = a * a;</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> GGXL = NoV * <span class="hljs-built_in">sqrt</span>((-NoL * a2 + NoL) * NoL + a2);</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> GGXV = NoL * <span class="hljs-built_in">sqrt</span>((-NoV * a2 + NoV) * NoV + a2);</span>
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-type">float</span> <span class="hljs-title function_">GDFG</span><span class="hljs-params">(<span class="hljs-type">float</span> NoV, <span class="hljs-type">float</span> NoL, <span class="hljs-type">float</span> a)</span> {</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> <span class="hljs-variable">a2</span> <span class="hljs-operator">=</span> a * a;</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> <span class="hljs-variable">GGXL</span> <span class="hljs-operator">=</span> NoV * sqrt((-NoL * a2 + NoL) * NoL + a2);</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> <span class="hljs-variable">GGXV</span> <span class="hljs-operator">=</span> NoL * sqrt((-NoV * a2 + NoV) * NoV + a2);</span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> (<span class="hljs-number">2</span> * NoL) / (GGXV + GGXL);</span>
|
||||
<span class="line">}</span>
|
||||
<span class="line"></span>
|
||||
<span class="line">float2 DFG(<span class="hljs-type">float</span> NoV, <span class="hljs-type">float</span> a) {</span>
|
||||
<span class="line">float2 <span class="hljs-title function_">DFG</span><span class="hljs-params">(<span class="hljs-type">float</span> NoV, <span class="hljs-type">float</span> a)</span> {</span>
|
||||
<span class="line"> float3 V;</span>
|
||||
<span class="line"> V.x = <span class="hljs-built_in">sqrt</span>(<span class="hljs-number">1.0</span>f - NoV*NoV);</span>
|
||||
<span class="line"> V.y = <span class="hljs-number">0.0</span>f;</span>
|
||||
<span class="line"> V.x = sqrt(<span class="hljs-number">1.0f</span> - NoV*NoV);</span>
|
||||
<span class="line"> V.y = <span class="hljs-number">0.0f</span>;</span>
|
||||
<span class="line"> V.z = NoV;</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"> float2 r = <span class="hljs-number">0.0</span>f;</span>
|
||||
<span class="line"> <span class="hljs-keyword">for</span> (<span class="hljs-type">uint</span> i = <span class="hljs-number">0</span>; i < sampleCount; i++) {</span>
|
||||
<span class="line"> float2 Xi = hammersley(i, sampleCount);</span>
|
||||
<span class="line"> float3 H = importanceSampleGGX(Xi, a, N);</span>
|
||||
<span class="line"> float3 L = <span class="hljs-number">2.0</span>f * <span class="hljs-built_in">dot</span>(V, H) * H - V;</span>
|
||||
<span class="line"> <span class="hljs-type">float2</span> <span class="hljs-variable">r</span> <span class="hljs-operator">=</span> <span class="hljs-number">0.0f</span>;</span>
|
||||
<span class="line"> <span class="hljs-keyword">for</span> (<span class="hljs-type">uint</span> <span class="hljs-variable">i</span> <span class="hljs-operator">=</span> <span class="hljs-number">0</span>; i < sampleCount; i++) {</span>
|
||||
<span class="line"> <span class="hljs-type">float2</span> <span class="hljs-variable">Xi</span> <span class="hljs-operator">=</span> hammersley(i, sampleCount);</span>
|
||||
<span class="line"> <span class="hljs-type">float3</span> <span class="hljs-variable">H</span> <span class="hljs-operator">=</span> importanceSampleGGX(Xi, a, N);</span>
|
||||
<span class="line"> <span class="hljs-type">float3</span> <span class="hljs-variable">L</span> <span class="hljs-operator">=</span> <span class="hljs-number">2.0f</span> * dot(V, H) * H - V;</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"> <span class="hljs-type">float</span> VoH = saturate(<span class="hljs-built_in">dot</span>(V, H));</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> NoL = saturate(L.z);</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> NoH = saturate(H.z);</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> <span class="hljs-variable">VoH</span> <span class="hljs-operator">=</span> saturate(dot(V, H));</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> <span class="hljs-variable">NoL</span> <span class="hljs-operator">=</span> saturate(L.z);</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> <span class="hljs-variable">NoH</span> <span class="hljs-operator">=</span> saturate(H.z);</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"> <span class="hljs-keyword">if</span> (NoL > <span class="hljs-number">0.0</span>f) {</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> G = GDFG(NoV, NoL, a);</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> Gv = G * VoH / NoH;</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> Fc = <span class="hljs-built_in">pow</span>(<span class="hljs-number">1</span> - VoH, <span class="hljs-number">5.0</span>f);</span>
|
||||
<span class="line"> <span class="hljs-keyword">if</span> (NoL > <span class="hljs-number">0.0f</span>) {</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> <span class="hljs-variable">G</span> <span class="hljs-operator">=</span> GDFG(NoV, NoL, a);</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> <span class="hljs-variable">Gv</span> <span class="hljs-operator">=</span> G * VoH / NoH;</span>
|
||||
<span class="line"> <span class="hljs-type">float</span> <span class="hljs-variable">Fc</span> <span class="hljs-operator">=</span> pow(<span class="hljs-number">1</span> - VoH, <span class="hljs-number">5.0f</span>);</span>
|
||||
<span class="line"> r.x += Gv * (<span class="hljs-number">1</span> - Fc);</span>
|
||||
<span class="line"> r.y += Gv * Fc;</span>
|
||||
<span class="line"> }</span>
|
||||
<span class="line"> }</span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> r * (<span class="hljs-number">1.0</span>f / sampleCount);</span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> r * (<span class="hljs-number">1.0f</span> / sampleCount);</span>
|
||||
<span class="line">}</span></code></pre><center><div class="listingcaption tilde">C++ implementation of the \( L_{DFG} \) term</div></center>
|
||||
<a class="target" name="sphericalharmonics"> </a><a class="target" name="annex/sphericalharmonics"> </a><a class="target" name="toc9.6"> </a><h2 id="spherical-harmonics"><a class="header" href="#spherical-harmonics">Spherical Harmonics</a></h2>
|
||||
<p>
|
||||
@@ -3851,56 +3851,56 @@ sin(m \phi + \phi) &= sin(m \phi) cos(\phi) + cos(m \phi) sin(\phi) \Leftrightar
|
||||
\end{align*}$$
|
||||
</p><p>
|
||||
<a href="#listing_nonnormalizedshbasis">Listing 47</a> shows the C++ code to compute the non-normalized SH basis \(\frac{y^m_l(s)}{\sqrt{2} K^m_l}\):
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">inline</span> <span class="hljs-keyword">size_t</span> <span class="hljs-title">SHindex</span><span class="hljs-params">(<span class="hljs-keyword">ssize_t</span> m, <span class="hljs-keyword">size_t</span> l)</span> </span>{</span>
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-function"><span class="hljs-type">static</span> <span class="hljs-keyword">inline</span> <span class="hljs-type">size_t</span> <span class="hljs-title">SHindex</span><span class="hljs-params">(<span class="hljs-type">ssize_t</span> m, <span class="hljs-type">size_t</span> l)</span> </span>{</span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> l * (l + <span class="hljs-number">1</span>) + m;</span>
|
||||
<span class="line">}</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">computeShBasis</span><span class="hljs-params">(</span>
|
||||
<span class="line"> <span class="hljs-keyword">double</span>* <span class="hljs-keyword">const</span> SHb,</span>
|
||||
<span class="line"> <span class="hljs-keyword">size_t</span> numBands,</span>
|
||||
<span class="line"> <span class="hljs-keyword">const</span> vec3& s)</span></span>
|
||||
<span class="line"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">computeShBasis</span><span class="hljs-params">(</span>
|
||||
<span class="line"> <span class="hljs-type">double</span>* <span class="hljs-type">const</span> SHb,</span>
|
||||
<span class="line"> <span class="hljs-type">size_t</span> numBands,</span>
|
||||
<span class="line"> <span class="hljs-type">const</span> vec3& s)</span></span>
|
||||
<span class="line"></span>{</span>
|
||||
<span class="line"> <span class="hljs-comment">// handle m=0 separately, since it produces only one coefficient</span></span>
|
||||
<span class="line"> <span class="hljs-keyword">double</span> Pml_2 = <span class="hljs-number">0</span>;</span>
|
||||
<span class="line"> <span class="hljs-keyword">double</span> Pml_1 = <span class="hljs-number">1</span>;</span>
|
||||
<span class="line"> <span class="hljs-type">double</span> Pml_2 = <span class="hljs-number">0</span>;</span>
|
||||
<span class="line"> <span class="hljs-type">double</span> Pml_1 = <span class="hljs-number">1</span>;</span>
|
||||
<span class="line"> SHb[<span class="hljs-number">0</span>] = Pml_1;</span>
|
||||
<span class="line"> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">ssize_t</span> l = <span class="hljs-number">1</span>; l < numBands; l++) {</span>
|
||||
<span class="line"> <span class="hljs-keyword">double</span> Pml = ((<span class="hljs-number">2</span> * l - <span class="hljs-number">1</span>) * Pml_1 * s.z - (l - <span class="hljs-number">1</span>) * Pml_2) / l;</span>
|
||||
<span class="line"> <span class="hljs-keyword">for</span> (<span class="hljs-type">ssize_t</span> l = <span class="hljs-number">1</span>; l < numBands; l++) {</span>
|
||||
<span class="line"> <span class="hljs-type">double</span> Pml = ((<span class="hljs-number">2</span> * l - <span class="hljs-number">1</span>) * Pml_1 * s.z - (l - <span class="hljs-number">1</span>) * Pml_2) / l;</span>
|
||||
<span class="line"> Pml_2 = Pml_1;</span>
|
||||
<span class="line"> Pml_1 = Pml;</span>
|
||||
<span class="line"> SHb[SHindex(<span class="hljs-number">0</span>, l)] = Pml;</span>
|
||||
<span class="line"> SHb[<span class="hljs-built_in">SHindex</span>(<span class="hljs-number">0</span>, l)] = Pml;</span>
|
||||
<span class="line"> }</span>
|
||||
<span class="line"> <span class="hljs-keyword">double</span> Pmm = <span class="hljs-number">1</span>;</span>
|
||||
<span class="line"> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">ssize_t</span> m = <span class="hljs-number">1</span>; m < numBands ; m++) {</span>
|
||||
<span class="line"> <span class="hljs-type">double</span> Pmm = <span class="hljs-number">1</span>;</span>
|
||||
<span class="line"> <span class="hljs-keyword">for</span> (<span class="hljs-type">ssize_t</span> m = <span class="hljs-number">1</span>; m < numBands ; m++) {</span>
|
||||
<span class="line"> Pmm = (<span class="hljs-number">1</span> - <span class="hljs-number">2</span> * m) * Pmm;</span>
|
||||
<span class="line"> <span class="hljs-keyword">double</span> Pml_2 = Pmm;</span>
|
||||
<span class="line"> <span class="hljs-keyword">double</span> Pml_1 = (<span class="hljs-number">2</span> * m + <span class="hljs-number">1</span>)*Pmm*s.z;</span>
|
||||
<span class="line"> <span class="hljs-type">double</span> Pml_2 = Pmm;</span>
|
||||
<span class="line"> <span class="hljs-type">double</span> Pml_1 = (<span class="hljs-number">2</span> * m + <span class="hljs-number">1</span>)*Pmm*s.z;</span>
|
||||
<span class="line"> <span class="hljs-comment">// l == m</span></span>
|
||||
<span class="line"> SHb[SHindex(-m, m)] = Pml_2;</span>
|
||||
<span class="line"> SHb[SHindex( m, m)] = Pml_2;</span>
|
||||
<span class="line"> SHb[<span class="hljs-built_in">SHindex</span>(-m, m)] = Pml_2;</span>
|
||||
<span class="line"> SHb[<span class="hljs-built_in">SHindex</span>( m, m)] = Pml_2;</span>
|
||||
<span class="line"> <span class="hljs-keyword">if</span> (m + <span class="hljs-number">1</span> < numBands) {</span>
|
||||
<span class="line"> <span class="hljs-comment">// l == m+1</span></span>
|
||||
<span class="line"> SHb[SHindex(-m, m + <span class="hljs-number">1</span>)] = Pml_1;</span>
|
||||
<span class="line"> SHb[SHindex( m, m + <span class="hljs-number">1</span>)] = Pml_1;</span>
|
||||
<span class="line"> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">ssize_t</span> l = m + <span class="hljs-number">2</span>; l < numBands; l++) {</span>
|
||||
<span class="line"> <span class="hljs-keyword">double</span> Pml = ((<span class="hljs-number">2</span> * l - <span class="hljs-number">1</span>) * Pml_1 * s.z - (l + m - <span class="hljs-number">1</span>) * Pml_2)</span>
|
||||
<span class="line"> SHb[<span class="hljs-built_in">SHindex</span>(-m, m + <span class="hljs-number">1</span>)] = Pml_1;</span>
|
||||
<span class="line"> SHb[<span class="hljs-built_in">SHindex</span>( m, m + <span class="hljs-number">1</span>)] = Pml_1;</span>
|
||||
<span class="line"> <span class="hljs-keyword">for</span> (<span class="hljs-type">ssize_t</span> l = m + <span class="hljs-number">2</span>; l < numBands; l++) {</span>
|
||||
<span class="line"> <span class="hljs-type">double</span> Pml = ((<span class="hljs-number">2</span> * l - <span class="hljs-number">1</span>) * Pml_1 * s.z - (l + m - <span class="hljs-number">1</span>) * Pml_2)</span>
|
||||
<span class="line"> / (l - m);</span>
|
||||
<span class="line"> Pml_2 = Pml_1;</span>
|
||||
<span class="line"> Pml_1 = Pml;</span>
|
||||
<span class="line"> SHb[SHindex(-m, l)] = Pml;</span>
|
||||
<span class="line"> SHb[SHindex( m, l)] = Pml;</span>
|
||||
<span class="line"> SHb[<span class="hljs-built_in">SHindex</span>(-m, l)] = Pml;</span>
|
||||
<span class="line"> SHb[<span class="hljs-built_in">SHindex</span>( m, l)] = Pml;</span>
|
||||
<span class="line"> }</span>
|
||||
<span class="line"> }</span>
|
||||
<span class="line"> }</span>
|
||||
<span class="line"> <span class="hljs-keyword">double</span> Cm = s.x;</span>
|
||||
<span class="line"> <span class="hljs-keyword">double</span> Sm = s.y;</span>
|
||||
<span class="line"> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">ssize_t</span> m = <span class="hljs-number">1</span>; m <= numBands ; m++) {</span>
|
||||
<span class="line"> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">ssize_t</span> l = m; l < numBands ; l++) {</span>
|
||||
<span class="line"> SHb[SHindex(-m, l)] *= Sm;</span>
|
||||
<span class="line"> SHb[SHindex( m, l)] *= Cm;</span>
|
||||
<span class="line"> <span class="hljs-type">double</span> Cm = s.x;</span>
|
||||
<span class="line"> <span class="hljs-type">double</span> Sm = s.y;</span>
|
||||
<span class="line"> <span class="hljs-keyword">for</span> (<span class="hljs-type">ssize_t</span> m = <span class="hljs-number">1</span>; m <= numBands ; m++) {</span>
|
||||
<span class="line"> <span class="hljs-keyword">for</span> (<span class="hljs-type">ssize_t</span> l = m; l < numBands ; l++) {</span>
|
||||
<span class="line"> SHb[<span class="hljs-built_in">SHindex</span>(-m, l)] *= Sm;</span>
|
||||
<span class="line"> SHb[<span class="hljs-built_in">SHindex</span>( m, l)] *= Cm;</span>
|
||||
<span class="line"> }</span>
|
||||
<span class="line"> <span class="hljs-keyword">double</span> Cm1 = Cm * s.x - Sm * s.y;</span>
|
||||
<span class="line"> <span class="hljs-keyword">double</span> Sm1 = Sm * s.x + Cm * s.y;</span>
|
||||
<span class="line"> <span class="hljs-type">double</span> Cm1 = Cm * s.x - Sm * s.y;</span>
|
||||
<span class="line"> <span class="hljs-type">double</span> Sm1 = Sm * s.x + Cm * s.y;</span>
|
||||
<span class="line"> Cm = Cm1;</span>
|
||||
<span class="line"> Sm = Sm1;</span>
|
||||
<span class="line"> }</span>
|
||||
@@ -3979,10 +3979,10 @@ $$\begin{equation}
|
||||
\end{equation}$$
|
||||
</p><p>
|
||||
Here is the C++ code to compute \(\hat{C}_l\):
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">double</span> <span class="hljs-title">factorial</span><span class="hljs-params">(<span class="hljs-keyword">size_t</span> n, <span class="hljs-keyword">size_t</span> d = <span class="hljs-number">1</span>)</span></span>;</span>
|
||||
</p><pre class="listing tilde"><code><span class="line"><span class="hljs-function"><span class="hljs-type">static</span> <span class="hljs-type">double</span> <span class="hljs-title">factorial</span><span class="hljs-params">(<span class="hljs-type">size_t</span> n, <span class="hljs-type">size_t</span> d = <span class="hljs-number">1</span>)</span></span>;</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"><span class="hljs-comment">// < cos(theta) > SH coefficients pre-multiplied by 1 / K(0,l)</span></span>
|
||||
<span class="line"><span class="hljs-function"><span class="hljs-keyword">double</span> <span class="hljs-title">computeTruncatedCosSh</span><span class="hljs-params">(<span class="hljs-keyword">size_t</span> l)</span> </span>{</span>
|
||||
<span class="line"><span class="hljs-function"><span class="hljs-type">double</span> <span class="hljs-title">computeTruncatedCosSh</span><span class="hljs-params">(<span class="hljs-type">size_t</span> l)</span> </span>{</span>
|
||||
<span class="line"> <span class="hljs-keyword">if</span> (l == <span class="hljs-number">0</span>) {</span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> M_PI;</span>
|
||||
<span class="line"> } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (l == <span class="hljs-number">1</span>) {</span>
|
||||
@@ -3990,17 +3990,17 @@ Here is the C++ code to compute \(\hat{C}_l\):
|
||||
<span class="line"> } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (l & <span class="hljs-number">1</span>) {</span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;</span>
|
||||
<span class="line"> }</span>
|
||||
<span class="line"> <span class="hljs-keyword">const</span> <span class="hljs-keyword">size_t</span> l_2 = l / <span class="hljs-number">2</span>;</span>
|
||||
<span class="line"> <span class="hljs-keyword">double</span> A0 = ((l_2 & <span class="hljs-number">1</span>) ? <span class="hljs-number">1.0</span> : <span class="hljs-number">-1.0</span>) / ((l + <span class="hljs-number">2</span>) * (l - <span class="hljs-number">1</span>));</span>
|
||||
<span class="line"> <span class="hljs-keyword">double</span> A1 = factorial(l, l_2) / (factorial(l_2) * (<span class="hljs-number">1</span> << l));</span>
|
||||
<span class="line"> <span class="hljs-type">const</span> <span class="hljs-type">size_t</span> l_2 = l / <span class="hljs-number">2</span>;</span>
|
||||
<span class="line"> <span class="hljs-type">double</span> A0 = ((l_2 & <span class="hljs-number">1</span>) ? <span class="hljs-number">1.0</span> : <span class="hljs-number">-1.0</span>) / ((l + <span class="hljs-number">2</span>) * (l - <span class="hljs-number">1</span>));</span>
|
||||
<span class="line"> <span class="hljs-type">double</span> A1 = <span class="hljs-built_in">factorial</span>(l, l_2) / (<span class="hljs-built_in">factorial</span>(l_2) * (<span class="hljs-number">1</span> << l));</span>
|
||||
<span class="line"> <span class="hljs-keyword">return</span> <span class="hljs-number">2</span> * M_PI * A0 * A1;</span>
|
||||
<span class="line">}</span>
|
||||
<span class="line"></span>
|
||||
<span class="line"><span class="hljs-comment">// returns n! / d!</span></span>
|
||||
<span class="line"><span class="hljs-function"><span class="hljs-keyword">double</span> <span class="hljs-title">factorial</span><span class="hljs-params">(<span class="hljs-keyword">size_t</span> n, <span class="hljs-keyword">size_t</span> d )</span> </span>{</span>
|
||||
<span class="line"> d = <span class="hljs-built_in">std</span>::max(<span class="hljs-keyword">size_t</span>(<span class="hljs-number">1</span>), d);</span>
|
||||
<span class="line"> n = <span class="hljs-built_in">std</span>::max(<span class="hljs-keyword">size_t</span>(<span class="hljs-number">1</span>), n);</span>
|
||||
<span class="line"> <span class="hljs-keyword">double</span> r = <span class="hljs-number">1.0</span>;</span>
|
||||
<span class="line"><span class="hljs-function"><span class="hljs-type">double</span> <span class="hljs-title">factorial</span><span class="hljs-params">(<span class="hljs-type">size_t</span> n, <span class="hljs-type">size_t</span> d )</span> </span>{</span>
|
||||
<span class="line"> d = std::<span class="hljs-built_in">max</span>(<span class="hljs-built_in">size_t</span>(<span class="hljs-number">1</span>), d);</span>
|
||||
<span class="line"> n = std::<span class="hljs-built_in">max</span>(<span class="hljs-built_in">size_t</span>(<span class="hljs-number">1</span>), n);</span>
|
||||
<span class="line"> <span class="hljs-type">double</span> r = <span class="hljs-number">1.0</span>;</span>
|
||||
<span class="line"> <span class="hljs-keyword">if</span> (n == d) {</span>
|
||||
<span class="line"> <span class="hljs-comment">// intentionally left blank</span></span>
|
||||
<span class="line"> } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (n > d) {</span>
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
@@ -437,7 +446,8 @@ void OpenGLDriver::setPushConstant(ShaderStage const stage, uint8_t const index,
|
||||
if (std::holds_alternative<bool>(value)) {
|
||||
assert_invariant(type == ConstantType::BOOL);
|
||||
bool const bval = std::get<bool>(value);
|
||||
glUniform1i(location, bval ? 1 : 0);
|
||||
// This must be the 'ui' version of glUniform1 due to a crash on M-series macbooks.
|
||||
glUniform1ui(location, bval ? 1 : 0);
|
||||
} else if (std::holds_alternative<float>(value)) {
|
||||
assert_invariant(type == ConstantType::FLOAT);
|
||||
float const fval = std::get<float>(value);
|
||||
|
||||
@@ -254,8 +254,14 @@ void OpenGLProgram::initializeProgramState(OpenGLContext& context, GLuint progra
|
||||
mPushConstants.reserve(totalConstantCount);
|
||||
mPushConstantFragmentStageOffset = vertexConstants.size();
|
||||
auto const transformAndAdd = [&](Program::PushConstant const& constant) {
|
||||
GLint const loc = glGetUniformLocation(program, constant.name.c_str());
|
||||
mPushConstants.push_back({loc, constant.type});
|
||||
if (!constant.name.empty()) {
|
||||
GLint const loc = glGetUniformLocation(program, constant.name.c_str());
|
||||
mPushConstants.push_back({loc, constant.type});
|
||||
} else {
|
||||
// If the constant is not named, then we assume it will not be referenced in this
|
||||
// program.
|
||||
mPushConstants.push_back({ -1, constant.type });
|
||||
}
|
||||
};
|
||||
std::for_each(vertexConstants.cbegin(), vertexConstants.cend(), transformAndAdd);
|
||||
std::for_each(fragmentConstants.cbegin(), fragmentConstants.cend(), transformAndAdd);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -272,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) {
|
||||
@@ -2146,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;
|
||||
};
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -52,17 +52,17 @@ layout(push_constant) uniform Constants {
|
||||
float triangleScale;
|
||||
float triangleOffsetX;
|
||||
float triangleOffsetY;
|
||||
} pushConstants;
|
||||
} pushConstantsV;
|
||||
|
||||
layout(location = 0) in vec4 mesh_position;
|
||||
void main() {
|
||||
if (pushConstants.hideTriangle) {
|
||||
if (pushConstantsV.hideTriangle) {
|
||||
// Test that bools are written correctly. All bits must be 0 if the bool is false.
|
||||
gl_Position = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
gl_Position = vec4(mesh_position.xy * pushConstants.triangleScale +
|
||||
vec2(pushConstants.triangleOffsetX, pushConstants.triangleOffsetY), 0.0, 1.0);
|
||||
gl_Position = vec4(mesh_position.xy * pushConstantsV.triangleScale +
|
||||
vec2(pushConstantsV.triangleOffsetX, pushConstantsV.triangleOffsetY), 0.0, 1.0);
|
||||
#if defined(TARGET_VULKAN_ENVIRONMENT)
|
||||
// In Vulkan, clip space is Y-down. In OpenGL and Metal, clip space is Y-up.
|
||||
gl_Position.y = -gl_Position.y;
|
||||
@@ -72,16 +72,22 @@ 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;
|
||||
} pushConstants;
|
||||
} pushConstantsF;
|
||||
|
||||
precision mediump int; precision highp float;
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
void main() {
|
||||
fragColor = vec4(pushConstants.red, pushConstants.green, pushConstants.blue, 1.0);
|
||||
fragColor = vec4(pushConstantsF.red, pushConstantsF.green, pushConstantsF.blue, 1.0);
|
||||
})";
|
||||
|
||||
void initPushConstants() {
|
||||
@@ -91,22 +97,22 @@ void initPushConstants() {
|
||||
|
||||
gVertConstants.reserve(4);
|
||||
gVertConstants.resize(4);
|
||||
gVertConstants[pushConstantIndex.TRIANGLE_HIDE] = {"hideTriangle", backend::ConstantType::BOOL};
|
||||
gVertConstants[pushConstantIndex.TRIANGLE_SCALE] = {"triangleScale", backend::ConstantType::FLOAT};
|
||||
gVertConstants[pushConstantIndex.TRIANGLE_OFFSET_X] = {"triangleOffsetX", backend::ConstantType::FLOAT};
|
||||
gVertConstants[pushConstantIndex.TRIANGLE_OFFSET_Y] = {"triangleOffsetY", backend::ConstantType::FLOAT};
|
||||
gVertConstants[pushConstantIndex.TRIANGLE_HIDE] = {"pushConstantsV.hideTriangle", backend::ConstantType::BOOL};
|
||||
gVertConstants[pushConstantIndex.TRIANGLE_SCALE] = {"pushConstantsV.triangleScale", backend::ConstantType::FLOAT};
|
||||
gVertConstants[pushConstantIndex.TRIANGLE_OFFSET_X] = {"pushConstantsV.triangleOffsetX", backend::ConstantType::FLOAT};
|
||||
gVertConstants[pushConstantIndex.TRIANGLE_OFFSET_Y] = {"pushConstantsV.triangleOffsetY", backend::ConstantType::FLOAT};
|
||||
|
||||
gFragConstants.reserve(4);
|
||||
gFragConstants.resize(4);
|
||||
gFragConstants[pushConstantIndex.RED] = {"red", backend::ConstantType::FLOAT};
|
||||
gFragConstants[pushConstantIndex.GREEN] = {"green", backend::ConstantType::FLOAT};
|
||||
gFragConstants[pushConstantIndex.BLUE] = {"blue", backend::ConstantType::FLOAT};
|
||||
gFragConstants[pushConstantIndex.RED] = {"pushConstantsF.red", backend::ConstantType::FLOAT};
|
||||
gFragConstants[pushConstantIndex.GREEN] = {"pushConstantsF.green", backend::ConstantType::FLOAT};
|
||||
gFragConstants[pushConstantIndex.BLUE] = {"pushConstantsF.blue", backend::ConstantType::FLOAT};
|
||||
}
|
||||
|
||||
TEST_F(BackendTest, PushConstants) {
|
||||
SKIP_IF(Backend::OPENGL, "see b/453757504");
|
||||
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.
|
||||
|
||||
+107
-47
@@ -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();
|
||||
@@ -1137,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>();
|
||||
@@ -1151,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;
|
||||
}
|
||||
@@ -1456,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;
|
||||
}
|
||||
@@ -1550,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);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
+22
-136
@@ -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,7 +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 {
|
||||
class FEngine : public Engine, public utils::FeatureFlagManager {
|
||||
public:
|
||||
void* operator new(std::size_t const size) noexcept {
|
||||
return utils::aligned_alloc(size, alignof(FEngine));
|
||||
@@ -458,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>;
|
||||
@@ -572,6 +570,11 @@ public:
|
||||
|
||||
backend::Driver& getDriver() const noexcept { return *mDriver; }
|
||||
|
||||
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);
|
||||
void init();
|
||||
@@ -584,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);
|
||||
@@ -706,6 +709,8 @@ private:
|
||||
// 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.
|
||||
@@ -752,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>
|
||||
|
||||
@@ -97,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(),
|
||||
@@ -132,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)) {
|
||||
@@ -282,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();
|
||||
|
||||
@@ -296,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();
|
||||
|
||||
@@ -398,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();
|
||||
@@ -419,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;
|
||||
}
|
||||
|
||||
@@ -467,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(
|
||||
@@ -566,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(
|
||||
@@ -577,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();
|
||||
|
||||
@@ -585,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();
|
||||
}
|
||||
}
|
||||
@@ -604,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() ||
|
||||
@@ -623,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
|
||||
@@ -636,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());
|
||||
@@ -689,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;
|
||||
@@ -724,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,
|
||||
@@ -1007,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
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1197,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) {
|
||||
@@ -1243,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) {
|
||||
|
||||
@@ -83,7 +83,7 @@ public:
|
||||
|
||||
void resetUserTime();
|
||||
|
||||
void skipNextFrames(size_t frameCount) const noexcept {
|
||||
void skipNextFrames(size_t frameCount) noexcept {
|
||||
mFrameSkipper.skipNextFrames(frameCount);
|
||||
}
|
||||
|
||||
@@ -196,8 +196,8 @@ private:
|
||||
return mCommandsHighWatermark;
|
||||
}
|
||||
|
||||
void renderInternal(FView const* view, bool flush);
|
||||
void renderJob(RootArenaScope& rootArenaScope, FView& view);
|
||||
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,
|
||||
@@ -214,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;
|
||||
@@ -226,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;
|
||||
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
* @return Reference to the descriptor
|
||||
*/
|
||||
template<typename RESOURCE>
|
||||
RESOURCE::Descriptor const& getDescriptor(FrameGraphId<RESOURCE> handle) const;
|
||||
typename RESOURCE::Descriptor const& getDescriptor(FrameGraphId<RESOURCE> handle) const;
|
||||
|
||||
/**
|
||||
* Retrieves the descriptor associated to a subresource
|
||||
@@ -75,7 +75,7 @@ public:
|
||||
* @return Reference to the subresource descriptor
|
||||
*/
|
||||
template<typename RESOURCE>
|
||||
RESOURCE::SubResourceDescriptor const& getSubResourceDescriptor(
|
||||
typename RESOURCE::SubResourceDescriptor const& getSubResourceDescriptor(
|
||||
FrameGraphId<RESOURCE> handle) const;
|
||||
|
||||
/**
|
||||
@@ -85,7 +85,7 @@ public:
|
||||
* @return Reference to the descriptor
|
||||
*/
|
||||
template<typename RESOURCE>
|
||||
RESOURCE::Usage const& getUsage(FrameGraphId<RESOURCE> handle) const;
|
||||
typename RESOURCE::Usage const& getUsage(FrameGraphId<RESOURCE> handle) const;
|
||||
|
||||
/**
|
||||
* detach() is used to detach (export) a resource from the framegraph, at which point its
|
||||
@@ -100,7 +100,7 @@ public:
|
||||
*/
|
||||
template<typename RESOURCE>
|
||||
void detach(FrameGraphId<RESOURCE> handle,
|
||||
RESOURCE* pOutResource, RESOURCE::Descriptor* pOutDescriptor) const;
|
||||
RESOURCE* pOutResource, typename RESOURCE::Descriptor* pOutDescriptor) const;
|
||||
|
||||
/**
|
||||
* Retrieves the render pass information associated with Builder::userRenderTarget() with the
|
||||
@@ -134,19 +134,19 @@ RESOURCE const& FrameGraphResources::get(FrameGraphId<RESOURCE> handle) const {
|
||||
}
|
||||
|
||||
template<typename RESOURCE>
|
||||
RESOURCE::Descriptor const& FrameGraphResources::getDescriptor(
|
||||
typename RESOURCE::Descriptor const& FrameGraphResources::getDescriptor(
|
||||
FrameGraphId<RESOURCE> handle) const {
|
||||
return static_cast<Resource<RESOURCE> const&>(getResource(handle)).descriptor;
|
||||
}
|
||||
|
||||
template<typename RESOURCE>
|
||||
RESOURCE::SubResourceDescriptor const& FrameGraphResources::getSubResourceDescriptor(
|
||||
typename RESOURCE::SubResourceDescriptor const& FrameGraphResources::getSubResourceDescriptor(
|
||||
FrameGraphId<RESOURCE> handle) const {
|
||||
return static_cast<Resource<RESOURCE> const&>(getResource(handle)).subResourceDescriptor;
|
||||
}
|
||||
|
||||
template<typename RESOURCE>
|
||||
RESOURCE::Usage const& FrameGraphResources::getUsage(
|
||||
typename RESOURCE::Usage const& FrameGraphResources::getUsage(
|
||||
FrameGraphId<RESOURCE> handle) const {
|
||||
return static_cast<Resource<RESOURCE> const&>(getResource(handle)).usage;
|
||||
}
|
||||
|
||||
@@ -128,11 +128,11 @@ protected:
|
||||
*/
|
||||
template<typename RESOURCE>
|
||||
class Resource : public VirtualResource {
|
||||
using Usage = RESOURCE::Usage;
|
||||
using Usage = typename RESOURCE::Usage;
|
||||
|
||||
public:
|
||||
using Descriptor = RESOURCE::Descriptor;
|
||||
using SubResourceDescriptor = RESOURCE::SubResourceDescriptor;
|
||||
using Descriptor = typename RESOURCE::Descriptor;
|
||||
using SubResourceDescriptor = typename RESOURCE::SubResourceDescriptor;
|
||||
|
||||
// valid only after devirtualize() has been called
|
||||
RESOURCE resource{};
|
||||
@@ -269,8 +269,8 @@ protected:
|
||||
template<typename RESOURCE>
|
||||
class ImportedResource : public Resource<RESOURCE> {
|
||||
public:
|
||||
using Descriptor = RESOURCE::Descriptor;
|
||||
using Usage = RESOURCE::Usage;
|
||||
using Descriptor = typename RESOURCE::Descriptor;
|
||||
using Usage = typename RESOURCE::Usage;
|
||||
|
||||
UTILS_NOINLINE
|
||||
ImportedResource(utils::StaticString name, Descriptor const& desc, Usage usage, RESOURCE const& rsrc) noexcept
|
||||
|
||||
@@ -81,7 +81,7 @@ template <typename T>
|
||||
struct ResourceAllocator {
|
||||
static void create(T& resource, ResourceCreationContext const& context,
|
||||
utils::StaticString name,
|
||||
T::Descriptor const& desc, T::Usage usage) {
|
||||
typename T::Descriptor const& desc, typename T::Usage usage) {
|
||||
if constexpr (is_backend_resource_v<T>) {
|
||||
// This is a backend resource, pass the driver.
|
||||
if constexpr (check_create_v<T,
|
||||
|
||||
@@ -82,11 +82,11 @@ float calculateHorizonCos(highp vec3 sampleDelta, highp vec3 viewDir, float hori
|
||||
|
||||
// https://cdrinmatane.github.io/posts/ssaovb-code/
|
||||
// https://github.com/cdrinmatane/SSRT3/blob/main/HDRP/Shaders/Resources/SSRTCS.compute
|
||||
uint updateSectors(float minHorizon, float maxHorizon, uint globalOccludedBitfield) {
|
||||
uint startHorizonInt = uint(minHorizon * float(SECTOR_COUNT));
|
||||
uint angleHorizonInt = uint(ceil(saturate(maxHorizon-minHorizon) * float(SECTOR_COUNT)));
|
||||
uint angleHorizonBitfield = angleHorizonInt > 0u ? (0xFFFFFFFFu >> (SECTOR_COUNT-angleHorizonInt)) : 0u;
|
||||
uint currentOccludedBitfield = angleHorizonBitfield << startHorizonInt;
|
||||
highp uint updateSectors(float minHorizon, float maxHorizon, highp uint globalOccludedBitfield) {
|
||||
highp uint startHorizonInt = uint(minHorizon * float(SECTOR_COUNT));
|
||||
highp uint angleHorizonInt = uint(ceil(saturate(maxHorizon-minHorizon) * float(SECTOR_COUNT)));
|
||||
highp uint angleHorizonBitfield = angleHorizonInt > 0u ? (0xFFFFFFFFu >> (SECTOR_COUNT-angleHorizonInt)) : 0u;
|
||||
highp uint currentOccludedBitfield = angleHorizonBitfield << startHorizonInt;
|
||||
return globalOccludedBitfield | currentOccludedBitfield;
|
||||
}
|
||||
|
||||
@@ -96,8 +96,8 @@ uint updateSectors(float minHorizon, float maxHorizon, uint globalOccludedBitfie
|
||||
// for each slice. This bitmask flags whether each sector is occluded or not,
|
||||
// which enables surfaces to be modeled with constant thickness, overcoming the limitation
|
||||
// of treating them as a simple height field.
|
||||
uint calculateVisibilityMask(highp vec3 deltaPos, highp vec3 viewDir, float samplingDirection,
|
||||
uint globalOccludedBitfield, float n, highp vec3 origin) {
|
||||
highp uint calculateVisibilityMask(highp vec3 deltaPos, highp vec3 viewDir, float samplingDirection,
|
||||
highp uint globalOccludedBitfield, float n, highp vec3 origin) {
|
||||
vec2 frontBackHorizon;
|
||||
float linearThicknessMultiplier = materialConstants_linearThickness
|
||||
? saturate(origin.z * materialParams.invFarPlane) * 100.0
|
||||
@@ -164,7 +164,7 @@ void groundTruthAmbientOcclusion(out float obscurance, out vec3 bentNormal,
|
||||
float horizonCos1 = -1.0;
|
||||
|
||||
// This is only used in bitmask mode
|
||||
uint globalOccludedBitfield = 0u;
|
||||
highp uint globalOccludedBitfield = 0u;
|
||||
|
||||
for (float j = 0.0; j < materialParams.stepsPerSlice; j += 1.0) {
|
||||
// At least move 1 pixel forward in the screen-space
|
||||
|
||||
@@ -8,6 +8,8 @@ Pod::Spec.new do |spec|
|
||||
spec.platform = :ios, "11.0"
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.68.4/filament-v1.68.4-ios.tgz" }
|
||||
|
||||
spec.libraries = 'c++'
|
||||
|
||||
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
|
||||
spec.pod_target_xcconfig = {
|
||||
'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'arm64'
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
# Filament CocoaPods
|
||||
|
||||
[CocoaPods](https://cocoapods.org/) is the dependency manager Filament uses for Apple platforms
|
||||
(macOS and iOS).
|
||||
|
||||
## Installation
|
||||
|
||||
On macOS, CocoaPods requires a modern Ruby environment. Avoid using the system Ruby; instead,
|
||||
install the latest Ruby version using `brew`, `port,` or use a manager like `rbenv` or `rvm`. Once
|
||||
Ruby is configured:
|
||||
|
||||
```bash
|
||||
gem install cocoapods
|
||||
```
|
||||
|
||||
## Linting the Podspec
|
||||
|
||||
The Filament podspec is configured to fetch releases directly from GitHub. Before deployment,
|
||||
CocoaPods must **lint** the spec to validate that the library compiles and links correctly across
|
||||
all supported architectures.
|
||||
|
||||
To run the linter locally:
|
||||
|
||||
```bash
|
||||
cd ios/CocoaPods/
|
||||
pod spec lint
|
||||
```
|
||||
|
||||
### Debugging Failures
|
||||
|
||||
If the lint fails, use the `--verbose` flag to inspect the underlying `xcodebuild` output:
|
||||
|
||||
```bash
|
||||
pod spec lint --verbose
|
||||
```
|
||||
|
||||
## Isolating Subspecs
|
||||
|
||||
Filament is partitioned into multiple **subspecs**. CocoaPods lints these individually. To
|
||||
accelerate debugging or isolate a specific build failure (e.g., `Filament/filament`), use the
|
||||
following command:
|
||||
|
||||
```bash
|
||||
pod spec lint --no-clean --verbose --subspec=Filament/filament 2>&1 | tee lint_output.log
|
||||
```
|
||||
|
||||
* `--no-clean`: Preserves the temporary Xcode workspace and build artifacts in `/var/folders/...`
|
||||
for inspection.
|
||||
* `--verbose`: Prints the full compiler and linker invocations.
|
||||
* `--subspec`: Limits the scope of the lint to a specific component.
|
||||
|
||||
> **Tip:** To view all defined subspecs, grep the podspec file:
|
||||
> `grep "spec.subspec" ios/CocoaPods/Filament.podspec`
|
||||
|
||||
@@ -963,6 +963,10 @@ utils::io::sstream& CodeGenerator::generateSpecializationConstant(utils::io::sst
|
||||
return out;
|
||||
}
|
||||
|
||||
// Note that we've only introduced push constants to the vertex stage. If we want to add push
|
||||
// constants to the fragment stage, in vulkan, we would have to offset the definition of the field
|
||||
// by the size of the constant struct in the vertex stage. This is due to vulkan having essentially
|
||||
// one block of memory for push constants that is shared across all stages).
|
||||
utils::io::sstream& CodeGenerator::generatePushConstants(utils::io::sstream& out,
|
||||
MaterialBuilder::PushConstantList const& pushConstants, size_t const layoutLocation) const {
|
||||
if (UTILS_UNLIKELY(pushConstants.empty())) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user