Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5f08c87424 |
@@ -0,0 +1,25 @@
|
||||
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
|
||||
@@ -0,0 +1,29 @@
|
||||
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
|
||||
@@ -0,0 +1,26 @@
|
||||
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
|
||||
@@ -0,0 +1,29 @@
|
||||
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
|
||||
@@ -1,59 +0,0 @@
|
||||
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,115 +1,59 @@
|
||||
name: 'Postsubmit CI'
|
||||
name: 'Post-submit tasks'
|
||||
|
||||
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'
|
||||
|
||||
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
|
||||
- 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
|
||||
- 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: |
|
||||
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'
|
||||
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
|
||||
- name: Run build script
|
||||
- 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: |
|
||||
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
|
||||
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,4 +1,4 @@
|
||||
name: 'Presubmit CI'
|
||||
name: Presubmit
|
||||
|
||||
on:
|
||||
push:
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
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
|
||||
@@ -0,0 +1,24 @@
|
||||
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
|
||||
+1
-9
@@ -367,22 +367,14 @@ 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++")
|
||||
elseif (CLANG_WITH_GLIBC)
|
||||
else ()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
|
||||
link_libraries("-static-libgcc -static-libstdc++")
|
||||
link_libraries(libc++.a)
|
||||
link_libraries(libc++abi.a)
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.68.5'
|
||||
implementation 'com.google.android.filament:filament-android:1.68.3'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
|
||||
iOS projects can use CocoaPods to install the latest release:
|
||||
|
||||
```shell
|
||||
pod 'Filament', '~> 1.68.5'
|
||||
pod 'Filament', '~> 1.68.3'
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -7,11 +7,6 @@ A new header is inserted each time a *tag* is created.
|
||||
Instead, if you are authoring a PR for the main branch, add your release note to
|
||||
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
|
||||
|
||||
## v1.68.5
|
||||
|
||||
- engine: "native" Streams are officially deprecated. Use "acquired" streams instead.
|
||||
- engine: add "engine.skip_frame_when_cpu_ahead_of_display" feature [b/474599530]
|
||||
|
||||
## v1.68.4
|
||||
|
||||
- gltfio: Add optional support for webp textures (EXT_texture_webp), controlled via FILAMENT_SUPPORTS_WEBP_TEXTURES cmake option
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
GROUP=com.google.android.filament
|
||||
VERSION_NAME=1.68.5
|
||||
VERSION_NAME=1.68.3
|
||||
|
||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||
|
||||
|
||||
+5
-5
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<!-- Book generated using mdBook -->
|
||||
<meta charset="UTF-8">
|
||||
<title>Maven - Filament</title>
|
||||
<title>Maven Release - 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="../release/cocoapods.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>
|
||||
|
||||
<a rel="next prefetch" href="../release/guide.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>
|
||||
|
||||
@@ -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="../release/cocoapods.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>
|
||||
|
||||
<a rel="next prefetch" href="../release/guide.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>
|
||||
Vendored
+3
-3
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<!-- Book generated using mdBook -->
|
||||
<meta charset="UTF-8">
|
||||
<title>Android on Windows - Filament</title>
|
||||
<title>Build for 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="../dup/contributing.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../build/maven_release.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="../dup/contributing.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../build/maven_release.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/windows_android.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../build/maven_release.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/windows_android.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../build/maven_release.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="../release/branching.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../notes/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>
|
||||
|
||||
@@ -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="../release/branching.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../notes/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>
|
||||
|
||||
|
||||
@@ -159,8 +159,7 @@
|
||||
<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 (<code>/test/renderdiff</code>) is a collections of scripts to run <code>gltf_viewer</code> and produce headless
|
||||
renderings.</p>
|
||||
<p>This tool 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>.
|
||||
@@ -252,7 +251,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_BRANCH=my-pr-branch-golden
|
||||
<pre><code>RDIFF_BBRANCH=my-pr-branch-golden
|
||||
</code></pre>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -293,7 +292,7 @@ the run number is <code>18023632663</code>.</p>
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../dup/test_backend.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<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>
|
||||
|
||||
@@ -307,7 +306,7 @@ the run number is <code>18023632663</code>.</p>
|
||||
</div>
|
||||
|
||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||
<a rel="prev" href="../dup/test_backend.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<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>
|
||||
|
||||
@@ -1,230 +0,0 @@
|
||||
<!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>
|
||||
+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>
|
||||
|
||||
@@ -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="../release/versioning.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../notes/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="../dup/docs.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../notes/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>
|
||||
|
||||
@@ -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="../release/versioning.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../notes/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="../dup/docs.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../notes/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>
|
||||
@@ -165,7 +165,7 @@
|
||||
|
||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||
<!-- Mobile navigation buttons -->
|
||||
<a rel="prev" href="../dup/test_renderdiff.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../dup/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/test_renderdiff.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../dup/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="../release/index.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../notes/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>
|
||||
|
||||
@@ -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="../release/index.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../notes/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>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<!-- Book generated using mdBook -->
|
||||
<meta charset="UTF-8">
|
||||
<title>Github - Filament</title>
|
||||
<title>Release Guide - 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="../release/maven.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../notes/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>
|
||||
|
||||
<a rel="next prefetch" href="../release/versioning.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>
|
||||
|
||||
@@ -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="../release/maven.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<a rel="prev" href="../notes/branching.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/versioning.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>
|
||||
@@ -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/test_backend.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../dup/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>
|
||||
|
||||
@@ -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/test_backend.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../dup/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>
|
||||
|
||||
@@ -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="../release/guide.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<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/branching.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../notes/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="../release/guide.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||
<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/branching.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||
<a rel="next prefetch" href="../notes/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,249 +0,0 @@
|
||||
<!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>
|
||||
@@ -1,215 +0,0 @@
|
||||
<!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>
|
||||
+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,9 +49,6 @@
|
||||
"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"
|
||||
},
|
||||
@@ -86,12 +83,9 @@
|
||||
"dest": "dup/docs.md"
|
||||
},
|
||||
"test/renderdiff/README.md": {
|
||||
"dest": "dup/test_renderdiff.md",
|
||||
"dest": "dup/renderdiff.md",
|
||||
"link_transforms": {
|
||||
"docs/images/": "../images/"
|
||||
}
|
||||
},
|
||||
"test/backend/README.md": {
|
||||
"dest": "dup/test_backend.md"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
- [Introduction](./dup/intro.md)
|
||||
- [Build](./dup/building.md)
|
||||
- [Android on Windows](./build/windows_android.md)
|
||||
- [Build for Android on Windows](./build/windows_android.md)
|
||||
- [Maven Release](./build/maven_release.md)
|
||||
- [Contribute](./dup/contributing.md)
|
||||
- [Coding Style](./dup/code_style.md)
|
||||
- [Core Concepts](./main/README.md)
|
||||
@@ -13,12 +14,9 @@
|
||||
- [Web Tutorial](./samples/web.md)
|
||||
- [Technical Notes](./notes/README.md)
|
||||
- [Material Properties](./notes/material_properties.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)
|
||||
- [Versioning](./notes/versioning.md)
|
||||
- [Branching](./notes/branching.md)
|
||||
- [Release Guide](./notes/release_guide.md)
|
||||
- [Documentation](./dup/docs.md)
|
||||
- [Debugging](./notes/debugging.md)
|
||||
- [Metal](./notes/metal_debugging.md)
|
||||
@@ -30,8 +28,7 @@
|
||||
- [Performance analysis](./notes/performance_analysis.md)
|
||||
- [Framegraph](./notes/framegraph.md)
|
||||
- [Tests](./notes/tests.md)
|
||||
- [backend](./dup/test_backend.md)
|
||||
- [renderdiff](./dup/test_renderdiff.md)
|
||||
- [renderdiff](./dup/renderdiff.md)
|
||||
- [Libraries](./notes/libs.md)
|
||||
- [bluegl](./dup/bluegl.md)
|
||||
- [bluevk](./dup/bluevk.md)
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
# Release
|
||||
|
||||
This is a collection of guides for releasing Filament on different distribution platforms, including
|
||||
Github, Maven, and CocoaPods.
|
||||
@@ -28,6 +28,7 @@ set(SRCS
|
||||
src/BackendUtils.cpp
|
||||
src/BlobCacheKey.cpp
|
||||
src/Callable.cpp
|
||||
src/CallbackHandler.cpp
|
||||
src/CallbackManager.cpp
|
||||
src/CircularBuffer.cpp
|
||||
src/CommandBufferQueue.cpp
|
||||
|
||||
@@ -17,14 +17,6 @@
|
||||
#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 {
|
||||
|
||||
/**
|
||||
@@ -72,13 +64,9 @@ public:
|
||||
virtual void post(void* user, Callback callback) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~CallbackHandler() = default;
|
||||
virtual ~CallbackHandler();
|
||||
};
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // TNT_FILAMENT_BACKEND_CALLBACKHANDLER_H
|
||||
|
||||
@@ -1009,99 +1009,98 @@ 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, // [0 - 4]
|
||||
R8, R8_SNORM, R8UI, R8I, STENCIL8,
|
||||
|
||||
// 16-bits per element
|
||||
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]
|
||||
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,
|
||||
|
||||
// 24-bits per element
|
||||
RGB8, SRGB8, RGB8_SNORM, RGB8UI, RGB8I, // [17 - 21]
|
||||
DEPTH24, // [22]
|
||||
RGB8, SRGB8, RGB8_SNORM, RGB8UI, RGB8I,
|
||||
DEPTH24,
|
||||
|
||||
// 32-bits per element
|
||||
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]
|
||||
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,
|
||||
|
||||
// 48-bits per element
|
||||
RGB16F, RGB16UI, RGB16I, // [40 - 42]
|
||||
RGB16F, RGB16UI, RGB16I,
|
||||
|
||||
// 64-bits per element
|
||||
RG32F, RG32UI, RG32I, // [43 - 45]
|
||||
RGBA16F, RGBA16UI, RGBA16I, // [46 - 48]
|
||||
RG32F, RG32UI, RG32I,
|
||||
RGBA16F, RGBA16UI, RGBA16I,
|
||||
|
||||
// 96-bits per element
|
||||
RGB32F, RGB32UI, RGB32I, // [49 - 51]
|
||||
RGB32F, RGB32UI, RGB32I,
|
||||
|
||||
// 128-bits per element
|
||||
RGBA32F, RGBA32UI, RGBA32I, // [52 - 54]
|
||||
RGBA32F, RGBA32UI, RGBA32I,
|
||||
|
||||
// compressed formats
|
||||
|
||||
// Mandatory in GLES 3.0 and GL 4.3
|
||||
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]
|
||||
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,
|
||||
|
||||
// Available everywhere except Android/iOS
|
||||
DXT1_RGB, DXT1_RGBA, DXT3_RGBA, DXT5_RGBA, // [65 - 68]
|
||||
DXT1_SRGB, DXT1_SRGBA, DXT3_SRGBA, DXT5_SRGBA, // [69 - 72]
|
||||
DXT1_RGB, DXT1_RGBA, DXT3_RGBA, DXT5_RGBA,
|
||||
DXT1_SRGB, DXT1_SRGBA, DXT3_SRGBA, DXT5_SRGBA,
|
||||
|
||||
// ASTC formats are available with a GLES extension
|
||||
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]
|
||||
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,
|
||||
|
||||
// RGTC formats available with a GLES extension
|
||||
RED_RGTC1, // BC4 unsigned [101]
|
||||
SIGNED_RED_RGTC1, // BC4 signed [102]
|
||||
RED_GREEN_RGTC2, // BC5 unsigned [103]
|
||||
SIGNED_RED_GREEN_RGTC2, // BC5 signed [104]
|
||||
RED_RGTC1, // BC4 unsigned
|
||||
SIGNED_RED_RGTC1, // BC4 signed
|
||||
RED_GREEN_RGTC2, // BC5 unsigned
|
||||
SIGNED_RED_GREEN_RGTC2, // BC5 signed
|
||||
|
||||
// BPTC formats available with a GLES extension
|
||||
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]
|
||||
RGB_BPTC_SIGNED_FLOAT, // BC6H signed
|
||||
RGB_BPTC_UNSIGNED_FLOAT,// BC6H unsigned
|
||||
RGBA_BPTC_UNORM, // BC7
|
||||
SRGB_ALPHA_BPTC_UNORM, // BC7 sRGB
|
||||
};
|
||||
|
||||
TextureType getTextureType(TextureFormat format) noexcept;
|
||||
|
||||
@@ -31,10 +31,6 @@
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
namespace utils {
|
||||
class FeatureFlagManager;
|
||||
}
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
class CallbackHandler;
|
||||
@@ -108,11 +104,6 @@ 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
|
||||
@@ -120,6 +111,11 @@ 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.
|
||||
@@ -127,9 +123,22 @@ public:
|
||||
duration_ns compositeToPresentLatency;
|
||||
|
||||
/**
|
||||
* Expected latency [ns] of frame presentation relative to vsync.
|
||||
* The timestamp [ns] since epoch of the system's expected presentation time.
|
||||
* INVALID if not supported.
|
||||
*/
|
||||
duration_ns expectedPresentLatency;
|
||||
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;
|
||||
};
|
||||
|
||||
struct FrameTimestamps {
|
||||
@@ -269,11 +278,6 @@ public:
|
||||
};
|
||||
|
||||
struct DriverConfig {
|
||||
/**
|
||||
* Reference to the system's FeatureFlagManager. Can be nullptr.
|
||||
*/
|
||||
utils::FeatureFlagManager const * UTILS_NULLABLE featureFlagManager = nullptr;
|
||||
|
||||
/**
|
||||
* Size of handle arena in bytes. Setting to 0 indicates default value is to be used.
|
||||
* Driver clamps to valid values.
|
||||
|
||||
@@ -56,16 +56,6 @@ struct VulkanCmdFence;
|
||||
*/
|
||||
class VulkanPlatform : public Platform, utils::PrivateImplementation<VulkanPlatformPrivate> {
|
||||
public:
|
||||
/**
|
||||
* Encapsulates information required to instantiate a known external format,
|
||||
* typically for the purpose of preloading a pipeline cache for materials using
|
||||
* external formats for samplers.
|
||||
*/
|
||||
struct ExternalYcbcrFormat {
|
||||
uint64_t externalFormat;
|
||||
VkSamplerYcbcrModelConversion ycbcrModelConversion;
|
||||
VkSamplerYcbcrRange ycbcrRange;
|
||||
};
|
||||
|
||||
struct ExtensionHashFn {
|
||||
std::size_t operator()(utils::CString const& s) const noexcept {
|
||||
@@ -511,17 +501,6 @@ protected:
|
||||
*/
|
||||
bool isTransientAttachmentSupported() const noexcept;
|
||||
|
||||
/**
|
||||
* For pipeline cache prewarming, if external samplers are present, we need to build
|
||||
* the fake pipeline using the proper formats specified. Since there's no way to
|
||||
* get these at material build time, we allow the app to register them before
|
||||
* creating materials.
|
||||
*
|
||||
* @param format The format, containing the external format value which should be
|
||||
* extracted from an AHardwareBuffer.
|
||||
*/
|
||||
void registerPipelineCachePrewarmExternalFormat(const ExternalYcbcrFormat& format) noexcept;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Contains information about features that should be requested
|
||||
@@ -540,11 +519,6 @@ private:
|
||||
* to be created from a 3d VkImage.
|
||||
*/
|
||||
bool imageView2Don3DImage;
|
||||
|
||||
/**
|
||||
* Desired global priority value for all VkQueue at a system level.
|
||||
*/
|
||||
Platform::GpuContextPriority gpuContextPriority = Platform::GpuContextPriority::DEFAULT;
|
||||
};
|
||||
|
||||
void createInstance(ExtensionSet const& requiredExts) noexcept;
|
||||
|
||||
@@ -81,6 +81,7 @@ public:
|
||||
bool queryFrameTimestamps(SwapChain const* swapchain, uint64_t frameId,
|
||||
FrameTimestamps* outFrameTimestamps) const noexcept override;
|
||||
|
||||
|
||||
protected:
|
||||
ExtensionSet getSwapchainInstanceExtensions() const override;
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <backend/CallbackHandler.h>
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
// Define the virtual destructor here to avoid a compiler warning that we treat as an error.
|
||||
// "'CallbackHandler' has no out-of-line virtual method definitions; its vtable will be emitted in every translation unit"
|
||||
// The warning occurs when a class inherits from CallbackHandler.
|
||||
CallbackHandler::~CallbackHandler() = default;
|
||||
|
||||
} // namespace filament::backend
|
||||
@@ -19,13 +19,17 @@
|
||||
|
||||
#include <backend/PixelBufferDescriptor.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <math/scalar.h>
|
||||
#include <math/half.h>
|
||||
|
||||
#include <utils/debug.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/ostream.h>
|
||||
|
||||
namespace filament {
|
||||
namespace backend {
|
||||
@@ -76,7 +80,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// Converts a n-channel image of UBYTE, INT, UINT, or FLOAT to a different type.
|
||||
// Converts a n-channel image of UBYTE, INT, UINT, HALF, or FLOAT to a different type.
|
||||
template<typename dstComponentType, typename srcComponentType>
|
||||
static void reshapeImage(uint8_t* UTILS_RESTRICT dest, const uint8_t* UTILS_RESTRICT src,
|
||||
size_t srcBytesPerRow,
|
||||
@@ -91,6 +95,8 @@ public:
|
||||
UTILS_ASSUME(minChannelCount <= 4);
|
||||
dest += (dstRowOffset * dstBytesPerRow);
|
||||
const int inds[4] = { swizzle ? 2 : 0, 1, swizzle ? 0 : 2, 3 };
|
||||
|
||||
utils::slog.e <<"dstMaxValue=" << +dstMaxValue << utils::io::endl;
|
||||
for (size_t row = 0; row < height; ++row) {
|
||||
const srcComponentType* in = (const srcComponentType*) src;
|
||||
dstComponentType* out = (dstComponentType*)dest + (dstColumnOffset * dstChannelCount);
|
||||
@@ -119,6 +125,7 @@ public:
|
||||
static bool reshapeImage(PixelBufferDescriptor* UTILS_RESTRICT dst, PixelDataType srcType,
|
||||
uint32_t srcChannelCount, const uint8_t* UTILS_RESTRICT srcBytes, int srcBytesPerRow,
|
||||
int width, int height, bool swizzle) {
|
||||
using namespace utils;
|
||||
size_t dstChannelCount;
|
||||
switch (dst->format) {
|
||||
case PixelDataFormat::R_INTEGER: dstChannelCount = 1; break;
|
||||
@@ -129,7 +136,9 @@ public:
|
||||
case PixelDataFormat::RG: dstChannelCount = 2; break;
|
||||
case PixelDataFormat::RGB: dstChannelCount = 3; break;
|
||||
case PixelDataFormat::RGBA: dstChannelCount = 4; break;
|
||||
default: return false;
|
||||
default:
|
||||
slog.e << "DataReshaper: unsupported dst->format: " << (int)dst->format << io::endl;
|
||||
return false;
|
||||
}
|
||||
void (*reshaper)(uint8_t* dest, const uint8_t* src, size_t srcBytesPerRow,
|
||||
size_t srcChannelCount,
|
||||
@@ -155,7 +164,10 @@ public:
|
||||
case FLOAT: reshaper = reshapeImage<uint8_t, float>; break;
|
||||
case INT: reshaper = reshapeImage<uint8_t, int32_t>; break;
|
||||
case UINT: reshaper = reshapeImage<uint8_t, uint32_t>; break;
|
||||
default: return false;
|
||||
case HALF: reshaper = reshapeImage<uint8_t, math::half>; break;
|
||||
default:
|
||||
slog.e << "DataReshaper: UBYTE dst, unsupported srcType: " << (int)srcType << io::endl;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case FLOAT:
|
||||
@@ -164,7 +176,9 @@ public:
|
||||
case FLOAT: reshaper = reshapeImage<float, float>; break;
|
||||
case INT: reshaper = reshapeImage<float, int32_t>; break;
|
||||
case UINT: reshaper = reshapeImage<float, uint32_t>; break;
|
||||
default: return false;
|
||||
default:
|
||||
slog.e << "DataReshaper: FLOAT dst, unsupported srcType: " << (int)srcType << io::endl;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case INT:
|
||||
@@ -173,7 +187,9 @@ public:
|
||||
case FLOAT: reshaper = reshapeImage<int32_t, float>; break;
|
||||
case INT: reshaper = reshapeImage<int32_t, int32_t>; break;
|
||||
case UINT: reshaper = reshapeImage<int32_t, uint32_t>; break;
|
||||
default: return false;
|
||||
default:
|
||||
slog.e << "DataReshaper: INT dst, unsupported srcType: " << (int)srcType << io::endl;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case UINT:
|
||||
@@ -182,16 +198,21 @@ public:
|
||||
case FLOAT: reshaper = reshapeImage<uint32_t, float>; break;
|
||||
case INT: reshaper = reshapeImage<uint32_t, int32_t>; break;
|
||||
case UINT: reshaper = reshapeImage<uint32_t, uint32_t>; break;
|
||||
default: return false;
|
||||
default:
|
||||
slog.e << "DataReshaper: UINT dst, unsupported srcType: " << (int)srcType << io::endl;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case HALF:
|
||||
switch (srcType) {
|
||||
case HALF: reshaper = copyImage; break;
|
||||
default: return false;
|
||||
default:
|
||||
slog.e << "DataReshaper: HALF dst, unsupported srcType: " << (int)srcType << io::endl;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
slog.e << "DataReshaper: unsupported dst->type: " << (int)dst->type << io::endl;
|
||||
return false;
|
||||
}
|
||||
uint8_t* dstBytes = (uint8_t*) dst->buffer;
|
||||
@@ -200,6 +221,7 @@ public:
|
||||
reshaper(dstBytes, srcBytes, srcBytesPerRow, srcChannelCount,
|
||||
dst->top, dst->left, dstBytesPerRow,
|
||||
dstChannelCount, width, height, swizzle);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -209,6 +231,7 @@ template<> inline int32_t getMaxValue() { return 0x7fffffff; }
|
||||
template<> inline uint32_t getMaxValue() { return 0xffffffff; }
|
||||
template<> inline uint16_t getMaxValue() { return 0x3c00; } // 0x3c00 is 1.0 in half-float.
|
||||
template<> inline uint8_t getMaxValue() { return 0xff; }
|
||||
template<> inline math::half getMaxValue() { return math::half(1.0f); }
|
||||
|
||||
} // namespace backend
|
||||
} // namespace filament
|
||||
|
||||
@@ -79,7 +79,6 @@ 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);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -780,7 +779,6 @@ 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
|
||||
@@ -791,10 +789,10 @@ void ShaderCompilerService::cancelPendingSynchronousProgram(program_token_t cons
|
||||
version = "#version 310 es\n";
|
||||
}
|
||||
|
||||
std::array<std::string_view, 6> sources = {
|
||||
std::array<std::string_view, 5> sources = {
|
||||
version, prolog,
|
||||
{ specializationConstantString.data(), specializationConstantString.size() },
|
||||
packingFunctions, countBitsFunctions,
|
||||
packingFunctions,
|
||||
{ body.data(), body.size() - 1 } // null-terminated
|
||||
};
|
||||
|
||||
@@ -805,8 +803,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*, 6> shaderStrings;
|
||||
std::array<GLint, 6> lengths;
|
||||
std::array<const char*, 5> shaderStrings;
|
||||
std::array<GLint, 5> lengths;
|
||||
for (size_t j = 0; j < count; j++) {
|
||||
shaderStrings[j] = sources[j].data();
|
||||
lengths[j] = GLint(sources[j].size());
|
||||
@@ -1087,22 +1085,6 @@ 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,18 +296,9 @@ bool PlatformEGLAndroid::queryCompositorTiming(SwapChain const* swapchain,
|
||||
|
||||
AndroidFrameCallback::Timeline const preferredTimeline{
|
||||
mAndroidDetails.androidFrameCallback.getPreferredTimeline() };
|
||||
// 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->frameTime = preferredTimeline.frameTime;
|
||||
outCompositorTiming->expectedPresentTime = preferredTimeline.expectedPresentTime;
|
||||
outCompositorTiming->frameTimelineDeadline = preferredTimeline.frameTimelineDeadline;
|
||||
outCompositorTiming->compositeDeadline = CompositorTiming::INVALID;
|
||||
outCompositorTiming->compositeInterval = CompositorTiming::INVALID;
|
||||
outCompositorTiming->compositeToPresentLatency = CompositorTiming::INVALID;
|
||||
|
||||
@@ -22,9 +22,8 @@
|
||||
|
||||
#include "vulkan/memory/ResourcePointer.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <utils/bitset.h>
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
#include <utils/Mutex.h>
|
||||
#include <utils/Slice.h>
|
||||
|
||||
@@ -91,19 +90,6 @@ public:
|
||||
return selectMemoryType(mMemoryProperties, types, reqs);
|
||||
}
|
||||
|
||||
/**
|
||||
* For pipeline cache prewarming, if external samplers are present, we need to build
|
||||
* the fake pipeline using the proper formats specified. Since there's no way to
|
||||
* get these at material build time, we allow the app to register them before
|
||||
* creating materials.
|
||||
*
|
||||
* @param format The format, containing the external format value which should be
|
||||
* extracted from an AHardwareBuffer.
|
||||
*/
|
||||
inline void addPipelineCachePrewarmExternalFormat(const VulkanPlatform::ExternalYcbcrFormat& format) {
|
||||
mPipelineCachePrewarmExternalFormats.push_back(format);
|
||||
}
|
||||
|
||||
inline fvkutils::VkFormatList const& getAttachmentDepthStencilFormats() const {
|
||||
return mDepthStencilFormats;
|
||||
}
|
||||
@@ -120,18 +106,6 @@ public:
|
||||
return mPhysicalDeviceProperties.properties.vendorID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a list of pre-registered external formats for prewarming the Vulkan
|
||||
* pipeline cache.
|
||||
*
|
||||
* @return A list containing an external format number, YCbCr color model conversion,
|
||||
* and YCbCr color range.
|
||||
*/
|
||||
inline const std::vector<VulkanPlatform::ExternalYcbcrFormat>&
|
||||
getPipelineCachePrewarmExternalFormats() const noexcept {
|
||||
return mPipelineCachePrewarmExternalFormats;
|
||||
}
|
||||
|
||||
inline VkExternalFenceHandleTypeFlags getFenceExportFlags() const noexcept {
|
||||
return mFenceExportFlags;
|
||||
}
|
||||
@@ -207,10 +181,6 @@ public:
|
||||
isDynamicRenderingSupported();
|
||||
}
|
||||
|
||||
inline bool isGlobalPrioritySupported() const noexcept {
|
||||
return mGlobalPrioritySupported;
|
||||
}
|
||||
|
||||
private:
|
||||
VkPhysicalDeviceMemoryProperties mMemoryProperties = {};
|
||||
VkPhysicalDeviceProperties2 mPhysicalDeviceProperties = {
|
||||
@@ -244,7 +214,6 @@ private:
|
||||
bool mPipelineCreationFeedbackSupported = false;
|
||||
bool mProtectedMemorySupported = false;
|
||||
bool mVertexInputDynamicStateSupported = false;
|
||||
bool mGlobalPrioritySupported = false;
|
||||
|
||||
// These are options that can be enabled or disabled at an application level.
|
||||
bool mAsyncPipelineCachePrewarmingEnabled = false;
|
||||
@@ -254,8 +223,6 @@ private:
|
||||
fvkutils::VkFormatList mDepthStencilFormats;
|
||||
fvkutils::VkFormatList mBlittableDepthStencilFormats;
|
||||
|
||||
std::vector<VulkanPlatform::ExternalYcbcrFormat> mPipelineCachePrewarmExternalFormats;
|
||||
|
||||
// For convenience so that VulkanPlatform can initialize the private fields.
|
||||
friend class VulkanPlatform;
|
||||
};
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
#include <utils/CString.h>
|
||||
#include <utils/ImmutableCString.h>
|
||||
#include <utils/Panic.h>
|
||||
#include <private/utils/FeatureFlagManager.h>
|
||||
|
||||
#ifndef NDEBUG
|
||||
#include <set> // For VulkanDriver::debugCommandBegin
|
||||
@@ -152,28 +151,6 @@ static CallbackHandler::Callback syncCallbackWrapper = [](void* userData) {
|
||||
cbData->cb(cbData->sync, cbData->userData);
|
||||
};
|
||||
|
||||
/**
|
||||
* Shorthand for converting a description for an external YCbCr format used for
|
||||
* pipeline cache prewarming to the params for the actual YCbCr conversion.
|
||||
*/
|
||||
inline VulkanYcbcrConversionCache::Params getYcbcrConversionParams(const VulkanPlatform::ExternalYcbcrFormat& format) {
|
||||
return VulkanYcbcrConversionCache::Params {
|
||||
.conversion = {
|
||||
.ycbcrModel = fvkutils::getYcbcrModelConversionFilament(format.ycbcrModelConversion),
|
||||
.r = fvkutils::getSwizzleFilament(VK_COMPONENT_SWIZZLE_R, 0),
|
||||
.g = fvkutils::getSwizzleFilament(VK_COMPONENT_SWIZZLE_G, 1),
|
||||
.b = fvkutils::getSwizzleFilament(VK_COMPONENT_SWIZZLE_B, 2),
|
||||
.a = fvkutils::getSwizzleFilament(VK_COMPONENT_SWIZZLE_A, 3),
|
||||
.ycbcrRange = fvkutils::getYcbcrRangeFilament(format.ycbcrRange),
|
||||
.xChromaOffset = fvkutils::getChromaLocationFilament(VK_CHROMA_LOCATION_MIDPOINT),
|
||||
.yChromaOffset = fvkutils::getChromaLocationFilament(VK_CHROMA_LOCATION_MIDPOINT),
|
||||
.chromaFilter = SamplerMagFilter::NEAREST,
|
||||
},
|
||||
.format = VK_FORMAT_UNDEFINED,
|
||||
.externalFormat = format.externalFormat,
|
||||
};
|
||||
}
|
||||
|
||||
}// anonymous namespace
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_DEBUG_UTILS)
|
||||
@@ -273,10 +250,6 @@ 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) {
|
||||
@@ -830,18 +803,12 @@ void VulkanDriver::createProgramR(Handle<HwProgram> ph, Program&& program, utils
|
||||
}
|
||||
|
||||
// If async prewarming is enabled, let's find the proper layout and build the pipeline.
|
||||
std::array<resource_ptr<VulkanDescriptorSetLayout>, MAX_DESCRIPTOR_SET_COUNT> layouts {};
|
||||
VulkanDescriptorSetLayout::DescriptorSetLayoutArray vkLayouts {};
|
||||
bool hasExternalSamplers = false;
|
||||
for (const auto& layoutBinding : program.getDescriptorSetLayouts()) {
|
||||
DescriptorSetLayout layoutDescription = layoutBinding.layout;
|
||||
auto layoutHandle = mResourceManager.allocHandle<VulkanDescriptorSetLayout>();
|
||||
auto layout = mDescriptorSetLayoutCache.createLayout(layoutHandle, std::move(layoutDescription));
|
||||
layouts[layoutBinding.set] = layout;
|
||||
vkLayouts[layoutBinding.set] = layout->getVkLayout();
|
||||
if (layout->bitmask.externalSampler.count() > 0) {
|
||||
hasExternalSamplers = true;
|
||||
}
|
||||
}
|
||||
|
||||
StereoscopicType stereoscopicType = mStereoscopicType;
|
||||
@@ -849,51 +816,13 @@ void VulkanDriver::createProgramR(Handle<HwProgram> ph, Program&& program, utils
|
||||
stereoscopicType = StereoscopicType::NONE;
|
||||
}
|
||||
|
||||
// Base case - build the pipeline without any external samplers.
|
||||
VkPipelineLayout layout = mPipelineLayoutCache.getLayout(vkLayouts, vprogram);
|
||||
mPipelineCache.asyncPrewarmCache(
|
||||
vprogram,
|
||||
mPipelineLayoutCache.getLayout(vkLayouts, vprogram),
|
||||
*vprogram.get(),
|
||||
layout,
|
||||
stereoscopicType,
|
||||
mStereoscopicEyeCount,
|
||||
program.getPriorityQueue());
|
||||
|
||||
if (!hasExternalSamplers) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we have external samplers, let's do this again with the external samplers
|
||||
// specified.
|
||||
for (const auto& format : mContext.getPipelineCachePrewarmExternalFormats()) {
|
||||
// The values that seem to matter in terms of cache hits here are the model conversion,
|
||||
// and model range. We need some value for externalFormat that is known to support that
|
||||
// pair of values, but we need not find every possible externalFormat. As we test on
|
||||
// more devices, this may change.
|
||||
VkSamplerYcbcrConversion vkConversion = mYcbcrConversionCache.getConversion(
|
||||
getYcbcrConversionParams(format));
|
||||
VkSampler externalSampler = mSamplerCache.getSampler({.sampler = {}, .conversion = vkConversion});
|
||||
|
||||
// Update all layouts to use the external samplers.
|
||||
for (size_t i = 0; i < MAX_DESCRIPTOR_SET_COUNT; ++i) {
|
||||
if (!layouts[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// For cache prewarming, we don't need every single possible combination of external sampler
|
||||
// formats. It seems to be enough, in practicce, to simply run through a list of the types of
|
||||
// samplers that *might* appear. As long as the real pipeline is close enough to something that
|
||||
// the driver has seen before, we are able to get a cache hit.
|
||||
utils::FixedCapacityVector<VkSampler> externalSamplers (layouts[i]->bitmask.externalSampler.count(), externalSampler);
|
||||
vkLayouts[i] = mDescriptorSetLayoutCache.getVkLayout(
|
||||
layouts[i]->bitmask, layouts[i]->bitmask.externalSampler, externalSamplers);
|
||||
}
|
||||
|
||||
mPipelineCache.asyncPrewarmCache(
|
||||
vprogram,
|
||||
mPipelineLayoutCache.getLayout(vkLayouts, vprogram),
|
||||
stereoscopicType,
|
||||
mStereoscopicEyeCount,
|
||||
program.getPriorityQueue());
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanDriver::destroyProgram(Handle<HwProgram> ph) {
|
||||
@@ -2151,10 +2080,6 @@ 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,7 +205,6 @@ private:
|
||||
|
||||
bool const mIsSRGBSwapChainSupported;
|
||||
bool const mIsMSAASwapChainSupported;
|
||||
bool const mAcquireSwapChainInMakeCurrent;
|
||||
backend::StereoscopicType const mStereoscopicType;
|
||||
uint8_t const mStereoscopicEyeCount;
|
||||
backend::AsynchronousMode const mAsynchronousMode;
|
||||
|
||||
@@ -265,31 +265,24 @@ void VulkanDescriptorSet::addNewSet(VkDescriptorSet vkSet, OnRecycle&& onRecycle
|
||||
|
||||
PushConstantDescription::PushConstantDescription(backend::Program const& program) {
|
||||
mRangeCount = 0;
|
||||
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 }) {
|
||||
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.
|
||||
description.types.reserve(constants.size());
|
||||
std::for_each(constants.cbegin(), constants.cend(),
|
||||
[&description](Program::PushConstant t) { description.types.push_back(t.type); });
|
||||
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);
|
||||
});
|
||||
|
||||
uint32_t const constantsSize = (uint32_t) constants.size() * ENTRY_SIZE;
|
||||
mRanges[mRangeCount++] = {
|
||||
.stageFlags = getVkStage(stage),
|
||||
.offset = offset,
|
||||
.size = constantsSize,
|
||||
.offset = 0,
|
||||
.size = (uint32_t) constants.size() * ENTRY_SIZE,
|
||||
};
|
||||
description.offset = offset;
|
||||
offset += constantsSize;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,10 +290,7 @@ void PushConstantDescription::write(VkCommandBuffer cmdbuf, VkPipelineLayout lay
|
||||
backend::ShaderStage stage, uint8_t index, backend::PushConstantVariant const& value) {
|
||||
|
||||
uint32_t binaryValue = 0;
|
||||
auto const& description = mDescriptions[(uint8_t) stage];
|
||||
UTILS_UNUSED_IN_RELEASE auto const& types = description.types;
|
||||
uint32_t const offset = description.offset;
|
||||
|
||||
UTILS_UNUSED_IN_RELEASE auto const& types = mTypes[(uint8_t) stage];
|
||||
if (std::holds_alternative<bool>(value)) {
|
||||
assert_invariant(types[index] == ConstantType::BOOL);
|
||||
bool const bval = std::get<bool>(value);
|
||||
@@ -314,8 +304,7 @@ 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), offset + index * ENTRY_SIZE, ENTRY_SIZE,
|
||||
vkCmdPushConstants(cmdbuf, layout, getVkStage(stage), index * ENTRY_SIZE, ENTRY_SIZE,
|
||||
&binaryValue);
|
||||
}
|
||||
|
||||
|
||||
@@ -245,13 +245,7 @@ struct PushConstantDescription {
|
||||
private:
|
||||
static constexpr uint32_t ENTRY_SIZE = sizeof(uint32_t);
|
||||
|
||||
struct ConstantDescription {
|
||||
utils::FixedCapacityVector<backend::ConstantType> types;
|
||||
uint32_t offset = 0;
|
||||
};
|
||||
|
||||
// Describes the constants in each shader stage.
|
||||
ConstantDescription mDescriptions[Program::SHADER_TYPE_COUNT];
|
||||
utils::FixedCapacityVector<backend::ConstantType> mTypes[Program::SHADER_TYPE_COUNT];
|
||||
VkPushConstantRange mRanges[Program::SHADER_TYPE_COUNT];
|
||||
uint32_t mRangeCount;
|
||||
};
|
||||
|
||||
@@ -126,16 +126,14 @@ void VulkanPipelineCache::bindPipeline(VulkanCommandBuffer* commands) {
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanPipelineCache::asyncPrewarmCache(
|
||||
resource_ptr<VulkanProgram> vprogram,
|
||||
void VulkanPipelineCache::asyncPrewarmCache(const VulkanProgram& program,
|
||||
VkPipelineLayout layout,
|
||||
StereoscopicType stereoscopicType,
|
||||
uint8_t stereoscopicViewCount,
|
||||
CompilerPriorityQueue priority) {
|
||||
uint8_t stereoscopicViewCount, CompilerPriorityQueue priority) {
|
||||
PipelineKey key {
|
||||
.shaders = {
|
||||
vprogram->getVertexShader(),
|
||||
vprogram->getFragmentShader(),
|
||||
program.getVertexShader(),
|
||||
program.getFragmentShader(),
|
||||
},
|
||||
// We're using dynamic rendering, so this should be empty.
|
||||
.renderPass = VK_NULL_HANDLE,
|
||||
@@ -177,20 +175,12 @@ void VulkanPipelineCache::asyncPrewarmCache(
|
||||
|
||||
CallbackManager::Handle cmh = mCallbackManager.get();
|
||||
auto token = std::make_shared<ProgramToken>();
|
||||
// Note: we keep a ref to vprogram in this lambda so that the shader modules don't get
|
||||
// destroyed before we call createPipeline(). This is rare enough that we are ok with
|
||||
// occasionally creating pipelines for destroyed materials.
|
||||
mCompilerThreadPool.queue(priority, token, [this, vprogram, key, dynamicOptions, cmh]() mutable {
|
||||
mCompilerThreadPool.queue(priority, token, [this, key, dynamicOptions, cmh]() mutable {
|
||||
VkPipeline pipeline = createPipeline(key, dynamicOptions);
|
||||
mCallbackManager.put(cmh);
|
||||
// We don't actually need this pipeline, we just wanted to force the driver to cache
|
||||
// the pipeline's information.
|
||||
if (pipeline != VK_NULL_HANDLE) {
|
||||
vkDestroyPipeline(mDevice, pipeline, VKALLOC);
|
||||
} else {
|
||||
FVK_LOGW << "Failed to create a pipeline during prewarming, draw-time pipeline "
|
||||
"creation may fail.";
|
||||
}
|
||||
vkDestroyPipeline(mDevice, pipeline, VKALLOC);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ public:
|
||||
// compiling the pipeline on the main thread at draw time. This is very dependent
|
||||
// on the implementation of the driver on the current device; it's expected to work
|
||||
// on devices with VK_EXT_vertex_input_dynamic_state and VK_KHR_dynamic_rendering.
|
||||
void asyncPrewarmCache(resource_ptr<VulkanProgram> vprogram, VkPipelineLayout layout,
|
||||
void asyncPrewarmCache(const VulkanProgram& program, VkPipelineLayout layout,
|
||||
StereoscopicType stereoscopicType, uint8_t stereoscopicViewCount,
|
||||
CompilerPriorityQueue priority);
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ VkPipelineLayout VulkanPipelineLayoutCache::getLayout(
|
||||
|
||||
// build the push constant layout key
|
||||
uint32_t const pushConstantRangeCount = program->getPushConstantRangeCount();
|
||||
auto pushConstantRanges = program->getPushConstantRanges();
|
||||
auto const& pushConstantRanges = program->getPushConstantRanges();
|
||||
if (pushConstantRangeCount > 0) {
|
||||
assert_invariant(pushConstantRangeCount <= Program::SHADER_TYPE_COUNT);
|
||||
for (uint8_t i = 0; i < pushConstantRangeCount; ++i) {
|
||||
|
||||
@@ -232,7 +232,6 @@ ExtensionSet getDeviceExtensions(VkPhysicalDevice device) {
|
||||
VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME,
|
||||
// Required for dynamic rendering, enable this too.
|
||||
VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME,
|
||||
VK_KHR_GLOBAL_PRIORITY_EXTENSION_NAME,
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_SHADER_MODULE)
|
||||
VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME,
|
||||
@@ -486,22 +485,6 @@ bool hasUnifiedMemoryArchitecture(VkPhysicalDeviceMemoryProperties memoryPropert
|
||||
return true;
|
||||
}
|
||||
|
||||
VkQueueGlobalPriorityKHR getVkQueueGlobalPriority(
|
||||
Platform::GpuContextPriority priority) {
|
||||
switch (priority) {
|
||||
case Platform::GpuContextPriority::LOW:
|
||||
return VK_QUEUE_GLOBAL_PRIORITY_LOW_KHR;
|
||||
case Platform::GpuContextPriority::MEDIUM:
|
||||
return VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR;
|
||||
case Platform::GpuContextPriority::HIGH:
|
||||
return VK_QUEUE_GLOBAL_PRIORITY_HIGH_KHR;
|
||||
case Platform::GpuContextPriority::REALTIME:
|
||||
return VK_QUEUE_GLOBAL_PRIORITY_REALTIME_KHR;
|
||||
case Platform::GpuContextPriority::DEFAULT:
|
||||
return VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR;
|
||||
}
|
||||
}
|
||||
|
||||
}// anonymous namespace
|
||||
|
||||
using SwapChainPtr = VulkanPlatform::SwapChainPtr;
|
||||
@@ -641,6 +624,9 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Add support of VK_KHR_global_priority with `driverConfig.gpuContextPriority`
|
||||
// in VulkanPlatform::createDriver.
|
||||
|
||||
MiscDeviceFeatures requestedFeatures {};
|
||||
|
||||
if (setContains(deviceExts, VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME)) {
|
||||
@@ -653,10 +639,6 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
|
||||
context.mPortabilitySubsetFeatures.imageView2DOn3DImage == VK_TRUE;
|
||||
}
|
||||
|
||||
if (context.mGlobalPrioritySupported) {
|
||||
requestedFeatures.gpuContextPriority = driverConfig.gpuContextPriority;
|
||||
}
|
||||
|
||||
if (mImpl->mDevice == VK_NULL_HANDLE) {
|
||||
createLogicalDeviceAndQueues(deviceExts, context.mPhysicalDeviceFeatures.features,
|
||||
context.mPhysicalDeviceVk11Features, context.mProtectedMemorySupported,
|
||||
@@ -816,11 +798,6 @@ bool VulkanPlatform::isTransientAttachmentSupported() const noexcept {
|
||||
return mImpl->mContext.isLazilyAllocatedMemorySupported();
|
||||
}
|
||||
|
||||
void VulkanPlatform::registerPipelineCachePrewarmExternalFormat(
|
||||
const ExternalYcbcrFormat& format) noexcept {
|
||||
mImpl->mContext.addPipelineCachePrewarmExternalFormat(format);
|
||||
}
|
||||
|
||||
VkInstance VulkanPlatform::createVkInstance(const VkInstanceCreateInfo& createInfo) noexcept {
|
||||
VkInstance instance = VK_NULL_HANDLE;
|
||||
VkResult result = vkCreateInstance(&createInfo, VKALLOC, &instance);
|
||||
@@ -945,13 +922,6 @@ void VulkanPlatform::queryAndSetDeviceFeatures(Platform::DriverConfig const& dri
|
||||
chainStruct(&context.mPhysicalDeviceFeatures, &context.mPortabilitySubsetFeatures);
|
||||
}
|
||||
|
||||
VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR globalPriorityFeatures = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_KHR,
|
||||
};
|
||||
if (setContains(deviceExts, VK_KHR_GLOBAL_PRIORITY_EXTENSION_NAME)) {
|
||||
chainStruct(&context.mPhysicalDeviceFeatures, &globalPriorityFeatures);
|
||||
}
|
||||
|
||||
// Initialize the following fields: physicalDeviceProperties, memoryProperties,
|
||||
// physicalDeviceFeatures.
|
||||
vkGetPhysicalDeviceProperties2(mImpl->mPhysicalDevice, &context.mPhysicalDeviceProperties);
|
||||
@@ -968,7 +938,6 @@ void VulkanPlatform::queryAndSetDeviceFeatures(Platform::DriverConfig const& dri
|
||||
setContains(deviceExts, VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME);
|
||||
context.mVertexInputDynamicStateSupported =
|
||||
setContains(deviceExts, VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
|
||||
context.mGlobalPrioritySupported = globalPriorityFeatures.globalPriorityQuery == VK_TRUE;
|
||||
} else {
|
||||
VulkanSharedContext const* scontext = (VulkanSharedContext const*) sharedContext;
|
||||
context.mDebugUtilsSupported = scontext->debugUtilsSupported;
|
||||
@@ -1041,18 +1010,9 @@ void VulkanPlatform::createLogicalDeviceAndQueues(const ExtensionSet& deviceExte
|
||||
for (auto const& ext: deviceExtensions) {
|
||||
requestExtensions.push_back(ext.data());
|
||||
}
|
||||
|
||||
bool const requiresGpuPriority =
|
||||
requestedFeatures.gpuContextPriority != Platform::GpuContextPriority::DEFAULT;
|
||||
VkDeviceQueueGlobalPriorityCreateInfoKHR queuePriorityCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_KHR,
|
||||
.globalPriority = getVkQueueGlobalPriority(requestedFeatures.gpuContextPriority),
|
||||
};
|
||||
|
||||
VkDeviceQueueCreateInfo deviceQueueCreateInfo[2] = {};
|
||||
deviceQueueCreateInfo[0] = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
|
||||
.pNext = requiresGpuPriority ? &queuePriorityCreateInfo : nullptr,
|
||||
.queueFamilyIndex = mImpl->mGraphicsQueueFamilyIndex,
|
||||
.queueCount = 1,
|
||||
.pQueuePriorities = &queuePriority[0],
|
||||
@@ -1130,14 +1090,6 @@ void VulkanPlatform::createLogicalDeviceAndQueues(const ExtensionSet& deviceExte
|
||||
chainStruct(&deviceCreateInfo, &protectedMemory);
|
||||
}
|
||||
|
||||
VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR globalPriority = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_KHR,
|
||||
.globalPriorityQuery = VK_TRUE,
|
||||
};
|
||||
if (requiresGpuPriority) {
|
||||
chainStruct(&deviceCreateInfo, &globalPriority);
|
||||
}
|
||||
|
||||
mImpl->mDevice = createVkDevice(deviceCreateInfo);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/Panic.h>
|
||||
|
||||
#include <bluevk/BlueVK.h>
|
||||
@@ -539,18 +538,9 @@ bool VulkanPlatformAndroid::queryCompositorTiming(SwapChain const* swapchain,
|
||||
|
||||
AndroidFrameCallback::Timeline const preferredTimeline{
|
||||
mAndroidDetails.androidFrameCallback.getPreferredTimeline() };
|
||||
// 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->frameTime = preferredTimeline.frameTime;
|
||||
outCompositorTiming->expectedPresentTime = preferredTimeline.expectedPresentTime;
|
||||
outCompositorTiming->frameTimelineDeadline = preferredTimeline.frameTimelineDeadline;
|
||||
outCompositorTiming->compositeDeadline = CompositorTiming::INVALID;
|
||||
outCompositorTiming->compositeInterval = CompositorTiming::INVALID;
|
||||
outCompositorTiming->compositeToPresentLatency = CompositorTiming::INVALID;
|
||||
|
||||
@@ -72,13 +72,7 @@ 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;
|
||||
@@ -110,9 +104,8 @@ void initPushConstants() {
|
||||
}
|
||||
|
||||
TEST_F(BackendTest, PushConstants) {
|
||||
SKIP_IF(SkipEnvironment(OperatingSystem::CI, Backend::VULKAN), "see b/453776664");
|
||||
SKIP_IF(Backend::WEBGPU, "Push constants not supported on WebGPU");
|
||||
// Test is flaky on CI (but does not repro locally).
|
||||
SKIP_IF(SkipEnvironment(OperatingSystem::CI, Backend::VULKAN), "b/453776664");
|
||||
|
||||
initPushConstants();
|
||||
|
||||
|
||||
@@ -44,8 +44,8 @@ public:
|
||||
math::float3 halfExtent = {};
|
||||
|
||||
/**
|
||||
* Whether the box is empty, i.e.: its extents are zero.
|
||||
* @return true if the extents of the box are zero
|
||||
* Whether the box is empty, i.e.: it's volume is null.
|
||||
* @return true if the volume of the box is null
|
||||
*/
|
||||
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 of its projection.
|
||||
* This is useful to adjust the aspect ratio of the camera independent from 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 in nanoseconds. Using a \p timeout of 0 is a way to query the state of the fence.
|
||||
* @param timeout Wait time out. 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,13 +51,6 @@ 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,13 +42,6 @@ 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];
|
||||
@@ -119,13 +112,6 @@ 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
|
||||
* renderable are immutable.
|
||||
* the 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]
|
||||
duration_ns expectedPresentLatency; //!< system's expected presentation time since epoch [ns]
|
||||
time_point_ns expectedPresentTime; //!< 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) noexcept;
|
||||
void skipNextFrames(size_t frameCount) const 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 for rendering purposes if it doesn't have a Renderable or Light component.
|
||||
* @param entity The entity is ignored 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 7; 7 is lowest priority
|
||||
* @param priority clamped to the range [0..7], defaults to 4; 7 is lowest priority
|
||||
* (rendered last).
|
||||
*
|
||||
* @return Builder reference for chaining calls.
|
||||
|
||||
@@ -69,11 +69,12 @@ 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 explicitly acquires
|
||||
* For ACQUIRED streams, there is no need to perform the copy because Filament explictly acquires
|
||||
* the stream, then releases it later via a callback function. This configuration is especially
|
||||
* useful when the Vulkan backend is enabled.
|
||||
*
|
||||
* NATIVE streams are deprecated because they are backend specific and do not make any synchronization guarantee.
|
||||
* 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.
|
||||
*
|
||||
* Please see `sample-stream-test` and `sample-hello-camera` for usage examples.
|
||||
*
|
||||
@@ -115,9 +116,7 @@ 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,8 +399,7 @@ 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. The driver will invoke
|
||||
* the callback associated with this buffer when the data has been consumed.
|
||||
* @param buffer Client-side buffer containing the image to set.
|
||||
*
|
||||
* @attention \p engine must be the instance passed to Builder::build()
|
||||
* @attention \p level must be less than getLevels().
|
||||
|
||||
@@ -38,16 +38,12 @@
|
||||
#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>
|
||||
@@ -367,7 +363,7 @@ void Engine::flushAndWait() {
|
||||
downcast(this)->flushAndWait();
|
||||
}
|
||||
|
||||
bool Engine::flushAndWait(uint64_t const timeout) {
|
||||
bool Engine::flushAndWait(uint64_t timeout) {
|
||||
return downcast(this)->flushAndWait(timeout);
|
||||
}
|
||||
|
||||
|
||||
@@ -135,7 +135,12 @@ void FrameInfoManager::beginFrame(FSwapChain* swapChain, DriverApi& driver,
|
||||
front.presentDeadline = compositorTiming.compositeDeadline;
|
||||
front.displayPresentInterval = compositorTiming.compositeInterval;
|
||||
front.compositionToPresentLatency = compositorTiming.compositeToPresentLatency;
|
||||
front.expectedPresentLatency = compositorTiming.expectedPresentLatency;
|
||||
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) };
|
||||
}
|
||||
}
|
||||
|
||||
if (mHasTimerQueries) {
|
||||
@@ -329,7 +334,6 @@ void FrameInfoManager::updateUserHistory(FSwapChain* swapChain, DriverApi& drive
|
||||
if (success) {
|
||||
assert_invariant(entry.displayPresent < 0 ||
|
||||
entry.displayPresent == frameTimestamps.displayPresentTime);
|
||||
|
||||
entry.displayPresent = frameTimestamps.displayPresentTime;
|
||||
}
|
||||
} else {
|
||||
@@ -362,7 +366,8 @@ void FrameInfoManager::updateUserHistory(FSwapChain* swapChain, DriverApi& drive
|
||||
.presentDeadline = entry.presentDeadline,
|
||||
.displayPresentInterval = entry.displayPresentInterval,
|
||||
.compositionToPresentLatency = entry.compositionToPresentLatency,
|
||||
.expectedPresentLatency = entry.expectedPresentLatency
|
||||
.expectedPresentTime = entry.expectedPresentTime,
|
||||
|
||||
});
|
||||
}
|
||||
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 latency from vsync [ns]
|
||||
CompositorTiming::duration_ns expectedPresentLatency{ FrameTimestamps::INVALID };
|
||||
// system's expected present time [ns]
|
||||
FrameTimestamps::time_point_ns expectedPresentTime{ FrameTimestamps::INVALID };
|
||||
|
||||
// the fence used for gpuFrameComplete
|
||||
backend::FenceHandle fence{};
|
||||
|
||||
@@ -50,6 +50,7 @@ void FrameSkipper::terminate(DriverApi& driver) noexcept {
|
||||
bool FrameSkipper::shouldRenderFrame(DriverApi& driver) const noexcept {
|
||||
|
||||
if (UTILS_UNLIKELY(mFrameToSkip)) {
|
||||
mFrameToSkip--;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -85,7 +86,7 @@ void FrameSkipper::submitFrame(DriverApi& driver) noexcept {
|
||||
fences[last] = driver.createFence();
|
||||
}
|
||||
|
||||
void FrameSkipper::skipNextFrames(size_t frameCount) noexcept {
|
||||
void FrameSkipper::skipNextFrames(size_t frameCount) const noexcept {
|
||||
frameCount = std::min(frameCount, size_t(std::numeric_limits<decltype(mFrameToSkip)>::max()));
|
||||
mFrameToSkip = uint16_t(frameCount);
|
||||
}
|
||||
|
||||
@@ -69,17 +69,10 @@ 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) noexcept;
|
||||
void skipNextFrames(size_t frameCount) const noexcept;
|
||||
// return remaining number of frame to be skipped
|
||||
size_t getFrameToSkipCount() const noexcept;
|
||||
|
||||
@@ -87,7 +80,7 @@ private:
|
||||
using Container = std::array<backend::Handle<backend::HwFence>, MAX_FRAME_LATENCY>;
|
||||
Container mDelayedFences{};
|
||||
uint8_t const mLatency;
|
||||
uint16_t mFrameToSkip{};
|
||||
mutable uint16_t mFrameToSkip{};
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -13,42 +13,22 @@
|
||||
* 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;
|
||||
@@ -103,7 +83,7 @@ std::unique_ptr<MaterialDefinition> MaterialDefinition::create(FEngine& engine,
|
||||
uint32_t parsedCrc32 = 0;
|
||||
parser->getMaterialCrc32(&parsedCrc32);
|
||||
|
||||
uint32_t const expectedCrc32 = parser->computeCrc32();
|
||||
uint32_t expectedCrc32 = parser->computeCrc32();
|
||||
|
||||
if (parsedCrc32 != expectedCrc32) {
|
||||
CString name;
|
||||
@@ -151,9 +131,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 << ".";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -188,16 +168,16 @@ void MaterialDefinition::processMain() {
|
||||
uint8_t level = 1;
|
||||
mMaterialParser->getFeatureLevel(&level);
|
||||
assert_invariant(level <= 3);
|
||||
FeatureLevel result = FeatureLevel::FEATURE_LEVEL_1;
|
||||
FeatureLevel featureLevel = 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:
|
||||
result = FeatureLevel(level);
|
||||
featureLevel = FeatureLevel(level);
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
return featureLevel;
|
||||
}();
|
||||
|
||||
UTILS_UNUSED_IN_RELEASE bool success;
|
||||
@@ -366,8 +346,6 @@ 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);
|
||||
|
||||
@@ -386,18 +364,18 @@ void MaterialDefinition::processSpecializationConstants(FEngine& engine) {
|
||||
|
||||
specializationConstants
|
||||
[+ReservedSpecializationConstants::CONFIG_STATIC_TEXTURE_TARGET_WORKAROUND] =
|
||||
driver.isWorkaroundNeeded(
|
||||
engine.getDriverApi().isWorkaroundNeeded(
|
||||
Workaround::METAL_STATIC_TEXTURE_TARGET_ERROR);
|
||||
|
||||
specializationConstants[+ReservedSpecializationConstants::CONFIG_SRGB_SWAPCHAIN_EMULATION] =
|
||||
driver.isWorkaroundNeeded(Workaround::EMULATE_SRGB_SWAPCHAIN);
|
||||
engine.getDriverApi().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(driver) / 16u);
|
||||
int(Froxelizer::getFroxelBufferByteCount(engine.getDriverApi()) / 16u);
|
||||
|
||||
specializationConstants[+ReservedSpecializationConstants::CONFIG_POWER_VR_SHADER_WORKAROUNDS] =
|
||||
driver.isWorkaroundNeeded(Workaround::POWER_VR_SHADER_WORKAROUNDS);
|
||||
engine.getDriverApi().isWorkaroundNeeded(Workaround::POWER_VR_SHADER_WORKAROUNDS);
|
||||
|
||||
specializationConstants[+ReservedSpecializationConstants::CONFIG_DEBUG_DIRECTIONAL_SHADOWMAP] =
|
||||
engine.debug.shadowmap.debug_directional_shadowmap;
|
||||
@@ -415,7 +393,7 @@ void MaterialDefinition::processSpecializationConstants(FEngine& engine) {
|
||||
specializationConstants[+ReservedSpecializationConstants::CONFIG_SHADOW_SAMPLING_METHOD] = 0;
|
||||
|
||||
specializationConstants[+ReservedSpecializationConstants::CONFIG_FROXEL_RECORD_BUFFER_HEIGHT] =
|
||||
int(Froxelizer::getFroxelRecordBufferByteCount(driver) / 16u);
|
||||
int(Froxelizer::getFroxelRecordBufferByteCount(engine.getDriverApi()) / 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;
|
||||
@@ -448,21 +426,23 @@ 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> allPushConstants;
|
||||
mMaterialParser->getPushConstants(&structVarName, &allPushConstants);
|
||||
FixedCapacityVector<MaterialPushConstant> pushConstants;
|
||||
mMaterialParser->getPushConstants(&structVarName, &pushConstants);
|
||||
|
||||
vertexConstants.reserve(allPushConstants.size());
|
||||
fragmentConstants.reserve(allPushConstants.size());
|
||||
vertexConstants.reserve(pushConstants.size());
|
||||
fragmentConstants.reserve(pushConstants.size());
|
||||
|
||||
constexpr size_t MAX_NAME_LEN = 60;
|
||||
char buf[MAX_NAME_LEN];
|
||||
uint8_t vertexCount = 0, fragmentCount = 0;
|
||||
|
||||
std::for_each(allPushConstants.cbegin(), allPushConstants.cend(),
|
||||
std::for_each(pushConstants.cbegin(), pushConstants.cend(),
|
||||
[&](MaterialPushConstant const& constant) {
|
||||
snprintf(buf, sizeof(buf), "%s.%s", structVarName.c_str(), constant.name.c_str());
|
||||
|
||||
@@ -482,9 +462,6 @@ 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);
|
||||
@@ -519,22 +496,22 @@ void MaterialDefinition::processDescriptorSets(FEngine& engine) {
|
||||
Program::DescriptorBindingsInfo& descriptors = programDescriptorBindings[+bindingPoint];
|
||||
descriptors.reserve(dsl.descriptors.size());
|
||||
for (auto const& entry: dsl.descriptors) {
|
||||
auto const& descriptorName = descriptor_sets::getDescriptorName(bindingPoint, entry.binding);
|
||||
descriptors.push_back({ descriptorName, entry.type, entry.binding });
|
||||
auto const& name = descriptor_sets::getDescriptorName(bindingPoint, entry.binding);
|
||||
descriptors.push_back({ name, entry.type, entry.binding });
|
||||
}
|
||||
}
|
||||
|
||||
this->descriptorSetLayout = {
|
||||
descriptorSetLayoutFactory, driver,
|
||||
this->descriptorSetLayoutDescription };
|
||||
engine.getDescriptorSetLayoutFactory(),
|
||||
engine.getDriverApi(), this->descriptorSetLayoutDescription };
|
||||
|
||||
this->perViewDescriptorSetLayout = {
|
||||
descriptorSetLayoutFactory, driver,
|
||||
this->perViewDescriptorSetLayoutDescription };
|
||||
engine.getDescriptorSetLayoutFactory(),
|
||||
engine.getDriverApi(), this->perViewDescriptorSetLayoutDescription };
|
||||
|
||||
this->perViewDescriptorSetLayoutVsm = {
|
||||
descriptorSetLayoutFactory, driver,
|
||||
this->perViewDescriptorSetLayoutVsmDescription };
|
||||
engine.getDescriptorSetLayoutFactory(),
|
||||
engine.getDriverApi(), this->perViewDescriptorSetLayoutVsmDescription };
|
||||
}
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -194,11 +194,11 @@ void PostProcessManager::PostProcessMaterial::loadMaterial(FEngine& engine) cons
|
||||
|
||||
UTILS_NOINLINE
|
||||
FMaterial* PostProcessManager::PostProcessMaterial::getMaterial(FEngine& engine,
|
||||
DriverApi& driver, PostProcessVariant variant) const noexcept {
|
||||
PostProcessVariant variant) const noexcept {
|
||||
if (UTILS_UNLIKELY(mSize)) {
|
||||
loadMaterial(engine);
|
||||
}
|
||||
mMaterial->prepareProgram(driver, Variant{ Variant::type_t(variant) },
|
||||
mMaterial->prepareProgram(Variant{ Variant::type_t(variant) },
|
||||
CompilerPriorityQueue::CRITICAL);
|
||||
return mMaterial;
|
||||
}
|
||||
@@ -362,10 +362,6 @@ 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);
|
||||
@@ -566,7 +562,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 = mFeatureLevel == FeatureLevel::FEATURE_LEVEL_0;
|
||||
bool const isES2 = mEngine.getDriverApi().getFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0;
|
||||
data.depth = builder.createTexture("Structure Buffer", {
|
||||
.width = width, .height = height,
|
||||
.levels = uint8_t(levelCount),
|
||||
@@ -603,7 +599,7 @@ PostProcessManager::StructurePassOutput PostProcessManager::structure(FrameGraph
|
||||
passBuilder.variant(structureVariant);
|
||||
passBuilder.commandTypeFlags(RenderPass::CommandTypeFlags::SSAO);
|
||||
|
||||
RenderPass pass{ passBuilder.build(mEngine, driver) };
|
||||
RenderPass pass{ passBuilder.build(mEngine) };
|
||||
pass.finalize(mEngine, driver);
|
||||
auto const out = resources.getRenderPassInfo();
|
||||
driver.beginRenderPass(out.target, out.params);
|
||||
@@ -641,7 +637,7 @@ PostProcessManager::StructurePassOutput PostProcessManager::structure(FrameGraph
|
||||
|
||||
auto in = resources.getTexture(data.depth);
|
||||
auto& material = getPostProcessMaterial("mipmapDepth");
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, driver);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine);
|
||||
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.
|
||||
@@ -676,7 +672,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::transparentPicking(FrameGrap
|
||||
};
|
||||
auto const& pickingRenderPass = fg.addPass<PickingRenderPassData>("Picking Render Pass",
|
||||
[&](FrameGraph::Builder& builder, auto& data) {
|
||||
bool const isFL0 = mFeatureLevel ==
|
||||
bool const isFL0 = mEngine.getDriverApi().getFeatureLevel() ==
|
||||
FeatureLevel::FEATURE_LEVEL_0;
|
||||
|
||||
// TODO: Specify the precision for picking pass
|
||||
@@ -715,7 +711,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::transparentPicking(FrameGrap
|
||||
passBuilder.variant(pickingVariant);
|
||||
passBuilder.commandTypeFlags(RenderPass::CommandTypeFlags::DEPTH);
|
||||
|
||||
RenderPass pass{ passBuilder.build(mEngine, driver) };
|
||||
RenderPass pass{ passBuilder.build(mEngine) };
|
||||
pass.finalize(mEngine, driver);
|
||||
driver.beginRenderPass(target, params);
|
||||
pass.getExecutor().execute(mEngine, driver);
|
||||
@@ -814,7 +810,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, driver) };
|
||||
RenderPass pass{ passBuilder.build(mEngine) };
|
||||
pass.finalize(mEngine, driver);
|
||||
driver.beginRenderPass(out.target, out.params);
|
||||
pass.getExecutor().execute(mEngine, driver);
|
||||
@@ -1006,7 +1002,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::screenSpaceAmbientOcclusion(
|
||||
#endif
|
||||
auto& material = getPostProcessMaterial(materialName);
|
||||
|
||||
FMaterial* ma = material.getMaterial(mEngine, driver);
|
||||
FMaterial* ma = material.getMaterial(mEngine);
|
||||
bool dirty = false;
|
||||
setConstantParameter(ma, "useVisibilityBitmasks", options.gtao.useVisibilityBitmasks, dirty);
|
||||
setConstantParameter(ma, "linearThickness", options.gtao.linearThickness, dirty);
|
||||
@@ -1016,7 +1012,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::screenSpaceAmbientOcclusion(
|
||||
// with surface materials
|
||||
}
|
||||
|
||||
ma = material.getMaterial(mEngine, driver);
|
||||
ma = material.getMaterial(mEngine);
|
||||
FMaterialInstance* const mi = getMaterialInstance(ma);
|
||||
|
||||
// Set AO type specific material parameters
|
||||
@@ -1203,7 +1199,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::bilateralBlurPass(FrameGraph
|
||||
auto& material = config.bentNormals ?
|
||||
getPostProcessMaterial("bilateralBlurBentNormals") :
|
||||
getPostProcessMaterial("bilateralBlur");
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, driver);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine);
|
||||
FMaterialInstance* const mi = getMaterialInstance(ma);
|
||||
mi->setParameter("ssao", ssao, { /* only reads level 0 */ });
|
||||
mi->setParameter("axis", axis / float2{desc.width, desc.height});
|
||||
@@ -1372,7 +1368,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::gaussianBlurPass(FrameGraph&
|
||||
"separableGaussianBlur4L"sv : "separableGaussianBlur4"sv; break;
|
||||
}
|
||||
auto const& separableGaussianBlur = getPostProcessMaterial(materialName);
|
||||
auto ma = separableGaussianBlur.getMaterial(mEngine, driver);
|
||||
auto ma = separableGaussianBlur.getMaterial(mEngine);
|
||||
|
||||
const size_t kernelStorageSize = ma->reflect("kernel")->size;
|
||||
float2 kernel[64];
|
||||
@@ -1398,7 +1394,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::gaussianBlurPass(FrameGraph&
|
||||
|
||||
{
|
||||
// horizontal pass
|
||||
auto mi = getMaterialInstance(mEngine, driver, separableGaussianBlur);
|
||||
auto mi = getMaterialInstance(mEngine, separableGaussianBlur);
|
||||
setCommonParams(mi);
|
||||
mi->setParameter(sourceParameterName, hwIn, SamplerParams{
|
||||
.filterMag = SamplerMagFilter::LINEAR,
|
||||
@@ -1416,7 +1412,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::gaussianBlurPass(FrameGraph&
|
||||
|
||||
{
|
||||
// vertical pass
|
||||
auto mi = getMaterialInstance(mEngine, driver, separableGaussianBlur);
|
||||
auto mi = getMaterialInstance(mEngine, separableGaussianBlur);
|
||||
setCommonParams(mi);
|
||||
UTILS_UNUSED_IN_RELEASE auto width = outDesc.width;
|
||||
UTILS_UNUSED_IN_RELEASE auto height = outDesc.height;
|
||||
@@ -1826,7 +1822,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
|
||||
auto const& material = (dofResolution == 1) ?
|
||||
getPostProcessMaterial("dofCoc") :
|
||||
getPostProcessMaterial("dofDownsample");
|
||||
FMaterialInstance* const mi = getMaterialInstance(mEngine, driver, material);
|
||||
FMaterialInstance* const mi = getMaterialInstance(mEngine, material);
|
||||
|
||||
mi->setParameter("color", color, SamplerParams{
|
||||
.filterMin = SamplerMinFilter::NEAREST });
|
||||
@@ -1888,7 +1884,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, driver);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine);
|
||||
|
||||
auto const pipeline = getPipelineState(ma, variant);
|
||||
|
||||
@@ -1968,7 +1964,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
|
||||
auto const& material = (!textureSwizzleSupported && (i == 0)) ?
|
||||
getPostProcessMaterial("dofTilesSwizzle") :
|
||||
getPostProcessMaterial("dofTiles");
|
||||
FMaterialInstance* const mi = getMaterialInstance(mEngine, driver, material);
|
||||
FMaterialInstance* const mi = getMaterialInstance(mEngine, material);
|
||||
mi->setParameter("cocMinMax", inCocMinMax, SamplerParams{
|
||||
.filterMin = SamplerMinFilter::NEAREST });
|
||||
mi->setParameter("texelSize", float2{ 1.0f / inputDesc.width, 1.0f / inputDesc.height });
|
||||
@@ -2005,7 +2001,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, driver, material);
|
||||
FMaterialInstance* const mi = getMaterialInstance(mEngine, material);
|
||||
mi->setParameter("tiles", inTilesCocMinMax, SamplerParams{
|
||||
.filterMin = SamplerMinFilter::NEAREST });
|
||||
commitAndRenderFullScreenQuad(driver, out, mi);
|
||||
@@ -2068,7 +2064,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
|
||||
auto const& inputDesc = resources.getDescriptor(data.coc);
|
||||
|
||||
auto const& material = getPostProcessMaterial("dof");
|
||||
FMaterialInstance* const mi = getMaterialInstance(mEngine, driver, material);
|
||||
FMaterialInstance* const mi = getMaterialInstance(mEngine, 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 });
|
||||
@@ -2132,7 +2128,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
|
||||
auto tilesCocMinMax = resources.getTexture(data.tilesCocMinMax);
|
||||
|
||||
auto const& material = getPostProcessMaterial("dofMedian");
|
||||
FMaterialInstance* const mi = getMaterialInstance(mEngine, driver, material);
|
||||
FMaterialInstance* const mi = getMaterialInstance(mEngine, material);
|
||||
mi->setParameter("dof", inColor, SamplerParams{
|
||||
.filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
|
||||
mi->setParameter("alpha", inAlpha, SamplerParams{
|
||||
@@ -2186,7 +2182,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
|
||||
auto tilesCocMinMax = resources.getTexture(data.tilesCocMinMax);
|
||||
|
||||
auto const& material = getPostProcessMaterial("dofCombine");
|
||||
FMaterialInstance* const mi = getMaterialInstance(mEngine, driver, material);
|
||||
FMaterialInstance* const mi = getMaterialInstance(mEngine, material);
|
||||
mi->setParameter("color", color, SamplerParams{
|
||||
.filterMin = SamplerMinFilter::NEAREST });
|
||||
mi->setParameter("dof", dof, SamplerParams{
|
||||
@@ -2223,7 +2219,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::downscalePass(FrameGraph& fg
|
||||
|
||||
auto const& out = resources.getRenderPassInfo();
|
||||
auto const& material = getPostProcessMaterial("bloomDownsample2x");
|
||||
FMaterialInstance* const mi = getMaterialInstance(mEngine, driver, material);
|
||||
FMaterialInstance* const mi = getMaterialInstance(mEngine, material);
|
||||
mi->setParameter("source", resources.getTexture(data.input), SamplerParams{
|
||||
.filterMag = SamplerMagFilter::LINEAR,
|
||||
.filterMin = SamplerMinFilter::LINEAR
|
||||
@@ -2367,10 +2363,10 @@ PostProcessManager::BloomPassOutput PostProcessManager::bloom(FrameGraph& fg,
|
||||
auto hwOut = resources.getTexture(data.out);
|
||||
|
||||
auto const& material9 = getPostProcessMaterial("bloomDownsample9");
|
||||
auto* mi9 = getMaterialInstance(mEngine, driver, material9);
|
||||
auto* mi9 = getMaterialInstance(mEngine, material9);
|
||||
|
||||
auto const& material13 = getPostProcessMaterial("bloomDownsample");
|
||||
auto* mi13 = getMaterialInstance(mEngine, driver, material13);
|
||||
auto* mi13 = getMaterialInstance(mEngine, material13);
|
||||
// These material instances have no UBO updates in the loop, so we do not move
|
||||
// getMaterialInstance() inside the loop.
|
||||
|
||||
@@ -2415,7 +2411,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, driver);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine);
|
||||
|
||||
auto pipeline = getPipelineState(ma);
|
||||
pipeline.rasterState.blendFunctionSrcRGB = BlendFunction::ONE;
|
||||
@@ -2479,7 +2475,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::flarePass(FrameGraph& fg,
|
||||
|
||||
auto const& material = getPostProcessMaterial("flare");
|
||||
FMaterialInstance* const mi =
|
||||
getMaterialInstance(mEngine, driver, material);
|
||||
getMaterialInstance(mEngine, material);
|
||||
|
||||
mi->setParameter("color", in, SamplerParams{
|
||||
.filterMag = SamplerMagFilter::LINEAR,
|
||||
@@ -2543,7 +2539,7 @@ void PostProcessManager::colorGradingPrepareSubpass(DriverApi& driver,
|
||||
uint32_t const width, uint32_t const height) noexcept {
|
||||
auto& material = getPostProcessMaterial("colorGradingAsSubpass");
|
||||
FMaterialInstance const* const mi =
|
||||
configureColorGradingMaterial(driver, material, colorGrading, colorGradingConfig,
|
||||
configureColorGradingMaterial(material, colorGrading, colorGradingConfig,
|
||||
vignetteOptions, width, height);
|
||||
mi->commit(driver, getUboManager());
|
||||
}
|
||||
@@ -2558,7 +2554,7 @@ void PostProcessManager::colorGradingSubpass(DriverApi& driver,
|
||||
PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE;
|
||||
|
||||
auto const& material = getPostProcessMaterial("colorGradingAsSubpass");
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, driver, variant);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, variant);
|
||||
// the UBO has been set and committed in colorGradingPrepareSubpass()
|
||||
int32_t const fixedIndex = colorGradingConfig.translucent
|
||||
? mFixedMaterialInstanceIndex.colorGradingTranslucent
|
||||
@@ -2574,7 +2570,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, driver, PostProcessVariant::OPAQUE);
|
||||
auto const ma = material.getMaterial(mEngine, PostProcessVariant::OPAQUE);
|
||||
auto [mi, fixedIndex] = mMaterialInstanceManager.getFixedMaterialInstance(ma);
|
||||
mFixedMaterialInstanceIndex.customResolve = fixedIndex;
|
||||
mi->setParameter("direction", op == CustomResolveOp::COMPRESS ? 1.0f : -1.0f),
|
||||
@@ -2586,7 +2582,7 @@ void PostProcessManager::customResolveSubpass(DriverApi& driver) noexcept {
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
|
||||
auto const& material = getPostProcessMaterial("customResolveAsSubpass");
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, driver);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine);
|
||||
// the UBO has been set and committed in customResolvePrepareSubpass()
|
||||
FMaterialInstance const* mi = mMaterialInstanceManager.getMaterialInstance(ma,
|
||||
mFixedMaterialInstanceIndex.customResolve);
|
||||
@@ -2627,7 +2623,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::customResolveUncompressPass(
|
||||
|
||||
void PostProcessManager::clearAncillaryBuffersPrepare(DriverApi& driver) noexcept {
|
||||
auto const& material = getPostProcessMaterial("clearDepth");
|
||||
auto ma = material.getMaterial(mEngine, driver, PostProcessVariant::OPAQUE);
|
||||
auto ma = material.getMaterial(mEngine, PostProcessVariant::OPAQUE);
|
||||
auto [mi, fixedIndex] = mMaterialInstanceManager.getFixedMaterialInstance(ma);
|
||||
mFixedMaterialInstanceIndex.clearDepth = fixedIndex;
|
||||
mi->commit(driver, getUboManager());
|
||||
@@ -2645,7 +2641,7 @@ void PostProcessManager::clearAncillaryBuffers(DriverApi& driver,
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
|
||||
auto const& material = getPostProcessMaterial("clearDepth");
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, driver);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine);
|
||||
|
||||
// the UBO has been set and committed in clearAncillaryBuffersPrepare()
|
||||
FMaterialInstance const* const mi = mMaterialInstanceManager.getMaterialInstance(ma,
|
||||
@@ -2749,7 +2745,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::colorGrading(FrameGraph& fg,
|
||||
|
||||
auto& material = getPostProcessMaterial("colorGrading");
|
||||
FMaterialInstance* const mi =
|
||||
configureColorGradingMaterial(driver, material, colorGrading, colorGradingConfig,
|
||||
configureColorGradingMaterial(material, colorGrading, colorGradingConfig,
|
||||
vignetteOptions, output.width, output.height);
|
||||
|
||||
mi->setParameter("colorBuffer", colorTexture, { /* shader uses texelFetch */ });
|
||||
@@ -2834,7 +2830,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::fxaa(FrameGraph& fg,
|
||||
PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE;
|
||||
|
||||
FMaterialInstance* const mi =
|
||||
getMaterialInstance(mEngine, driver, material, variant);
|
||||
getMaterialInstance(mEngine, material, variant);
|
||||
|
||||
mi->setParameter("colorBuffer", texture, SamplerParams{
|
||||
.filterMag = SamplerMagFilter::LINEAR,
|
||||
@@ -2909,10 +2905,10 @@ void PostProcessManager::TaaJitterCamera(
|
||||
inoutCameraInfo->clipTransform.zw -= jitterInClipSpace;
|
||||
}
|
||||
|
||||
void PostProcessManager::configureTemporalAntiAliasingMaterial(backend::DriverApi& driver,
|
||||
void PostProcessManager::configureTemporalAntiAliasingMaterial(
|
||||
TemporalAntiAliasingOptions const& taaOptions) noexcept {
|
||||
|
||||
FMaterial* const ma = getPostProcessMaterial("taa").getMaterial(mEngine, driver);
|
||||
FMaterial* const ma = getPostProcessMaterial("taa").getMaterial(mEngine);
|
||||
bool dirty = false;
|
||||
|
||||
setConstantParameter(ma, "upscaling", taaOptions.upscaling > 1.0f, dirty);
|
||||
@@ -2932,11 +2928,11 @@ void PostProcessManager::configureTemporalAntiAliasingMaterial(backend::DriverAp
|
||||
}
|
||||
}
|
||||
|
||||
FMaterialInstance* PostProcessManager::configureColorGradingMaterial(backend::DriverApi& driver,
|
||||
FMaterialInstance* PostProcessManager::configureColorGradingMaterial(
|
||||
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, driver);
|
||||
FMaterial* ma = material.getMaterial(mEngine);
|
||||
bool dirty = false;
|
||||
|
||||
setConstantParameter(ma, "isOneDimensional", colorGrading->isOneDimensional(), dirty);
|
||||
@@ -2951,7 +2947,7 @@ FMaterialInstance* PostProcessManager::configureColorGradingMaterial(backend::Dr
|
||||
PostProcessVariant const variant = colorGradingConfig.translucent
|
||||
? PostProcessVariant::TRANSLUCENT
|
||||
: PostProcessVariant::OPAQUE;
|
||||
ma = material.getMaterial(mEngine, driver, variant);
|
||||
ma = material.getMaterial(mEngine, variant);
|
||||
FMaterialInstance* mi = nullptr;
|
||||
int32_t& fixedIndex = colorGradingConfig.translucent
|
||||
? mFixedMaterialInstanceIndex.colorGradingTranslucent
|
||||
@@ -3068,7 +3064,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::taa(FrameGraph& fg,
|
||||
PostProcessVariant const variant = colorGradingConfig.translucent ?
|
||||
PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE;
|
||||
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, driver, variant);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, variant);
|
||||
|
||||
FMaterialInstance* mi = getMaterialInstance(ma);
|
||||
mi->setParameter("color", color, SamplerParams{}); // nearest
|
||||
@@ -3180,7 +3176,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::rcas(
|
||||
|
||||
auto const& material = getPostProcessMaterial("fsr_rcas");
|
||||
FMaterialInstance* const mi =
|
||||
getMaterialInstance(mEngine, driver, material, variant);
|
||||
getMaterialInstance(mEngine, material, variant);
|
||||
|
||||
FSRUniforms uniforms;
|
||||
FSR_SharpeningSetup(&uniforms, { .sharpness = 2.0f - 2.0f * sharpness });
|
||||
@@ -3192,7 +3188,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::rcas(
|
||||
mi->commit(driver, getUboManager());
|
||||
mi->use(driver);
|
||||
|
||||
auto pipeline = getPipelineState(material.getMaterial(mEngine, driver), variant);
|
||||
auto pipeline = getPipelineState(material.getMaterial(mEngine), variant);
|
||||
if (mode == RcasMode::BLENDED) {
|
||||
pipeline.rasterState.blendFunctionSrcRGB = BlendFunction::ONE;
|
||||
pipeline.rasterState.blendFunctionSrcAlpha = BlendFunction::ONE;
|
||||
@@ -3267,7 +3263,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleBilinear(FrameGraph&
|
||||
|
||||
auto& material = getPostProcessMaterial("blitLow");
|
||||
FMaterialInstance* const mi =
|
||||
getMaterialInstance(mEngine, driver, material);
|
||||
getMaterialInstance(mEngine, material);
|
||||
mi->setParameter("color", color, SamplerParams{
|
||||
.filterMag = filter
|
||||
});
|
||||
@@ -3285,7 +3281,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleBilinear(FrameGraph&
|
||||
|
||||
auto out = resources.getRenderPassInfo();
|
||||
|
||||
auto pipeline = getPipelineState(material.getMaterial(mEngine, driver));
|
||||
auto pipeline = getPipelineState(material.getMaterial(mEngine));
|
||||
if (blended) {
|
||||
pipeline.rasterState.blendFunctionSrcRGB = BlendFunction::ONE;
|
||||
pipeline.rasterState.blendFunctionSrcAlpha = BlendFunction::ONE;
|
||||
@@ -3344,7 +3340,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleSGSR1(FrameGraph& fg,
|
||||
PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE;
|
||||
|
||||
FMaterialInstance* const mi =
|
||||
getMaterialInstance(mEngine, driver, material, variant);
|
||||
getMaterialInstance(mEngine, material, variant);
|
||||
|
||||
mi->setParameter("color", color, SamplerParams{
|
||||
// The SGSR documentation doesn't clarify if LINEAR or NEAREST should be used. The
|
||||
@@ -3454,7 +3450,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleFSR1(FrameGraph& fg,
|
||||
if (twoPassesEASU) {
|
||||
splitEasuMaterial = &getPostProcessMaterial("fsr_easu_mobileF");
|
||||
FMaterialInstance* const mi =
|
||||
getMaterialInstance(mEngine, driver, *splitEasuMaterial);
|
||||
getMaterialInstance(mEngine, *splitEasuMaterial);
|
||||
setEasuUniforms(mi, inputDesc, outputDesc);
|
||||
mi->setParameter("color", color, SamplerParams{
|
||||
.filterMag = SamplerMagFilter::LINEAR
|
||||
@@ -3471,7 +3467,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, driver, *easuMaterial);
|
||||
getMaterialInstance(mEngine, *easuMaterial);
|
||||
|
||||
setEasuUniforms(mi, inputDesc, outputDesc);
|
||||
|
||||
@@ -3499,15 +3495,15 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleFSR1(FrameGraph& fg,
|
||||
auto out = resources.getRenderPassInfo();
|
||||
|
||||
if (UTILS_UNLIKELY(twoPassesEASU)) {
|
||||
auto pipeline0 = getPipelineState(splitEasuMaterial->getMaterial(mEngine, driver));
|
||||
auto pipeline1 = getPipelineState(easuMaterial->getMaterial(mEngine, driver));
|
||||
auto pipeline0 = getPipelineState(splitEasuMaterial->getMaterial(mEngine));
|
||||
auto pipeline1 = getPipelineState(easuMaterial->getMaterial(mEngine));
|
||||
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, driver));
|
||||
auto pipeline = getPipelineState(easuMaterial->getMaterial(mEngine));
|
||||
renderFullScreenQuad(out, pipeline, driver);
|
||||
}
|
||||
unbindAllDescriptorSets(driver);
|
||||
@@ -3559,7 +3555,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::blit(FrameGraph& fg, bool co
|
||||
|
||||
PostProcessMaterial const& material =
|
||||
getPostProcessMaterial(layer ? "blitArray" : "blitLow");
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, driver);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine);
|
||||
auto* mi = getMaterialInstance(ma);
|
||||
mi->setParameter("color", color, SamplerParams{
|
||||
.filterMag = filterMag,
|
||||
@@ -3596,7 +3592,8 @@ 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 = mDepthStencilBlitSupported;
|
||||
bool const hardwareBlitSupported =
|
||||
mEngine.getDriverApi().isDepthStencilBlitSupported(inputDesc.format);
|
||||
|
||||
struct BlitData {
|
||||
FrameGraphId<FrameGraphTexture> input;
|
||||
@@ -3659,7 +3656,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::blitDepth(FrameGraph& fg,
|
||||
// set uniforms
|
||||
PostProcessMaterial const& material = getPostProcessMaterial("blitDepth");
|
||||
FMaterialInstance* const mi =
|
||||
getMaterialInstance(mEngine, driver, material);
|
||||
getMaterialInstance(mEngine, material);
|
||||
mi->setParameter("depth", depth, SamplerParams {
|
||||
.filterMag = SamplerMagFilter::NEAREST,
|
||||
.filterMin = SamplerMinFilter::NEAREST,
|
||||
@@ -3686,7 +3683,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::resolve(FrameGraph& fg,
|
||||
}
|
||||
|
||||
// The Metal / Vulkan backends currently don't support depth/stencil resolve.
|
||||
if (isDepthFormat(inDesc.format) && (!mDepthStencilResolveSupported)) {
|
||||
if (isDepthFormat(inDesc.format) && (!mEngine.getDriverApi().isDepthStencilResolveSupported())) {
|
||||
return resolveDepth(fg, outputBufferName, input, outDesc);
|
||||
}
|
||||
|
||||
@@ -3772,7 +3769,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::resolveDepth(FrameGraph& fg,
|
||||
auto const& input = resources.getTexture(data.input);
|
||||
auto const& material = getPostProcessMaterial("resolveDepth");
|
||||
FMaterialInstance* const mi =
|
||||
getMaterialInstance(mEngine, driver, material);
|
||||
getMaterialInstance(mEngine, material);
|
||||
mi->setParameter("depth", input, SamplerParams{}); // NEAREST
|
||||
commitAndRenderFullScreenQuad(driver, resources.getRenderPassInfo(), mi);
|
||||
unbindAllDescriptorSets(driver);
|
||||
@@ -3818,7 +3815,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::vsmMipmapPass(FrameGraph& fg
|
||||
int const dim = width >> (level + 1);
|
||||
|
||||
auto& material = getPostProcessMaterial("vsmMipmap");
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, driver);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine);
|
||||
|
||||
// When generating shadow map mip levels, we want to preserve the 1 texel border.
|
||||
// (note clearing never respects the scissor in Filament)
|
||||
@@ -3870,7 +3867,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::debugShadowCascades(FrameGra
|
||||
auto const out = resources.getRenderPassInfo();
|
||||
auto const& material = getPostProcessMaterial("debugShadowCascades");
|
||||
FMaterialInstance* const mi =
|
||||
getMaterialInstance(mEngine, driver, material);
|
||||
getMaterialInstance(mEngine, material);
|
||||
mi->setParameter("color", color, SamplerParams{}); // nearest
|
||||
mi->setParameter("depth", depth, SamplerParams{}); // nearest
|
||||
commitAndRenderFullScreenQuad(driver, out, mi);
|
||||
@@ -3920,7 +3917,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::debugCombineArrayTexture(Fra
|
||||
// set uniforms
|
||||
|
||||
PostProcessMaterial const& material = getPostProcessMaterial("blitArray");
|
||||
FMaterial const* const ma = material.getMaterial(mEngine, driver);
|
||||
FMaterial const* const ma = material.getMaterial(mEngine);
|
||||
// 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);
|
||||
@@ -3998,7 +3995,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, driver, material);
|
||||
FMaterialInstance* const mi = getMaterialInstance(mEngine, 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(backend::DriverApi& driver,
|
||||
void configureTemporalAntiAliasingMaterial(
|
||||
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, backend::DriverApi& driver,
|
||||
FMaterial* getMaterial(FEngine& engine,
|
||||
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(backend::DriverApi& driver,
|
||||
FMaterialInstance* configureColorGradingMaterial(
|
||||
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, backend::DriverApi& driver, PostProcessMaterial const& material,
|
||||
FMaterialInstance* getMaterialInstance(FEngine& engine, PostProcessMaterial const& material,
|
||||
PostProcessVariant variant = PostProcessVariant::OPAQUE) {
|
||||
FMaterial const* ma = material.getMaterial(engine, driver, variant);
|
||||
FMaterial const* ma = material.getMaterial(engine, variant);
|
||||
return getMaterialInstance(ma);
|
||||
}
|
||||
|
||||
@@ -438,9 +438,6 @@ 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, backend::DriverApi& driver) const {
|
||||
RenderPass RenderPassBuilder::build(FEngine const& engine) const {
|
||||
assert_invariant(mRenderableSoa);
|
||||
return RenderPass{ engine, driver, *this };
|
||||
return RenderPass{ engine, *this };
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -105,7 +105,7 @@ void RenderPass::DescriptorSetHandleDeleter::operator()(DescriptorSetHandle hand
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
RenderPass::RenderPass(FEngine const& engine, backend::DriverApi& driver,
|
||||
RenderPass::RenderPass(FEngine const& engine,
|
||||
RenderPassBuilder const& builder) noexcept
|
||||
: mRenderableSoa(*builder.mRenderableSoa),
|
||||
mColorPassDescriptorSet(builder.mColorPassDescriptorSet) {
|
||||
@@ -139,7 +139,7 @@ RenderPass::RenderPass(FEngine const& engine, backend::DriverApi& driver,
|
||||
}
|
||||
}
|
||||
|
||||
appendCommands(engine, driver, { commandBegin, commandCount },
|
||||
appendCommands(engine, { 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, backend::DriverApi& driver,
|
||||
void RenderPass::appendCommands(FEngine const& engine,
|
||||
Slice<Command> commands,
|
||||
Range<uint32_t> const visibleRenderables,
|
||||
CommandTypeFlags const commandTypeFlags,
|
||||
@@ -244,7 +244,7 @@ void RenderPass::appendCommands(FEngine const& engine, backend::DriverApi& drive
|
||||
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(driver, first->info.materialVariant, CompilerPriorityQueue::CRITICAL);
|
||||
ma->prepareProgram(first->info.materialVariant, CompilerPriorityQueue::CRITICAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -416,12 +416,11 @@ public:
|
||||
private:
|
||||
friend class FRenderer;
|
||||
friend class RenderPassBuilder;
|
||||
friend class RenderPassBuilder;
|
||||
RenderPass(FEngine const& engine, backend::DriverApi& driver, RenderPassBuilder const& builder) noexcept;
|
||||
RenderPass(FEngine const& engine, 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, backend::DriverApi& driver,
|
||||
void appendCommands(FEngine const& engine,
|
||||
utils::Slice<Command> commands,
|
||||
utils::Range<uint32_t> visibleRenderables,
|
||||
CommandTypeFlags commandTypeFlags,
|
||||
@@ -581,7 +580,7 @@ public:
|
||||
uint32_t order,
|
||||
const RenderPass::Executor::CustomCommandFn& command);
|
||||
|
||||
RenderPass build(FEngine const& engine, backend::DriverApi& driver) const;
|
||||
RenderPass build(FEngine const& engine) const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ void Renderer::resetUserTime() {
|
||||
downcast(this)->resetUserTime();
|
||||
}
|
||||
|
||||
void Renderer::skipNextFrames(size_t frameCount) noexcept {
|
||||
void Renderer::skipNextFrames(size_t frameCount) const noexcept {
|
||||
downcast(this)->skipNextFrames(frameCount);
|
||||
}
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ RendererUtils::ColorPassOutput RendererUtils::colorPass(
|
||||
data.color = builder.createTexture("Color Buffer", colorBufferDesc);
|
||||
}
|
||||
|
||||
const bool canAutoResolveDepth = config.isAutoDepthResolveSupported;
|
||||
const bool canAutoResolveDepth = engine.getDriverApi().isAutoDepthResolveSupported();
|
||||
|
||||
FrameGraphTexture::Usage depthStencilUsage = FrameGraphTexture::Usage::DEPTH_ATTACHMENT;
|
||||
|
||||
@@ -124,7 +124,7 @@ RendererUtils::ColorPassOutput RendererUtils::colorPass(
|
||||
utils::StaticString{"Depth Buffer"};
|
||||
|
||||
bool const isES2 =
|
||||
config.featureLevel == FeatureLevel::FEATURE_LEVEL_0;
|
||||
engine.getDriverApi().getFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0;
|
||||
|
||||
TextureFormat const stencilFormat = isES2 ?
|
||||
TextureFormat::DEPTH24_STENCIL8 : TextureFormat::DEPTH32F_STENCIL8;
|
||||
|
||||
@@ -71,10 +71,6 @@ 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,8 +73,7 @@ using namespace backend;
|
||||
using namespace math;
|
||||
|
||||
ShadowMapManager::ShadowMapManager(FEngine& engine)
|
||||
: mIsDepthClampSupported(engine.getDriverApi().isDepthClampSupported()),
|
||||
mDisableBlitIntoTextureArray(engine.getDriverApi().isWorkaroundNeeded(Workaround::DISABLE_BLIT_INTO_TEXTURE_ARRAY)) {
|
||||
: mIsDepthClampSupported(engine.getDriverApi().isDepthClampSupported()) {
|
||||
FDebugRegistry& debugRegistry = engine.getDebugRegistry();
|
||||
debugRegistry.registerProperty("d.shadowmap.visualize_cascades",
|
||||
&engine.debug.shadowmap.visualize_cascades);
|
||||
@@ -126,7 +125,6 @@ void ShadowMapManager::terminate(FEngine& engine) {
|
||||
}
|
||||
|
||||
ShadowMapManager::ShadowTechnique ShadowMapManager::update(
|
||||
DriverApi& driver,
|
||||
Builder const& builder,
|
||||
FEngine& engine, FView& view,
|
||||
CameraInfo const& cameraInfo,
|
||||
@@ -141,7 +139,7 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::update(
|
||||
if (UTILS_UNLIKELY(!mInitialized)) {
|
||||
mInitialized = true;
|
||||
// initialize our ShadowMap array in-place
|
||||
mShadowUbh = driver.createBufferObject(mShadowUb.getSize(),
|
||||
mShadowUbh = engine.getDriverApi().createBufferObject(mShadowUb.getSize(),
|
||||
BufferObjectBinding::UNIFORM, BufferUsage::DYNAMIC);
|
||||
UTILS_NOUNROLL
|
||||
for (auto& entry: mShadowMapCache) {
|
||||
@@ -423,7 +421,7 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
|
||||
.visibilityMask(entry.visibilityMask)
|
||||
.geometry(scene->getRenderableData(), entry.range)
|
||||
.commandTypeFlags(RenderPass::CommandTypeFlags::SHADOW)
|
||||
.build(engine, driver);
|
||||
.build(engine);
|
||||
|
||||
pass.finalize(engine, driver);
|
||||
|
||||
@@ -1087,7 +1085,7 @@ void ShadowMapManager::calculateTextureRequirements(FEngine& engine, FView& view
|
||||
((vsmShadowOptions.anisotropy > 0) || vsmShadowOptions.mipmapping);
|
||||
|
||||
uint8_t msaaSamples = vsmShadowOptions.msaaSamples;
|
||||
if (mDisableBlitIntoTextureArray) {
|
||||
if (engine.getDriverApi().isWorkaroundNeeded(Workaround::DISABLE_BLIT_INTO_TEXTURE_ARRAY)) {
|
||||
msaaSamples = 1;
|
||||
}
|
||||
|
||||
@@ -1115,7 +1113,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(backend::DriverApi& driver,
|
||||
Builder const& builder, FEngine& engine,
|
||||
FView& view,
|
||||
CameraInfo const& cameraInfo, FScene::RenderableSoa& renderableData, FScene::LightSoa const& lightData) noexcept;
|
||||
ShadowTechnique update(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,7 +238,6 @@ 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 = typename std::iterator_traits<Iterator>::value_type;
|
||||
using value_type = std::iterator_traits<Iterator>::value_type;
|
||||
|
||||
while (src != last) {
|
||||
// Find the end of the current run.
|
||||
|
||||
@@ -39,21 +39,20 @@
|
||||
#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 <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 <private/utils/Tracing.h>
|
||||
|
||||
#include <utils/Allocator.h>
|
||||
#include <utils/CallStack.h>
|
||||
#include <utils/CString.h>
|
||||
@@ -61,7 +60,6 @@
|
||||
#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>
|
||||
@@ -100,9 +98,8 @@ using namespace filaflat;
|
||||
|
||||
namespace {
|
||||
|
||||
Platform::DriverConfig getDriverConfig(FEngine* instance) {
|
||||
Platform::DriverConfig const driverConfig {
|
||||
.featureFlagManager = instance,
|
||||
backend::Platform::DriverConfig getDriverConfig(FEngine* instance) {
|
||||
Platform::DriverConfig driverConfig {
|
||||
.handleArenaSize = instance->getRequestedDriverHandleArenaSize(),
|
||||
.metalUploadBufferSizeBytes = instance->getConfig().metalUploadBufferSizeBytes,
|
||||
.disableParallelShaderCompile = instance->features.backend.disable_parallel_shader_compile,
|
||||
@@ -277,19 +274,10 @@ 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(utils::CString(name)) == builder->mFeatureFlags.end()) {
|
||||
if (builder->mFeatureFlags.find(name) == builder->mFeatureFlags.end()) {
|
||||
auto* const p = getFeatureFlagPtr(name, true);
|
||||
if (p) {
|
||||
*p = value;
|
||||
@@ -297,6 +285,14 @@ 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);
|
||||
@@ -720,11 +716,12 @@ void FEngine::shutdown() {
|
||||
mJobSystem.emancipate();
|
||||
}
|
||||
|
||||
void FEngine::prepare(DriverApi& driver) {
|
||||
void FEngine::prepare() {
|
||||
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) {
|
||||
@@ -734,7 +731,7 @@ void FEngine::prepare(DriverApi& driver) {
|
||||
|
||||
UboManager* uboManager = mUboManager;
|
||||
for (auto& materialInstanceList: mMaterialInstances) {
|
||||
materialInstanceList.second.forEach([&driver, uboManager](FMaterialInstance const* item) {
|
||||
materialInstanceList.second.forEach([&driver, uboManager](FMaterialInstance* 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) {
|
||||
@@ -745,7 +742,7 @@ void FEngine::prepare(DriverApi& driver) {
|
||||
|
||||
if (useUboBatching) {
|
||||
assert_invariant(mUboManager != nullptr);
|
||||
getUboManager()->finishBeginFrame(driver);
|
||||
getUboManager()->finishBeginFrame(getDriverApi());
|
||||
}
|
||||
|
||||
mMaterials.forEach([](FMaterial* material) {
|
||||
@@ -861,7 +858,13 @@ int FEngine::loop() {
|
||||
#endif
|
||||
if (fgviewerPortString != nullptr) {
|
||||
const int fgviewerPort = atoi(fgviewerPortString);
|
||||
debug.fgviewerServer = new fgviewer::DebugServer(fgviewerPort);
|
||||
debug.fgviewerServer = new fgviewer::DebugServer(fgviewerPort,
|
||||
fgviewer::DebugServer::ReadbackRequest([this](utils::CString name,
|
||||
std::function<void(fgviewer::DebugServer::PixelBuffer,
|
||||
uint32_t, uint32_t,
|
||||
fgviewer::DebugServer::PixelDataFormat)> callback) {
|
||||
requestTextureReadback(name, std::move(callback));
|
||||
}));
|
||||
|
||||
// Sometimes the server can fail to spin up (e.g. if the above port is already in use).
|
||||
// When this occurs, carry onward, developers can look at civetweb.txt for details.
|
||||
@@ -1459,7 +1462,7 @@ AsyncCallId FEngine::runCommandAsync(Invocable<void()>&& command,
|
||||
AsyncCompletionCallback userCallback;
|
||||
void* userParam;
|
||||
static void func(void* wrappedData) {
|
||||
auto const* const data = static_cast<RunCommandAsyncCallback*>(wrappedData);
|
||||
auto* const data = static_cast<RunCommandAsyncCallback*>(wrappedData);
|
||||
data->userCallback(data->userParam);
|
||||
delete data;
|
||||
}
|
||||
@@ -1553,26 +1556,30 @@ void FEngine::unprotected() noexcept {
|
||||
mUnprotectedDummySwapchain->makeCurrent(getDriverApi());
|
||||
}
|
||||
|
||||
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);
|
||||
bool FEngine::setFeatureFlag(char const* name, bool const value) const noexcept {
|
||||
auto* const p = getFeatureFlagPtr(name);
|
||||
if (p) {
|
||||
*p = value;
|
||||
}
|
||||
return p != nullptr;
|
||||
}
|
||||
|
||||
std::optional<bool> FEngine::getFeatureFlag(char const* name) const noexcept {
|
||||
return FeatureFlagManager::getFeatureFlag(name);
|
||||
auto* const p = getFeatureFlagPtr(name, true);
|
||||
if (p) {
|
||||
return *p;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool* FEngine::getFeatureFlagPtr(std::string_view name, bool const allowConstant) const noexcept {
|
||||
return FeatureFlagManager::getFeatureFlagPtr(name, allowConstant);
|
||||
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;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -1677,4 +1684,13 @@ Engine::Config Engine::BuilderDetails::validateConfig(Config config) noexcept {
|
||||
return config;
|
||||
}
|
||||
|
||||
#if FILAMENT_ENABLE_FGVIEWER
|
||||
void FEngine::requestTextureReadback(const CString& name,
|
||||
std::function<void(fgviewer::DebugServer::PixelBuffer, uint32_t, uint32_t,
|
||||
fgviewer::DebugServer::PixelDataFormat)>&& callback) {
|
||||
std::unique_lock<utils::Mutex> lock(mReadbackRequestsMutex);
|
||||
mReadbackRequests.emplace_back(ReadbackRequest{ name, std::move(callback) });
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace filament
|
||||
|
||||
+151
-16
@@ -47,14 +47,12 @@
|
||||
#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/backend/CommandBufferQueue.h>
|
||||
#include <private/backend/CommandStream.h>
|
||||
#include <private/backend/DriverApi.h>
|
||||
|
||||
#include <private/utils/FeatureFlagManager.h>
|
||||
#include <private/filament/BufferInterfaceBlock.h>
|
||||
|
||||
#include <filament/ColorGrading.h>
|
||||
#include <filament/Engine.h>
|
||||
@@ -72,10 +70,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>
|
||||
@@ -86,9 +84,6 @@
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if FILAMENT_ENABLE_MATDBG
|
||||
#include <matdbg/DebugServer.h>
|
||||
#else
|
||||
@@ -106,6 +101,14 @@ 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;
|
||||
@@ -131,7 +134,8 @@ class TextureCache;
|
||||
* Concrete implementation of the Engine interface. This keeps track of all hardware resources
|
||||
* for a given context.
|
||||
*/
|
||||
class FEngine : public Engine, public utils::FeatureFlagManager {
|
||||
class FEngine : public Engine {
|
||||
friend class FRenderer;
|
||||
public:
|
||||
void* operator new(std::size_t const size) noexcept {
|
||||
return utils::aligned_alloc(size, alignof(FEngine));
|
||||
@@ -455,7 +459,7 @@ public:
|
||||
return mPlatform->pumpEvents();
|
||||
}
|
||||
|
||||
void prepare(backend::DriverApi& driver);
|
||||
void prepare();
|
||||
void gc();
|
||||
void submitFrame();
|
||||
|
||||
@@ -569,10 +573,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;
|
||||
#if FILAMENT_ENABLE_FGVIEWER
|
||||
void requestTextureReadback(utils::CString const& name,
|
||||
std::function<void(fgviewer::DebugServer::PixelBuffer, uint32_t, uint32_t,
|
||||
fgviewer::DebugServer::PixelDataFormat)>&& callback);
|
||||
#endif
|
||||
|
||||
private:
|
||||
explicit FEngine(Builder const& builder);
|
||||
@@ -705,6 +710,17 @@ private:
|
||||
|
||||
bool mInitialized = false;
|
||||
|
||||
#if FILAMENT_ENABLE_FGVIEWER
|
||||
struct ReadbackRequest {
|
||||
using Callback = std::function<void(fgviewer::DebugServer::PixelBuffer, uint32_t, uint32_t,
|
||||
fgviewer::DebugServer::PixelDataFormat)>;
|
||||
utils::CString name;
|
||||
Callback callback;
|
||||
};
|
||||
utils::Mutex mReadbackRequestsMutex;
|
||||
std::vector<ReadbackRequest> mReadbackRequests;
|
||||
#endif
|
||||
|
||||
// Creation parameters
|
||||
Config mConfig;
|
||||
|
||||
@@ -754,6 +770,125 @@ 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,6 +28,7 @@
|
||||
#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>
|
||||
@@ -39,7 +40,6 @@
|
||||
|
||||
#include <filaflat/ChunkContainer.h>
|
||||
|
||||
#include <backend/DriverApiForward.h>
|
||||
#include <backend/DriverEnums.h>
|
||||
#include <backend/CallbackHandler.h>
|
||||
#include <backend/Program.h>
|
||||
@@ -51,6 +51,7 @@
|
||||
#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>
|
||||
@@ -165,20 +166,10 @@ 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(driver);
|
||||
precacheDepthVariants(engine);
|
||||
|
||||
#if FILAMENT_ENABLE_MATDBG
|
||||
// Register the material with matdbg.
|
||||
@@ -284,10 +275,11 @@ backend::DescriptorSetLayout const& FMaterial::getDescriptorSetLayoutDescription
|
||||
if (!isSharedVariant(variant)) {
|
||||
return mDefinition.descriptorSetLayoutDescription;
|
||||
}
|
||||
if (UTILS_UNLIKELY(!mDefaultMaterial)) {
|
||||
FMaterial const* const pDefaultMaterial = mEngine.getDefaultMaterial();
|
||||
if (UTILS_UNLIKELY(!pDefaultMaterial)) {
|
||||
return mDefinition.descriptorSetLayoutDescription;
|
||||
}
|
||||
return mDefaultMaterial->getDescriptorSetLayoutDescription();
|
||||
return pDefaultMaterial->getDescriptorSetLayoutDescription();
|
||||
}
|
||||
|
||||
void FMaterial::compile(CompilerPriorityQueue const priority,
|
||||
@@ -295,23 +287,21 @@ 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 (!mIsStereoSupported) {
|
||||
if (!mEngine.getDriverApi().isStereoSupported()) {
|
||||
variantSpec &= ~UserVariantFilterMask(UserVariantFilterBit::STE);
|
||||
}
|
||||
|
||||
UserVariantFilterMask const variantFilter =
|
||||
~variantSpec & UserVariantFilterMask(UserVariantFilterBit::ALL);
|
||||
|
||||
if (UTILS_LIKELY(mIsParallelShaderCompileSupported)) {
|
||||
if (UTILS_LIKELY(mEngine.getDriverApi().isParallelShaderCompileSupported())) {
|
||||
auto const& variants = isVariantLit() ?
|
||||
VariantUtils::getLitVariants() : VariantUtils::getUnlitVariants();
|
||||
for (auto const variant: variants) {
|
||||
if (!variantFilter || variant == Variant::filterUserVariant(variant, variantFilter)) {
|
||||
if (hasVariant(variant)) {
|
||||
prepareProgram(driver, variant, priority);
|
||||
prepareProgram(variant, priority);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -328,9 +318,9 @@ void FMaterial::compile(CompilerPriorityQueue const priority,
|
||||
}
|
||||
};
|
||||
auto* const user = new(std::nothrow) Callback{ std::move(callback), this };
|
||||
driver.compilePrograms(priority, handler, &Callback::func, user);
|
||||
mEngine.getDriverApi().compilePrograms(priority, handler, &Callback::func, user);
|
||||
} else {
|
||||
driver.compilePrograms(priority, nullptr, nullptr, nullptr);
|
||||
mEngine.getDriverApi().compilePrograms(priority, nullptr, nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -401,15 +391,15 @@ bool FMaterial::hasVariant(Variant const variant) const noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
void FMaterial::prepareProgramSlow(DriverApi& driver, Variant const variant,
|
||||
void FMaterial::prepareProgramSlow(Variant const variant,
|
||||
backend::CompilerPriorityQueue const priorityQueue) const noexcept {
|
||||
assert_invariant(mEngine.hasFeatureLevel(mDefinition.featureLevel));
|
||||
switch (getMaterialDomain()) {
|
||||
case MaterialDomain::SURFACE:
|
||||
getSurfaceProgramSlow(driver, variant, priorityQueue);
|
||||
getSurfaceProgramSlow(variant, priorityQueue);
|
||||
break;
|
||||
case MaterialDomain::POST_PROCESS:
|
||||
getPostProcessProgramSlow(driver, variant, priorityQueue);
|
||||
getPostProcessProgramSlow(variant, priorityQueue);
|
||||
break;
|
||||
case MaterialDomain::COMPUTE:
|
||||
// TODO: implement MaterialDomain::COMPUTE
|
||||
@@ -417,7 +407,7 @@ void FMaterial::prepareProgramSlow(DriverApi& driver, Variant const variant,
|
||||
}
|
||||
}
|
||||
|
||||
void FMaterial::getSurfaceProgramSlow(DriverApi& driver, Variant const variant,
|
||||
void FMaterial::getSurfaceProgramSlow(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
|
||||
@@ -433,14 +423,14 @@ void FMaterial::getSurfaceProgramSlow(DriverApi& driver, Variant const variant,
|
||||
pb.multiview(
|
||||
mEngine.getConfig().stereoscopicType == StereoscopicType::MULTIVIEW &&
|
||||
Variant::isStereoVariant(variant));
|
||||
createAndCacheProgram(driver, std::move(pb), variant);
|
||||
createAndCacheProgram(std::move(pb), variant);
|
||||
}
|
||||
|
||||
void FMaterial::getPostProcessProgramSlow(DriverApi& driver, Variant const variant,
|
||||
void FMaterial::getPostProcessProgramSlow(Variant const variant,
|
||||
CompilerPriorityQueue const priorityQueue) const noexcept {
|
||||
Program pb{ getProgramWithVariants(variant, variant, variant) };
|
||||
pb.priorityQueue(priorityQueue);
|
||||
createAndCacheProgram(driver, std::move(pb), variant);
|
||||
createAndCacheProgram(std::move(pb), variant);
|
||||
}
|
||||
|
||||
Program FMaterial::getProgramWithVariants(
|
||||
@@ -487,7 +477,7 @@ Program FMaterial::getProgramWithVariants(
|
||||
.shader(ShaderStage::FRAGMENT, fsBuilder.data(), fsBuilder.size())
|
||||
.shaderLanguage(parser.getShaderLanguage())
|
||||
.diagnostics(mDefinition.name,
|
||||
[variant, vertexVariant, fragmentVariant](CString const& name,
|
||||
[variant, vertexVariant, fragmentVariant](utils::CString const& name,
|
||||
io::ostream& out) -> io::ostream& {
|
||||
return out << name.c_str_safe() << ", variant=(" << io::hex << +variant.key
|
||||
<< io::dec << "), vertexVariant=(" << io::hex
|
||||
@@ -521,13 +511,17 @@ Program FMaterial::getProgramWithVariants(
|
||||
return program;
|
||||
}
|
||||
|
||||
void FMaterial::createAndCacheProgram(DriverApi& driver, Program&& p, Variant const variant) const noexcept {
|
||||
void FMaterial::createAndCacheProgram(Program&& p, Variant const variant) const noexcept {
|
||||
FEngine const& engine = mEngine;
|
||||
DriverApi& driverApi = mEngine.getDriverApi();
|
||||
|
||||
bool const isShared = isSharedVariant(variant);
|
||||
|
||||
// Check if the default material has this program cached
|
||||
if (isShared) {
|
||||
if (mDefaultMaterial) {
|
||||
auto const program = mDefaultMaterial->mCachedPrograms[variant.key];
|
||||
FMaterial const* const pDefaultMaterial = engine.getDefaultMaterial();
|
||||
if (pDefaultMaterial) {
|
||||
auto const program = pDefaultMaterial->mCachedPrograms[variant.key];
|
||||
if (program) {
|
||||
mCachedPrograms[variant.key] = program;
|
||||
return;
|
||||
@@ -545,7 +539,7 @@ void FMaterial::createAndCacheProgram(DriverApi& driver, Program&& p, Variant co
|
||||
p.descriptorLayout(+DescriptorSetBindingPoints::PER_MATERIAL,
|
||||
getDescriptorSetLayoutDescription(variant));
|
||||
|
||||
auto const program = driver.createProgram(std::move(p),
|
||||
auto const program = driverApi.createProgram(std::move(p),
|
||||
ImmutableCString{ mDefinition.name.c_str_safe() });
|
||||
assert_invariant(program);
|
||||
mCachedPrograms[variant.key] = program;
|
||||
@@ -554,8 +548,9 @@ void FMaterial::createAndCacheProgram(DriverApi& driver, Program&& p, Variant co
|
||||
// are met (Surface Domain and no custom depth shader), cache it now.
|
||||
// New Materials will inherit these program automatically.
|
||||
if (isShared) {
|
||||
if (mDefaultMaterial && !mDefaultMaterial->mCachedPrograms[variant.key]) {
|
||||
mDefaultMaterial->mCachedPrograms[variant.key] = program;
|
||||
FMaterial const* const pDefaultMaterial = engine.getDefaultMaterial();
|
||||
if (pDefaultMaterial && !pDefaultMaterial->mCachedPrograms[variant.key]) {
|
||||
pDefaultMaterial->mCachedPrograms[variant.key] = program;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -843,16 +838,17 @@ FMaterial::processSpecializationConstants(Builder const& builder) {
|
||||
return specializationConstants;
|
||||
}
|
||||
|
||||
void FMaterial::precacheDepthVariants(DriverApi& driver) {
|
||||
void FMaterial::precacheDepthVariants(FEngine& engine) {
|
||||
|
||||
bool const disableDepthPrecacheForDefaultMaterial = mDepthPrecacheDisabled;
|
||||
bool const disableDepthPrecacheForDefaultMaterial = engine.getDriverApi().isWorkaroundNeeded(
|
||||
Workaround::DISABLE_DEPTH_PRECACHE_FOR_DEFAULT_MATERIAL);
|
||||
|
||||
// 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 = driver.isStereoSupported();
|
||||
const bool stereoSupported = mEngine.getDriverApi().isStereoSupported();
|
||||
auto const allDepthVariants = VariantUtils::getDepthVariants();
|
||||
for (auto const variant: allDepthVariants) {
|
||||
// Don't precache any stereo variants if stereo is not supported.
|
||||
@@ -861,7 +857,7 @@ void FMaterial::precacheDepthVariants(DriverApi& driver) {
|
||||
}
|
||||
assert_invariant(Variant::isValidDepthVariant(variant));
|
||||
if (hasVariant(variant)) {
|
||||
prepareProgram(driver, variant, CompilerPriorityQueue::HIGH);
|
||||
prepareProgram(variant, CompilerPriorityQueue::HIGH);
|
||||
}
|
||||
}
|
||||
return;
|
||||
@@ -871,11 +867,12 @@ void FMaterial::precacheDepthVariants(DriverApi& driver) {
|
||||
if (mDefinition.materialDomain == MaterialDomain::SURFACE &&
|
||||
!mIsDefaultMaterial &&
|
||||
!mDefinition.hasCustomDepthShader) {
|
||||
assert_invariant(mDefaultMaterial);
|
||||
FMaterial const* const pDefaultMaterial = engine.getDefaultMaterial();
|
||||
assert_invariant(pDefaultMaterial);
|
||||
auto const allDepthVariants = VariantUtils::getDepthVariants();
|
||||
for (auto const variant: allDepthVariants) {
|
||||
assert_invariant(Variant::isValidDepthVariant(variant));
|
||||
mCachedPrograms[variant.key] = mDefaultMaterial->mCachedPrograms[variant.key];
|
||||
mCachedPrograms[variant.key] = pDefaultMaterial->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(backend::DriverApi& driver, Variant const variant,
|
||||
void prepareProgram(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(driver, variant, priorityQueue);
|
||||
prepareProgramSlow(variant, priorityQueue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,11 +292,11 @@ private:
|
||||
MaterialParser const& getMaterialParser() const noexcept;
|
||||
|
||||
bool hasVariant(Variant variant) const noexcept;
|
||||
void prepareProgramSlow(backend::DriverApi& driver, Variant variant,
|
||||
void prepareProgramSlow(Variant variant,
|
||||
CompilerPriorityQueue priorityQueue) const noexcept;
|
||||
void getSurfaceProgramSlow(backend::DriverApi& driver, Variant variant,
|
||||
void getSurfaceProgramSlow(Variant variant,
|
||||
CompilerPriorityQueue priorityQueue) const noexcept;
|
||||
void getPostProcessProgramSlow(backend::DriverApi& driver, Variant variant,
|
||||
void getPostProcessProgramSlow(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(backend::DriverApi& driver);
|
||||
void precacheDepthVariants(FEngine& engine);
|
||||
|
||||
void createAndCacheProgram(backend::DriverApi& driver, backend::Program&& p, Variant variant) const noexcept;
|
||||
void createAndCacheProgram(backend::Program&& p, Variant variant) const noexcept;
|
||||
|
||||
backend::DescriptorSetLayout const& getPerViewDescriptorSetLayoutDescription(
|
||||
Variant const variant, bool const useVsmDescriptorSetLayout) const noexcept;
|
||||
@@ -325,11 +325,6 @@ 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,7 +45,6 @@
|
||||
#include <limits>
|
||||
#include <mutex>
|
||||
#include <string_view>
|
||||
#include <variant>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "fg/FrameGraphResources.h"
|
||||
#include "fg/FrameGraphTexture.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <private/filament/EngineEnums.h>
|
||||
#include <private/filament/Variant.h>
|
||||
|
||||
@@ -60,6 +61,7 @@
|
||||
#include <utils/Allocator.h>
|
||||
#include <utils/bitset.h>
|
||||
#include <utils/JobSystem.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Logger.h>
|
||||
#include <utils/Panic.h>
|
||||
#include <utils/compiler.h>
|
||||
@@ -97,11 +99,7 @@ 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(),
|
||||
@@ -136,11 +134,7 @@ 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)) {
|
||||
@@ -290,9 +284,6 @@ 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();
|
||||
|
||||
@@ -310,78 +301,49 @@ void FRenderer::skipFrame(uint64_t vsyncSteadyClockTimeNano) {
|
||||
// Run the component managers' GC
|
||||
auto& js = engine.getJobSystem();
|
||||
js.runAndWait(jobs::createJob(js, nullptr, &FEngine::gc, &engine)); // gc all managers
|
||||
|
||||
mFrameSkipper.frameSkipped();
|
||||
}
|
||||
|
||||
bool FRenderer::shouldRenderFrame() const noexcept {
|
||||
FEngine& engine = mEngine;
|
||||
FEngine::DriverApi& driver = engine.getDriverApi();
|
||||
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;
|
||||
return mFrameSkipper.shouldRenderFrame(driver);
|
||||
}
|
||||
|
||||
bool FRenderer::beginFrame(FSwapChain* swapChain, uint64_t vsyncSteadyClockTimeNano) {
|
||||
assert_invariant(swapChain);
|
||||
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT, "frameId", (mFrameId + 1));
|
||||
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
|
||||
|
||||
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();
|
||||
|
||||
@@ -438,10 +400,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(driver);
|
||||
engine.prepare();
|
||||
};
|
||||
|
||||
if (shouldRenderFrame()) {
|
||||
if (mFrameSkipper.shouldRenderFrame(driver)) {
|
||||
// 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();
|
||||
@@ -459,9 +421,6 @@ 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;
|
||||
}
|
||||
|
||||
@@ -609,10 +568,9 @@ 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(
|
||||
@@ -621,7 +579,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(driver, view, true);
|
||||
renderInternal(view, true);
|
||||
|
||||
engine.submitFrame();
|
||||
|
||||
@@ -629,7 +587,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 most likely already running.
|
||||
// driver thread, which is mostlikely already running.
|
||||
engine.flush();
|
||||
}
|
||||
}
|
||||
@@ -648,11 +606,11 @@ void FRenderer::render(FView const* view) {
|
||||
assert_invariant(mSwapChain);
|
||||
|
||||
if (UTILS_LIKELY(view && view->getScene() && view->hasCamera())) {
|
||||
renderInternal(mEngine.getDriverApi(), view, false);
|
||||
renderInternal(view, false);
|
||||
}
|
||||
}
|
||||
|
||||
void FRenderer::renderInternal(DriverApi& driver, FView const* view, bool flush) {
|
||||
void FRenderer::renderInternal(FView const* view, bool flush) {
|
||||
FEngine& engine = mEngine;
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(!view->hasPostProcessPass() ||
|
||||
@@ -667,10 +625,10 @@ void FRenderer::renderInternal(DriverApi& driver, FView const* view, bool flush)
|
||||
auto *rootJob = js.setRootJob(js.createJob());
|
||||
|
||||
// execute the render pass
|
||||
renderJob(driver, rootArenaScope, const_cast<FView&>(*view));
|
||||
renderJob(rootArenaScope, const_cast<FView&>(*view));
|
||||
|
||||
if (flush) {
|
||||
driver.flush();
|
||||
engine.getDriverApi().flush();
|
||||
}
|
||||
|
||||
// make sure to flush the command buffer
|
||||
@@ -680,9 +638,10 @@ void FRenderer::renderInternal(DriverApi& driver, FView const* view, bool flush)
|
||||
js.runAndWait(rootJob);
|
||||
}
|
||||
|
||||
void FRenderer::renderJob(DriverApi& driver, RootArenaScope& rootArenaScope, FView& view) {
|
||||
void FRenderer::renderJob(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());
|
||||
@@ -732,7 +691,7 @@ void FRenderer::renderJob(DriverApi& driver, RootArenaScope& rootArenaScope, FVi
|
||||
} else {
|
||||
// This configures post-process materials by setting constant parameters
|
||||
if (taaOptions.enabled) {
|
||||
ppm.configureTemporalAntiAliasingMaterial(driver, taaOptions);
|
||||
ppm.configureTemporalAntiAliasingMaterial(taaOptions);
|
||||
if (taaOptions.upscaling > 1.0f) {
|
||||
// for now TAA upscaling is incompatible with regular dsr
|
||||
dsrOptions.enabled = false;
|
||||
@@ -767,11 +726,11 @@ void FRenderer::renderJob(DriverApi& driver, RootArenaScope& rootArenaScope, FVi
|
||||
const PostProcessManager::ColorGradingConfig colorGradingConfig{
|
||||
.asSubpass =
|
||||
isSubpassPossible &&
|
||||
mIsFrameBufferFetchSupported &&
|
||||
driver.isFrameBufferFetchSupported() &&
|
||||
!engine.debug.renderer.disable_subpasses,
|
||||
.customResolve =
|
||||
msaaSampleCount > 1 &&
|
||||
mIsFrameBufferFetchMultiSampleSupported &&
|
||||
driver.isFrameBufferFetchMultiSampleSupported() &&
|
||||
msaaOptions.customResolve &&
|
||||
hasColorGrading &&
|
||||
!engine.debug.renderer.disable_subpasses,
|
||||
@@ -1050,9 +1009,7 @@ void FRenderer::renderJob(DriverApi& driver, RootArenaScope& rootArenaScope, FVi
|
||||
.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(),
|
||||
.featureLevel = mFeatureLevel,
|
||||
.isAutoDepthResolveSupported = mIsAutoDepthResolveSupported
|
||||
.enabledStencilBuffer = view.isStencilBufferEnabled()
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1242,7 +1199,7 @@ void FRenderer::renderJob(DriverApi& driver, RootArenaScope& rootArenaScope, FVi
|
||||
}
|
||||
|
||||
// create the pass, which generates all its commands (this is a heavy operation)
|
||||
RenderPass const pass{ passBuilder.build(engine, driver) };
|
||||
RenderPass const pass{ passBuilder.build(engine) };
|
||||
|
||||
// now that we have the commands we can figure out if we have refraction commands
|
||||
auto* const firstRefractionCommand = [&view](RenderPass const& pass) {
|
||||
@@ -1288,9 +1245,10 @@ void FRenderer::renderJob(DriverApi& driver, RootArenaScope& rootArenaScope, FVi
|
||||
.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) {
|
||||
@@ -1534,12 +1492,18 @@ void FRenderer::renderJob(DriverApi& driver, RootArenaScope& rootArenaScope, FVi
|
||||
|
||||
fg.forwardResource(fgViewRenderTarget, input);
|
||||
|
||||
#if FILAMENT_ENABLE_FGVIEWER
|
||||
fgviewer::DebugServer* fgviewerServer = engine.debug.fgviewerServer;
|
||||
if (UTILS_LIKELY(fgviewerServer)) {
|
||||
readPixels(fg, blackboard);
|
||||
}
|
||||
#endif
|
||||
|
||||
fg.present(fgViewRenderTarget);
|
||||
|
||||
fg.compile();
|
||||
|
||||
#if FILAMENT_ENABLE_FGVIEWER
|
||||
fgviewer::DebugServer* fgviewerServer = engine.debug.fgviewerServer;
|
||||
if (UTILS_LIKELY(fgviewerServer)) {
|
||||
fgviewerServer->update(view.getViewHandle(), fg.getFrameGraphInfo(view.getName()));
|
||||
}
|
||||
@@ -1551,10 +1515,91 @@ void FRenderer::renderJob(DriverApi& driver, RootArenaScope& rootArenaScope, FVi
|
||||
|
||||
fg.execute(driver);
|
||||
|
||||
#if FILAMENT_ENABLE_FGVIEWER
|
||||
if (UTILS_LIKELY(fgviewerServer)) {
|
||||
fgviewerServer->tick();
|
||||
}
|
||||
#endif
|
||||
|
||||
// save the current history entry and destroy the oldest entry
|
||||
view.commitFrameHistory(engine);
|
||||
|
||||
recordHighWatermark(commandArena.getListener().getHighWatermark());
|
||||
}
|
||||
|
||||
#if FILAMENT_ENABLE_FGVIEWER
|
||||
|
||||
void FRenderer::readPixels(FrameGraph& fg, Blackboard& blackboard) {
|
||||
|
||||
FEngine& engine = mEngine;
|
||||
std::vector<FEngine::ReadbackRequest> requests;
|
||||
|
||||
{ // scope for lock
|
||||
std::unique_lock<utils::Mutex> lock(engine.mReadbackRequestsMutex);
|
||||
requests = std::move(engine.mReadbackRequests);
|
||||
engine.mReadbackRequests.clear();
|
||||
}
|
||||
|
||||
for (auto& request : requests) {
|
||||
FrameGraphId<FrameGraphTexture> fgTexture = fg.getTextureByName(request.name.c_str());
|
||||
if (!fgTexture.isInitialized()) {
|
||||
slog.w << "[fgviewer] Requested texture \"" << request.name.c_str_safe()
|
||||
<< "\" not found in FrameGraph." << io::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
struct ReadbackPassData {
|
||||
FrameGraphId<FrameGraphTexture> texture;
|
||||
};
|
||||
fg.addPass<ReadbackPassData>(
|
||||
"Readback Pass",
|
||||
[&](FrameGraph::Builder& builder, ReadbackPassData& data) {
|
||||
data.texture = builder.read(fgTexture, FrameGraphTexture::Usage::SAMPLEABLE);
|
||||
builder.sideEffect(); // Ensure this pass is not culled
|
||||
},
|
||||
[request = std::move(request)](FrameGraphResources const& resources,
|
||||
ReadbackPassData const& data, DriverApi& d) {
|
||||
const FrameGraphTexture::Descriptor& desc =
|
||||
resources.getDescriptor(data.texture);
|
||||
|
||||
backend::PixelBufferDescriptor::PixelDataFormat format =
|
||||
PixelBufferDescriptor::PixelDataFormat::RGBA;
|
||||
backend::PixelBufferDescriptor::PixelDataType type =
|
||||
PixelBufferDescriptor::PixelDataType::UBYTE;
|
||||
fgviewer::DebugServer::PixelDataFormat targetFormat =
|
||||
fgviewer::DebugServer::Format::RGBA;
|
||||
const size_t bufferSize = desc.width * desc.height * 4;
|
||||
|
||||
fgviewer::DebugServer::PixelBuffer pixelBuffer(bufferSize);
|
||||
void* bufferData = pixelBuffer.data();
|
||||
|
||||
struct UserData {
|
||||
size_t width;
|
||||
size_t height;
|
||||
fgviewer::DebugServer::PixelDataFormat targetFormat;
|
||||
FEngine::ReadbackRequest::Callback callback;
|
||||
fgviewer::DebugServer::PixelBuffer pixelBuffer;
|
||||
};
|
||||
|
||||
PixelBufferDescriptor pbd(
|
||||
bufferData, bufferSize, format, type, 1, 0, 0, 0, 0,
|
||||
[](void* buffer, size_t size, void* user) {
|
||||
std::unique_ptr<UserData> d {static_cast<UserData*>(user)};
|
||||
auto& callback = d->callback;
|
||||
callback(std::move(d->pixelBuffer), d->width, d->height, d->targetFormat);
|
||||
},
|
||||
new UserData{ desc.width, desc.height, targetFormat,
|
||||
std::move(request.callback), std::move(pixelBuffer) });
|
||||
|
||||
MRT color(resources.getTexture(data.texture), 0, 0);
|
||||
Handle<HwRenderTarget> rt = d.createRenderTarget(TargetBufferFlags::COLOR0,
|
||||
desc.width, desc.height, 1, 1, color, {}, {});
|
||||
|
||||
d.readPixels(rt, 0, 0, desc.width, desc.height, std::move(pbd));
|
||||
d.destroyRenderTarget(rt);
|
||||
});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
namespace filament {
|
||||
|
||||
class TextureCache;
|
||||
class Blackboard;
|
||||
|
||||
namespace backend {
|
||||
class Driver;
|
||||
@@ -83,7 +84,7 @@ public:
|
||||
|
||||
void resetUserTime();
|
||||
|
||||
void skipNextFrames(size_t frameCount) noexcept {
|
||||
void skipNextFrames(size_t frameCount) const noexcept {
|
||||
mFrameSkipper.skipNextFrames(frameCount);
|
||||
}
|
||||
|
||||
@@ -196,8 +197,11 @@ private:
|
||||
return mCommandsHighWatermark;
|
||||
}
|
||||
|
||||
void renderInternal(backend::DriverApi& driver, FView const* view, bool flush);
|
||||
void renderJob(backend::DriverApi& driver, RootArenaScope& rootArenaScope, FView& view);
|
||||
void renderInternal(FView const* view, bool flush);
|
||||
void renderJob(RootArenaScope& rootArenaScope, FView& view);
|
||||
#if FILAMENT_ENABLE_FGVIEWER
|
||||
void readPixels(FrameGraph& fg, Blackboard& blackboard);
|
||||
#endif
|
||||
|
||||
static std::pair<float, math::float2> prepareUpscaler(math::float2 scale,
|
||||
TemporalAntiAliasingOptions const& taaOptions,
|
||||
@@ -214,11 +218,7 @@ private:
|
||||
backend::TextureFormat mHdrTranslucent;
|
||||
backend::TextureFormat mHdrQualityMedium;
|
||||
backend::TextureFormat mHdrQualityHigh;
|
||||
backend::FeatureLevel mFeatureLevel;
|
||||
bool mIsRGB8Supported : 1;
|
||||
bool mIsFrameBufferFetchSupported : 1;
|
||||
bool mIsFrameBufferFetchMultiSampleSupported : 1;
|
||||
bool mIsAutoDepthResolveSupported : 1;
|
||||
Epoch mUserEpoch;
|
||||
math::float4 mShaderUserTime{};
|
||||
DisplayInfo mDisplayInfo;
|
||||
@@ -230,7 +230,6 @@ private:
|
||||
std::function<void()> mBeginFrameInternal;
|
||||
uint64_t mVsyncSteadyClockTimeNano = 0;
|
||||
std::unique_ptr<TextureCache> mResourceAllocator{};
|
||||
int64_t mLastFrameId = -1;
|
||||
};
|
||||
|
||||
FILAMENT_DOWNCAST(Renderer)
|
||||
|
||||
@@ -394,10 +394,8 @@ bool FView::isSkyboxVisible() const noexcept {
|
||||
return skybox != nullptr && (skybox->getLayerMask() & mVisibleLayers);
|
||||
}
|
||||
|
||||
void FView::prepareShadowing(FEngine& engine, DriverApi& driver,
|
||||
FScene::RenderableSoa& renderableData,
|
||||
FScene::LightSoa const& lightData,
|
||||
CameraInfo const& cameraInfo) noexcept {
|
||||
void FView::prepareShadowing(FEngine& engine, FScene::RenderableSoa& renderableData,
|
||||
FScene::LightSoa const& lightData, CameraInfo const& cameraInfo) noexcept {
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
|
||||
mHasShadowing = false;
|
||||
@@ -406,7 +404,7 @@ void FView::prepareShadowing(FEngine& engine, DriverApi& driver,
|
||||
return;
|
||||
}
|
||||
|
||||
auto const& lcm = engine.getLightManager();
|
||||
auto& lcm = engine.getLightManager();
|
||||
|
||||
ShadowMapManager::Builder builder;
|
||||
|
||||
@@ -463,8 +461,8 @@ void FView::prepareShadowing(FEngine& engine, DriverApi& driver,
|
||||
|
||||
if (builder.hasShadowMaps()) {
|
||||
ShadowMapManager::createIfNeeded(engine, mShadowMapManager);
|
||||
auto const shadowTechnique = mShadowMapManager->update(driver, builder, engine,
|
||||
*this, cameraInfo, renderableData, lightData);
|
||||
auto const shadowTechnique = mShadowMapManager->update(builder, engine, *this,
|
||||
cameraInfo, renderableData, lightData);
|
||||
|
||||
mHasShadowing = any(shadowTechnique);
|
||||
mNeedsShadowMap = any(shadowTechnique & ShadowMapManager::ShadowTechnique::SHADOW_MAP);
|
||||
@@ -687,7 +685,7 @@ void FView::prepare(FEngine& engine, DriverApi& driver, RootArenaScope& rootAren
|
||||
|
||||
setFroxelizerSync(froxelizeLightsJob);
|
||||
|
||||
prepareShadowing(engine, driver, renderableData, lightData, cameraInfo);
|
||||
prepareShadowing(engine, 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, backend::DriverApi& driver,
|
||||
FScene::RenderableSoa& renderableData, FScene::LightSoa const& lightData, CameraInfo const& cameraInfo) noexcept;
|
||||
void prepareShadowing(FEngine& engine, FScene::RenderableSoa& renderableData,
|
||||
FScene::LightSoa const& lightData, CameraInfo const& cameraInfo) noexcept;
|
||||
void prepareLighting(FEngine& engine, CameraInfo const& cameraInfo) noexcept;
|
||||
|
||||
void prepareSSAO(backend::Handle<backend::HwTexture> ssao) const noexcept;
|
||||
|
||||
@@ -582,6 +582,21 @@ fgviewer::FrameGraphInfo FrameGraph::getFrameGraphInfo(const char *viewName) con
|
||||
#endif
|
||||
}
|
||||
|
||||
#if FILAMENT_ENABLE_FGVIEWER
|
||||
FrameGraphId<FrameGraphTexture> FrameGraph::getTextureByName(const char* name) const {
|
||||
for (size_t i = 0; i < mResourceSlots.size(); ++i) {
|
||||
const auto& slot = mResourceSlots[i];
|
||||
const VirtualResource* resource = mResources[slot.rid];
|
||||
if (strcmp(resource->name.data(), name) == 0) {
|
||||
FrameGraphHandle handle((FrameGraphHandle::Index)i);
|
||||
handle.version = slot.version;
|
||||
return FrameGraphId<FrameGraphTexture>(handle);
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "fg/details/DependencyGraph.h"
|
||||
#include "fg/details/Resource.h"
|
||||
#include "fg/details/ResourceCreationContext.h"
|
||||
#include "fg/details/Utilities.h"
|
||||
|
||||
#include "backend/DriverApiForward.h"
|
||||
@@ -36,6 +37,8 @@
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <utils/Log.h>
|
||||
|
||||
#if FILAMENT_ENABLE_FGVIEWER
|
||||
#include <fgviewer/FrameGraphInfo.h>
|
||||
#else
|
||||
@@ -448,8 +451,21 @@ public:
|
||||
* Export a fgviewer::FrameGraphInfo for current graph.
|
||||
* Note that this function should be called after FrameGraph::compile().
|
||||
*/
|
||||
#if FILAMENT_ENABLE_FGVIEWER
|
||||
fgviewer::FrameGraphInfo getFrameGraphInfo(const char *viewName) const;
|
||||
|
||||
/**
|
||||
* Retrieve a texture handle by its name. This is used for debugging/visualization tools.
|
||||
* @param name Name of the resource
|
||||
* @return Handle to the texture, or an uninitialized handle if not found.
|
||||
*/
|
||||
FrameGraphId<FrameGraphTexture> getTextureByName(const char* name) const;
|
||||
#else
|
||||
fgviewer::FrameGraphInfo getFrameGraphInfo(const char*) const {
|
||||
return fgviewer::FrameGraphInfo();
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
friend class FrameGraphResources;
|
||||
friend class PassNode;
|
||||
@@ -673,4 +689,4 @@ extern template FrameGraphId<FrameGraphTexture> FrameGraph::forwardResource(
|
||||
|
||||
} // namespace filament
|
||||
|
||||
#endif //TNT_FILAMENT_FG_FRAMEGRAPH_H
|
||||
#endif // TNT_FILAMENT_FG_FRAMEGRAPH_H
|
||||
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
* @return Reference to the descriptor
|
||||
*/
|
||||
template<typename RESOURCE>
|
||||
typename RESOURCE::Descriptor const& getDescriptor(FrameGraphId<RESOURCE> handle) const;
|
||||
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>
|
||||
typename RESOURCE::SubResourceDescriptor const& getSubResourceDescriptor(
|
||||
RESOURCE::SubResourceDescriptor const& getSubResourceDescriptor(
|
||||
FrameGraphId<RESOURCE> handle) const;
|
||||
|
||||
/**
|
||||
@@ -85,7 +85,7 @@ public:
|
||||
* @return Reference to the descriptor
|
||||
*/
|
||||
template<typename RESOURCE>
|
||||
typename RESOURCE::Usage const& getUsage(FrameGraphId<RESOURCE> handle) const;
|
||||
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, typename RESOURCE::Descriptor* pOutDescriptor) const;
|
||||
RESOURCE* pOutResource, 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>
|
||||
typename RESOURCE::Descriptor const& FrameGraphResources::getDescriptor(
|
||||
RESOURCE::Descriptor const& FrameGraphResources::getDescriptor(
|
||||
FrameGraphId<RESOURCE> handle) const {
|
||||
return static_cast<Resource<RESOURCE> const&>(getResource(handle)).descriptor;
|
||||
}
|
||||
|
||||
template<typename RESOURCE>
|
||||
typename RESOURCE::SubResourceDescriptor const& FrameGraphResources::getSubResourceDescriptor(
|
||||
RESOURCE::SubResourceDescriptor const& FrameGraphResources::getSubResourceDescriptor(
|
||||
FrameGraphId<RESOURCE> handle) const {
|
||||
return static_cast<Resource<RESOURCE> const&>(getResource(handle)).subResourceDescriptor;
|
||||
}
|
||||
|
||||
template<typename RESOURCE>
|
||||
typename RESOURCE::Usage const& FrameGraphResources::getUsage(
|
||||
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 = typename RESOURCE::Usage;
|
||||
using Usage = RESOURCE::Usage;
|
||||
|
||||
public:
|
||||
using Descriptor = typename RESOURCE::Descriptor;
|
||||
using SubResourceDescriptor = typename RESOURCE::SubResourceDescriptor;
|
||||
using Descriptor = RESOURCE::Descriptor;
|
||||
using SubResourceDescriptor = 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 = typename RESOURCE::Descriptor;
|
||||
using Usage = typename RESOURCE::Usage;
|
||||
using Descriptor = RESOURCE::Descriptor;
|
||||
using Usage = RESOURCE::Usage;
|
||||
|
||||
UTILS_NOINLINE
|
||||
ImportedResource(utils::StaticString name, Descriptor const& desc, Usage usage, RESOURCE const& rsrc) noexcept
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user