Compare commits

..
Author SHA1 Message Date
Powei Feng 5f08c87424 fgviewer: add ability to look at rendertargets 2026-01-20 14:05:27 -08:00
127 changed files with 1494 additions and 2263 deletions
+25
View File
@@ -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
+29
View File
@@ -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
+26
View File
@@ -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
+29
View File
@@ -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
-59
View File
@@ -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}
+39 -95
View File
@@ -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 -1
View File
@@ -1,4 +1,4 @@
name: 'Presubmit CI'
name: Presubmit
on:
push:
+27
View File
@@ -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
+24
View File
@@ -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
View File
@@ -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()
+2 -2
View File
@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.68.4'
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.4'
pod 'Filament', '~> 1.68.3'
```
## Documentation
-5
View File
@@ -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 -1
View File
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.68.4
VERSION_NAME=1.68.3
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
+5 -5
View File
@@ -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>
+3 -3
View File
@@ -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>
+2 -2
View File
@@ -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
View File
@@ -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>
+2 -2
View File
@@ -181,7 +181,7 @@ important for <code>matc</code> (material compiler).</p>
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.68.4'
implementation 'com.google.android.filament:filament-android:1.68.3'
}
</code></pre>
<p>Here are all the libraries available in the group <code>com.google.android.filament</code>:</p>
@@ -196,7 +196,7 @@ dependencies {
</div>
<h3 id="ios"><a class="header" href="#ios">iOS</a></h3>
<p>iOS projects can use CocoaPods to install the latest release:</p>
<pre><code class="language-shell">pod 'Filament', '~&gt; 1.68.4'
<pre><code class="language-shell">pod 'Filament', '~&gt; 1.68.3'
</code></pre>
<h2 id="documentation"><a class="header" href="#documentation">Documentation</a></h2>
<ul>
@@ -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>
-230
View File
@@ -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>
@@ -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>
+2 -2
View File
@@ -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>
+2 -2
View File
@@ -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>
+2 -2
View File
@@ -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>
-249
View File
@@ -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&gt;&amp;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>
-215
View File
@@ -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
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -7
View File
@@ -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"
}
}
+6 -9
View File
@@ -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.
+1
View File
@@ -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
+64 -65
View File
@@ -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;
+20 -16
View File
@@ -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
@@ -81,6 +81,7 @@ public:
bool queryFrameTimestamps(SwapChain const* swapchain, uint64_t frameId,
FrameTimestamps* outFrameTimestamps) const noexcept override;
protected:
ExtensionSet getSwapchainInstanceExtensions() const override;
+26
View File
@@ -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
+30 -7
View File
@@ -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
+36 -49
View File
@@ -51,39 +51,45 @@ namespace filament::backend {
DriverBase::DriverBase(const Platform::DriverConfig& driverConfig) noexcept
: mDriverConfig(driverConfig) {
#if UTILS_HAS_THREADING
// This thread services user callbacks
mServiceThread = std::thread([this]() {
JobSystem::setThreadName("ServiceThread");
do {
auto& serviceThreadCondition = mServiceThreadCondition;
auto& serviceThreadCallbackQueue = mServiceThreadCallbackQueue;
if constexpr (UTILS_HAS_THREADING) {
// This thread services user callbacks
mServiceThread = std::thread([this]() {
JobSystem::setThreadName("ServiceThread");
do {
auto& serviceThreadCondition = mServiceThreadCondition;
auto& serviceThreadCallbackQueue = mServiceThreadCallbackQueue;
// wait for some callbacks to dispatch
std::unique_lock<std::mutex> lock(mServiceThreadLock);
while (serviceThreadCallbackQueue.empty() && !mExitRequested) {
serviceThreadCondition.wait(lock);
}
if (mExitRequested) {
break;
}
// move the callbacks to a temporary vector
auto callbacks(std::move(serviceThreadCallbackQueue));
lock.unlock();
// and make sure to call them without our lock held
for (auto[handler, callback, user]: callbacks) {
handler->post(user, callback);
}
} while (true);
});
#endif
// wait for some callbacks to dispatch
std::unique_lock<std::mutex> lock(mServiceThreadLock);
while (serviceThreadCallbackQueue.empty() && !mExitRequested) {
serviceThreadCondition.wait(lock);
}
if (mExitRequested) {
break;
}
// move the callbacks to a temporary vector
auto callbacks(std::move(serviceThreadCallbackQueue));
lock.unlock();
// and make sure to call them without our lock held
for (auto[handler, callback, user]: callbacks) {
handler->post(user, callback);
}
} while (true);
});
}
}
DriverBase::~DriverBase() noexcept {
assert_invariant(mCallbacks.empty());
#if UTILS_HAS_THREADING
stopServiceThread();
#endif
assert_invariant(mServiceThreadCallbackQueue.empty());
if constexpr (UTILS_HAS_THREADING) {
// quit our service thread
std::unique_lock<std::mutex> lock(mServiceThreadLock);
mExitRequested = true;
mServiceThreadCondition.notify_one();
lock.unlock();
mServiceThread.join();
}
}
// ------------------------------------------------------------------------------------------------
@@ -107,14 +113,11 @@ void DriverBase::CallbackData::release(CallbackData* data) {
void DriverBase::scheduleCallback(CallbackHandler* handler, void* user, CallbackHandler::Callback callback) {
#if UTILS_HAS_THREADING
if (handler) {
if (handler && UTILS_HAS_THREADING) {
std::lock_guard<std::mutex> const lock(mServiceThreadLock);
mServiceThreadCallbackQueue.emplace_back(handler, callback, user);
mServiceThreadCondition.notify_one();
} else
#endif
{
} else {
std::lock_guard<std::mutex> const lock(mPurgeLock);
mCallbacks.emplace_back(user, callback);
}
@@ -182,22 +185,6 @@ void DriverBase::debugCommandEnd(CommandStream* cmds, bool synchronous,
}
}
#if UTILS_HAS_THREADING
void DriverBase::stopServiceThread() noexcept {
if (!mServiceThread.joinable()) {
return;
}
{
std::lock_guard<std::mutex> lock(mServiceThreadLock);
mExitRequested = true;
}
mServiceThreadCondition.notify_one();
mServiceThread.join();
assert_invariant(mServiceThreadCallbackQueue.empty());
}
#endif
size_t Driver::getElementTypeSize(ElementType type) noexcept {
switch (type) {
case ElementType::BYTE: return sizeof(int8_t);
-10
View File
@@ -173,8 +173,6 @@ struct HwTimerQuery : public HwBase {
/*
* Base class of all Driver implementations
* If multithreading is supported, this class creates a `ServiceThread` responsible for executing
* user handlers.
*/
class DriverBase : public Driver {
@@ -238,25 +236,17 @@ protected:
void debugCommandBegin(CommandStream* cmds, bool synchronous, const char* methodName) noexcept override;
void debugCommandEnd(CommandStream* cmds, bool synchronous, const char* methodName) noexcept override;
#if UTILS_HAS_THREADING
// Stops the `ServiceThread`. This method is called during destruction but may be called
// explicitly if earlier shutdown is needed. This method is idempotent.
void stopServiceThread() noexcept;
#endif
private:
const Platform::DriverConfig mDriverConfig;
std::mutex mPurgeLock;
std::vector<std::pair<void*, CallbackHandler::Callback>> mCallbacks;
#if UTILS_HAS_THREADING
std::thread mServiceThread;
std::mutex mServiceThreadLock;
std::condition_variable mServiceThreadCondition;
std::vector<std::tuple<CallbackHandler*, CallbackHandler::Callback, void*>> mServiceThreadCallbackQueue;
bool mExitRequested = false;
#endif
};
@@ -382,18 +382,9 @@ void OpenGLDriver::terminate() {
delete mCurrentPushConstants;
mCurrentPushConstants = nullptr;
// Flush all pending asynchronous tasks. Some tasks may end up posting follow-up operations to
// the `ServiceThread` (e.g., via CountdownCallbackHandler or any user-provided handlers). So we
// early stop the ServiceThread to ensure these are processed as well. Tasks posted to the main
// thread (due to no user handler) during this process are handled later by `Driver::purge`
// within `FEngine::shutdown`.
if (getJobWorker()) {
getJobWorker()->terminate();
}
#if UTILS_HAS_THREADING
stopServiceThread();
#endif
mContext.terminate();
mPlatform.terminate();
}
@@ -79,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;
+1 -29
View File
@@ -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;
}
@@ -249,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;
};
+2 -77
View File
@@ -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.get(),
mPipelineLayoutCache.getLayout(vkLayouts, vprogram),
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.get(),
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;
+10 -21
View File
@@ -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);
}
+1 -7
View File
@@ -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;
};
@@ -180,12 +180,7 @@ void VulkanPipelineCache::asyncPrewarmCache(const VulkanProgram& program,
mCallbackManager.put(cmh);
// We don't actually need this pipeline, we just wanted to force the driver to cache
// the pipeline's information.
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);
});
}
@@ -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) {
@@ -798,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);
@@ -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;
+1 -8
View File
@@ -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();
+2 -2
View File
@@ -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;
+1 -1
View File
@@ -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:
*
+1 -1
View File
@@ -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
-7
View File
@@ -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.
+2 -2
View File
@@ -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
+1 -1
View File
@@ -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.
+1 -1
View File
@@ -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.
+3 -4
View File
@@ -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;
/**
+1 -2
View File
@@ -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().
+1 -5
View File
@@ -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);
}
+8 -3
View File
@@ -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);
+2 -2
View File
@@ -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{};
+2 -1
View File
@@ -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);
}
+2 -9
View File
@@ -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
+30 -53
View File
@@ -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
+60 -63
View File
@@ -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);
+5 -8
View File
@@ -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;
+6 -6
View File
@@ -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);
}
}
}
+3 -4
View File
@@ -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;
};
+1 -1
View File
@@ -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);
}
+2 -2
View File
@@ -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;
-4
View File
@@ -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 {
+5 -7
View File
@@ -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,
+4 -5
View File
@@ -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());
+1 -1
View File
@@ -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.
+63 -108
View File
@@ -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);
@@ -705,12 +701,6 @@ void FEngine::shutdown() {
// Driver::terminate() has been called here.
}
// Handle any pending deferred destruction for asynchronous objects.
if (isAsynchronousModeEnabled()) {
gcDeferredAsyncObjectDestruction();
assert_invariant(mDeferredAsyncObjectDestruction.empty());
}
// Finally, call user callbacks that might have been scheduled.
// These callbacks CANNOT call driver APIs.
getDriver().purge();
@@ -726,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) {
@@ -740,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) {
@@ -751,7 +742,7 @@ void FEngine::prepare(DriverApi& driver) {
if (useUboBatching) {
assert_invariant(mUboManager != nullptr);
getUboManager()->finishBeginFrame(driver);
getUboManager()->finishBeginFrame(getDriverApi());
}
mMaterials.forEach([](FMaterial* material) {
@@ -761,7 +752,7 @@ void FEngine::prepare(DriverApi& driver) {
});
}
void FEngine::gcManagers() {
void FEngine::gc() {
// Note: this runs in a Job
auto& em = mEntityManager;
mRenderableManager.gc(em);
@@ -770,21 +761,6 @@ void FEngine::gcManagers() {
mCameraManager.gc(*this, em);
}
void FEngine::gcDeferredAsyncObjectDestruction() {
if (mDeferredAsyncObjectDestruction.empty()) {
return;
}
auto it = std::remove_if(
mDeferredAsyncObjectDestruction.begin(),
mDeferredAsyncObjectDestruction.end(),
[](auto& f) {
return f(); // Returns true if it should be removed
}
);
// Actually erase the elements from the vector
mDeferredAsyncObjectDestruction.erase(it, mDeferredAsyncObjectDestruction.end());
}
void FEngine::submitFrame() {
if (isUboBatchingEnabled()) {
DriverApi& driver = getDriverApi();
@@ -882,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.
@@ -1161,18 +1143,11 @@ bool FEngine::isValid(const T* ptr, ResourceList<T> const& list) const {
return l.find(ptr) != l.end();
}
template <typename T, typename = void>
struct HasIsCreationComplete : std::false_type {};
template <typename T>
struct HasIsCreationComplete<T, std::void_t<decltype(std::declval<T>().isCreationComplete())>>
: std::true_type {};
template<typename T>
UTILS_ALWAYS_INLINE
bool FEngine::terminateAndDestroy(const T* ptr, ResourceList<T>& list) {
if (ptr == nullptr) return true;
bool const success = list.remove(ptr);
bool FEngine::terminateAndDestroy(const T* p, ResourceList<T>& list) {
if (p == nullptr) return true;
bool const success = list.remove(p);
#if UTILS_HAS_RTTI
auto typeName = CallStack::typeName<T>();
@@ -1182,42 +1157,9 @@ bool FEngine::terminateAndDestroy(const T* ptr, ResourceList<T>& list) {
#endif
if (ASSERT_PRECONDITION_NON_FATAL(success,
"Object %s at %p doesn't exist (double free?)", typeNameCStr, ptr)) {
T* p = const_cast<T*>(ptr);
if constexpr (HasIsCreationComplete<T>::value) {
// The presence of 'isCreationComplete' in type T implies it supports asynchronous
// creation. For these asynchronous objects, we can terminate the backend resources
// immediately as they are no longer referenced. However, we defer the destruction of
// the frontend object if it's still being loaded.
// Reason: The creation process is still active and holds a reference to the frontend
// object to set `mCreationComplete` to true (see FTexture::FTexture). Deleting it now
// may cause a crash, so we wait until creation completes.
// Terminate the backend resource immediately as they're unnecessary from this point.
p->terminate(*this);
if (p->isCreationComplete()) {
// If creation is complete, we free the frontend object immediately. Note that in
// regular (non-async) mode, the `isCreationComplete` method always return true.
mHeapAllocator.destroy(p);
} else {
// We defer the destruction of the frontend object until the creation process
// completes. This ensures the object remains valid while the creation process still
// holds references to it.
mDeferredAsyncObjectDestruction.push_back([this, p]() {
if (!p->isCreationComplete()) {
return false;
}
mHeapAllocator.destroy(p);
return true;
});
}
} else {
p->terminate(*this);
mHeapAllocator.destroy(p);
}
"Object %s at %p doesn't exist (double free?)", typeNameCStr, p)) {
const_cast<T*>(p)->terminate(*this);
mHeapAllocator.destroy(const_cast<T*>(p));
}
return success;
}
@@ -1520,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;
}
@@ -1614,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;
}
// ------------------------------------------------------------------------------------------------
@@ -1738,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
+153 -21
View File
@@ -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,9 +459,8 @@ public:
return mPlatform->pumpEvents();
}
void prepare(backend::DriverApi& driver);
void gcManagers();
void gcDeferredAsyncObjectDestruction();
void prepare();
void gc();
void submitFrame();
using ShaderContent = utils::FixedCapacityVector<uint8_t>;
@@ -570,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);
@@ -587,7 +591,7 @@ private:
bool isValid(const T* ptr, ResourceList<T> const& list) const;
template<typename T>
bool terminateAndDestroy(const T* ptr, ResourceList<T>& list);
bool terminateAndDestroy(const T* p, ResourceList<T>& list);
template<typename T, typename Lock>
bool terminateAndDestroyLocked(Lock& lock, const T* p, ResourceList<T>& list);
@@ -706,11 +710,20 @@ private:
bool mInitialized = false;
#if FILAMENT_ENABLE_FGVIEWER
struct ReadbackRequest {
using Callback = std::function<void(fgviewer::DebugServer::PixelBuffer, uint32_t, uint32_t,
fgviewer::DebugServer::PixelDataFormat)>;
utils::CString name;
Callback callback;
};
utils::Mutex mReadbackRequestsMutex;
std::vector<ReadbackRequest> mReadbackRequests;
#endif
// Creation parameters
Config mConfig;
std::vector<std::function<bool()>> mDeferredAsyncObjectDestruction;
public:
// These are the debug properties used by FDebug.
// They're accessed directly by modules who need them.
@@ -757,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)
+38 -41
View File
@@ -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];
}
}
}
+7 -12
View File
@@ -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;
-1
View File
@@ -45,7 +45,6 @@
#include <limits>
#include <mutex>
#include <string_view>
#include <variant>
#include <stddef.h>
#include <stdint.h>
+138 -103
View File
@@ -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();
@@ -307,86 +298,52 @@ void FRenderer::skipFrame(uint64_t vsyncSteadyClockTimeNano) {
engine.flush(); // flush command stream
// Run GC
JobSystem& js = engine.getJobSystem();
auto *rootJob = js.createJob();
js.run(jobs::createJob(js, rootJob, &FEngine::gcManagers, &engine)); // gc all component managers
if (engine.isAsynchronousModeEnabled()) {
js.run(jobs::createJob(js, rootJob, &FEngine::gcDeferredAsyncObjectDestruction, &engine));
}
js.runAndWait(rootJob);
mFrameSkipper.frameSkipped();
// Run the component managers' GC
auto& js = engine.getJobSystem();
js.runAndWait(jobs::createJob(js, nullptr, &FEngine::gc, &engine)); // gc all managers
}
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();
@@ -443,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();
@@ -464,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;
}
@@ -515,14 +469,9 @@ void FRenderer::endFrame() {
engine.flush(); // flush command stream
// Run GC
JobSystem& js = engine.getJobSystem();
auto *rootJob = js.createJob();
js.run(jobs::createJob(js, rootJob, &FEngine::gcManagers, &engine)); // gc all component managers
if (engine.isAsynchronousModeEnabled()) {
js.run(jobs::createJob(js, rootJob, &FEngine::gcDeferredAsyncObjectDestruction, &engine));
}
js.runAndWait(rootJob);
// Run the component managers' GC
auto& js = engine.getJobSystem();
js.runAndWait(jobs::createJob(js, nullptr, &FEngine::gc, &engine)); // gc all managers
}
void FRenderer::readPixels(
@@ -619,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(
@@ -631,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();
@@ -639,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();
}
}
@@ -658,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() ||
@@ -677,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
@@ -690,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());
@@ -742,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;
@@ -777,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,
@@ -1060,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()
};
/*
@@ -1252,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) {
@@ -1298,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) {
@@ -1544,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()));
}
@@ -1561,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
+7 -8
View File
@@ -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)
+6 -8
View File
@@ -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
+2 -2
View File
@@ -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;
+15
View File
@@ -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
// ------------------------------------------------------------------------------------------------
+17 -1
View File
@@ -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

Some files were not shown because too many files have changed in this diff Show More